Skip to content

Commit 99c7403

Browse files
author
Leo Y. Li
committed
#0: release v1.0.0
0 parents  commit 99c7403

File tree

10 files changed

+2417
-0
lines changed

10 files changed

+2417
-0
lines changed

.babelrc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"presets": [
3+
[
4+
"@babel/env",
5+
{
6+
"modules": false
7+
}
8+
],
9+
"@babel/typescript"
10+
],
11+
"comments": false,
12+
"minified": true
13+
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
dist

.prettierrc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"printWidth": 100,
3+
"tabWidth": 2,
4+
"useTabs": false,
5+
"semi": true,
6+
"singleQuote": true,
7+
"trailingComma": "es5",
8+
"bracketSpacing": true,
9+
"jsxBracketSameLine": false,
10+
"arrowParens": "always",
11+
"proseWrap": "never",
12+
"endOfLine": "lf"
13+
}

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# CHANGELOG
2+
3+
All notable changes to this project will be documented in this file.
4+
This project adheres to [Semantic Versioning](http://semver.org/).
5+
6+
---
7+
8+
## [1.0.0] - 2019-04-25
9+
10+
## Feature
11+
12+
- Initial publish.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 Leo Y. Li
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Vue createContext
2+
3+
[![npm version](https://badge.fury.io/js/vue-create-context.svg)](https://badge.fury.io/js/vue-create-context)
4+
5+
An abstracted util factory for creating declarative and reactive contexts component in Vue. This API abstraction is greatly inspired by [`React.createContexts`](https://reactjs.org/docs/context.html#reactcreatecontext). The usage and its behaviour is exactly the same as you may expect if you already familiar with React. Under the hood, it uses Vue's reactive system with its `provide/inject` and scoped-slot API. It is light weight, declarative, and easy to use.
6+
7+
## 🧰 Requirements
8+
9+
This library requires Vue 2.6+, where Vue introduces the `v-slot` derivative, opening a new declarative pattern for passing component props in a compositional manner.
10+
11+
## 🎬 Getting started
12+
13+
To get it started, add this package into your project:
14+
15+
```bash
16+
yarn add -D vue-create-context
17+
```
18+
19+
## 📔 API
20+
21+
### `createContext`
22+
23+
```js
24+
import { createContext } from 'vue-create-context';
25+
const MyContext = createContext(defaultValue);
26+
```
27+
28+
Calling `createContext` with the `defaultValue` to create a context object. The `defaultValue` can be either a reference object or primitive, which is **ONLY** used when the `Consumer` component can not find its paired `Provider` above the rendering tree. The behaviour is the same as the one in React, so you can also have a look at [React.createContext](https://reactjs.org/docs/context.html#reactcreatecontext).
29+
30+
### `Context.Provider`
31+
32+
```vue
33+
<MyContext.Provider :value={/* the provided value */}>
34+
```
35+
36+
The `Provider` accept a `value` prop to be any value you want it to pass down the rendering tree. Similar to React, you can use this component multiple times an any level of the rendering tree. Its conjugated `Consumer` will receive the value from the closest `Provider` among its ancestors.
37+
38+
Note: If the provided value is reactive, update this value "reactively" will also update all its subscribed descended `Consumers`.
39+
40+
### `Context.Consumer`
41+
42+
```vue
43+
<MyContext.Consumer v-slot="/* slot props: the value injected by the closed Provider */">
44+
/* you can access the value within the block */
45+
</MyContext.Consumer>
46+
```
47+
48+
The `Consumer` gives the access to the injected value from the closest `Provider`. Unlike React, where uses the CAAF (children as a function, also known as the "render prop") pattern to access the value, we uses `v-slot` inside the component block template to access the value (the so called "slot props"). If you uses single file component (SFC) or browsers supports ES6+ object spread operator, you can take the advantage of object destructuring (see more on [Vue's official page](https://vuejs.org/v2/guide/components-slots.html#Destructuring-Slot-Props)).
49+
50+
It is worth to mention that due to the current limitation of Vue's scoped slot API, the slot props have to be an object, so it is recommended to give the value as an plan old javascript object (POJO). In the case of the provided value to be a primitive, it will be normalized as an object with a `value` key to get the passed value in `v-slot`, i.e. `{ value: /* your provided value */ }`.
51+
52+
Note. You might be tempted to mutate the injected value from the consumer. This is a bad idea since it violate the "[props down event up principle](https://vuejs.org/v2/style-guide/#Implicit-parent-child-communication-use-with-caution)". Under the hood, the library leverage the `computed` property in the `Consumer`, and you would not able to update/mutate on the source value. This is also consistent with the behaviour of Vue's `provide/inject` API.
53+
54+
## 💎 Example
55+
56+
There is an example in [the Official Storybook Vue](https://storybooks-vue.netlify.com/?path=/story/addon-contexts--languages) as an example of the `createContexts`.
57+
58+
For people using the SFC format, here is an conceptual example:
59+
60+
```vue
61+
<template>
62+
<div>
63+
<Provider :value="currentUser">
64+
<Consumer v-slot="{ firstName, lastName }">
65+
<p>Hello {{ lastName }}, {{ firstName }}!</p>
66+
<!-- Hello Newman, Jack! -->
67+
</Consumer>
68+
</Provider>
69+
<Consumer v-slot="{ firstName, lastName }">
70+
<p>Hello {{ firstName }}, {{ lastName }}!</p>
71+
<!-- Hello N/A, N/A! -->
72+
</Consumer>
73+
</div>
74+
</template>
75+
76+
<script>
77+
import { createContext } from 'vue-create-context';
78+
const userContext = createContext({ firstName: 'N/A', lastName: 'N/A' }); // normally it is imported from other files.
79+
80+
module.exports = {
81+
name: 'MyComponent',
82+
components: {
83+
Provider: userContext.Provider,
84+
Consumer: userContext.Consumer,
85+
},
86+
data() {
87+
return {
88+
firstName: 'Jack',
89+
lastName: 'Newman',
90+
};
91+
},
92+
};
93+
</script>
94+
```
95+
96+
## 📖 License
97+
98+
MIT

package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "vue-create-context",
3+
"version": "1.0.0",
4+
"description": "An abstracted util factory for creating declarative and reactive contexts component in Vue.",
5+
"keywords": [
6+
"vue"
7+
],
8+
"files": [
9+
"dist/**/*"
10+
],
11+
"scripts": {
12+
"prettier": "prettier --config .prettierrc --write '**/*.{ts,tsx}'",
13+
"type:check": "tsc --isolatedModules --noEmit ",
14+
"type:watch": "yarn type:check --watch",
15+
"type:emit": "rm -rf dist && tsc --declaration --removeComments --emitDeclarationOnly",
16+
"build": "babel src --out-dir dist --extensions \".ts,.tsx\"",
17+
"prepare": "yarn type:emit && yarn build"
18+
},
19+
"main": "index.js",
20+
"types": "index.d.ts",
21+
"repository": "https://github.com/leoyli/vue-create-context.git",
22+
"author": "Leo Y. Li",
23+
"license": "MIT",
24+
"devDependencies": {
25+
"@babel/cli": "7.4.3",
26+
"@babel/core": "7.4.3",
27+
"@babel/preset-env": "7.4.3",
28+
"@babel/preset-typescript": "7.3.3",
29+
"prettier": "1.17.0",
30+
"typescript": "3.4.5"
31+
}
32+
}

src/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Component } from 'vue';
2+
3+
type createContext = (defaultValue: unknown) => { Provider: Component; Consumer: Component };
4+
5+
export const createContext: createContext = (defaultValue) => {
6+
const key = `_${Date.now()}${Math.random()}`;
7+
return {
8+
Provider: {
9+
name: 'Context.Provider',
10+
props: ['value'],
11+
provide(this: any) {
12+
return this.value === undefined ? undefined : { [key]: () => this.value };
13+
},
14+
render(this: any) {
15+
return this.$slots.default;
16+
},
17+
},
18+
Consumer: {
19+
name: 'Context.Consumer',
20+
inject: {
21+
[key]: {
22+
default: () => () =>
23+
defaultValue instanceof Object ? { ...defaultValue } : { value: defaultValue },
24+
},
25+
},
26+
computed: {
27+
value(this: any) {
28+
return this[key]();
29+
},
30+
},
31+
render(this: any) {
32+
return this.$scopedSlots.default(this.value);
33+
},
34+
},
35+
};
36+
};

tsconfig.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"compilerOptions": {
3+
"outDir": "dist",
4+
"module": "es2015",
5+
"target": "es5",
6+
"moduleResolution": "node",
7+
"strict": true,
8+
"esModuleInterop": true,
9+
"allowSyntheticDefaultImports": true
10+
},
11+
"include": ["src"],
12+
"exclude": ["src/register.ts"]
13+
}

0 commit comments

Comments
 (0)