├── .babelrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── src ├── Consumer.js ├── Provider.js ├── __tests__ │ ├── Consumer.spec.js │ └── Provider.spec.js ├── createContext.js └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | lib -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | .gitignore 3 | node_modules 4 | .npmignore 5 | .travis.yml 6 | yarn.lock -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: yarn 3 | notifications: 4 | email: false 5 | node_js: 6 | - '10' 7 | - '9' 8 | - '8' 9 | script: 10 | - yarn build 11 | - yarn test 12 | after_success: 13 | - npm run travis-deploy-once "npm run semantic-release" 14 | branches: 15 | except: 16 | - /^v\d+\.\d+\.\d+$/ 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [1.0.1](https://github.com/zephraph/vue-context-api/compare/v1.0.0...v1.0.1) (2018-05-22) 3 | 4 | 5 | ### Bug Fixes 6 | 7 | * Add vue as a peer dependency ([97da310](https://github.com/zephraph/vue-context-api/commit/97da310)) 8 | 9 | 10 | # 1.0.0 (2018-05-22) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * Remove console statement ([9c1167f](https://github.com/zephraph/vue-context-api/commit/9c1167f)) 16 | * **Consumer:** Render child content when slot-scope isn't defined. Provide a warning. ([c89a8d1](https://github.com/zephraph/vue-context-api/commit/c89a8d1)) 17 | * **Provider:** Unwrap from provider object, don't overwrite context value with undefined prop ([04f3b3a](https://github.com/zephraph/vue-context-api/commit/04f3b3a)) 18 | 19 | 20 | ### Features 21 | 22 | * **Update release process:** Adds semantic-release and commitizen to enable automatic, easy release ([100fa49](https://github.com/zephraph/vue-context-api/commit/100fa49)) 23 | * Implement createContext, Provider, and Consumer apis ([b499b0b](https://github.com/zephraph/vue-context-api/commit/b499b0b)) 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Zephraph 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-context-api 2 | 3 | A react-like context component api for Vue.js 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install --save vue-context-api 9 | ``` 10 | 11 | or 12 | 13 | ``` 14 | yarn add vue-context-api 15 | ``` 16 | 17 | ## Example Usage 18 | 19 | See a [live example](https://codesandbox.io/s/nrjz7ky4mp). 20 | 21 | **ThemeContext.js** 22 | 23 | ```javascript 24 | import { createContext } from "vue-context-api"; 25 | 26 | // The argument passed to createContext is the default context value 27 | export const { Provider, Consumer } = createContext("light"); 28 | ``` 29 | 30 | **App.vue** 31 | 32 | ```html 33 | 39 | 40 | 51 | ``` 52 | 53 | **ThemedButton.vue** 54 | 55 | ```html 56 | 61 | 62 | 78 | ``` 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-context-api", 3 | "version": "1.0.1", 4 | "description": "A react-like context api for Vue", 5 | "keywords": [ 6 | "vue", 7 | "react", 8 | "context", 9 | "api", 10 | "provider", 11 | "consumer", 12 | "inject", 13 | "provide" 14 | ], 15 | "source": "src/index.js", 16 | "main": "lib/vue-context-api.js", 17 | "umd:main": "lib/vue-context-api.umd.js", 18 | "module": "lib/vue-context-api.esm.js", 19 | "repository": "https://github.com/zephraph/vue-context-api", 20 | "author": "zephraph ", 21 | "license": "MIT", 22 | "scripts": { 23 | "build": "microbundle", 24 | "dev": "microbundle watch", 25 | "test": "jest", 26 | "semantic-release": "semantic-release", 27 | "travis-deploy-once": "travis-deploy-once" 28 | }, 29 | "release": { 30 | "verifyConditions": [ 31 | "@semantic-release/changelog", 32 | "@semantic-release/npm", 33 | "@semantic-release/git" 34 | ], 35 | "prepare": [ 36 | "@semantic-release/changelog", 37 | "@semantic-release/npm", 38 | "@semantic-release/git" 39 | ], 40 | "publish": [ 41 | "@semantic-release/github", 42 | "@semantic-release/npm" 43 | ] 44 | }, 45 | "devDependencies": { 46 | "@babel/core": "^7.0.0-beta.47", 47 | "@babel/preset-env": "^7.0.0-beta.47", 48 | "@semantic-release/changelog": "^2.0.2", 49 | "@semantic-release/git": "^5.0.0", 50 | "@vue/test-utils": "^1.0.0-beta.16", 51 | "babel-core": "^7.0.0-0", 52 | "babel-jest": "^22.4.4", 53 | "cz-conventional-changelog": "^2.1.0", 54 | "jest": "^22.4.4", 55 | "microbundle": "^0.4.4", 56 | "semantic-release": "^15.5.0", 57 | "travis-deploy-once": "^5.0.0", 58 | "vue": "^2.5.16", 59 | "vue-template-compiler": "^2.5.16" 60 | }, 61 | "peerDependencies": { 62 | "vue": "^2.5.0" 63 | }, 64 | "config": { 65 | "commitizen": { 66 | "path": "./node_modules/cz-conventional-changelog" 67 | } 68 | }, 69 | "jest": { 70 | "transform": { 71 | "^.+\\.js$": "babel-jest" 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Consumer.js: -------------------------------------------------------------------------------- 1 | export default function Consumer(context) { 2 | return { 3 | data: () => ({ 4 | context 5 | }), 6 | render(h) { 7 | if (!this.$scopedSlots.default) { 8 | console.warn("Context consumer expected to define slot-scope"); 9 | return this.$slots.default[0]; 10 | } 11 | return this.$scopedSlots.default(this.context.value); 12 | } 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/Provider.js: -------------------------------------------------------------------------------- 1 | export default function Provider(context, defaultValue) { 2 | return { 3 | props: { 4 | value: { 5 | default: () => defaultValue 6 | } 7 | }, 8 | created() { 9 | if (this.value !== undefined) { 10 | context.value = this.value; 11 | } 12 | }, 13 | watch: { 14 | value(v) { 15 | context.value = v; 16 | } 17 | }, 18 | render(h) { 19 | return this.$slots.default[0]; 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/__tests__/Consumer.spec.js: -------------------------------------------------------------------------------- 1 | import consumer from "../Consumer"; 2 | import { mount } from "@vue/test-utils"; 3 | 4 | const registerComponent = context => ({ 5 | components: { 6 | Consumer: consumer(context) 7 | } 8 | }); 9 | 10 | const ConsumerComponent = context => ({ 11 | template: ` 12 | 13 | 14 | {{ contextValue }} 15 | 16 | 17 | `, 18 | ...registerComponent(context) 19 | }); 20 | 21 | const MalformedConsumerComponent = context => ({ 22 | template: ` 23 | 24 | 25 | test 26 | 27 | 28 | `, 29 | ...registerComponent(context) 30 | }); 31 | 32 | describe("Consumer", () => { 33 | it("should return the given context as data", () => { 34 | const s = Symbol(); 35 | expect(consumer(s).data().context).toBe(s); 36 | }); 37 | 38 | it("should render the context's value", () => { 39 | const Consumer = ConsumerComponent({ value: "test-context" }); 40 | const wrapper = mount(Consumer); 41 | expect(wrapper.html()).toContain("test-context"); 42 | }); 43 | 44 | it("should not fail to render if consumer is missing slot-scope", () => { 45 | const Consumer = MalformedConsumerComponent({ value: "test-context" }); 46 | const wrapper = mount(Consumer); 47 | expect(wrapper.html()).toContain("test"); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/__tests__/Provider.spec.js: -------------------------------------------------------------------------------- 1 | import provider from "../Provider"; 2 | import { mount } from "@vue/test-utils"; 3 | 4 | describe("Provider", () => { 5 | it("should have a prop with the given default value", () => { 6 | const defaultValue = "TEST"; 7 | const Provider = provider({}, defaultValue); 8 | const wrapper = mount(Provider, { 9 | slots: { 10 | default: "Test" 11 | } 12 | }); 13 | expect(wrapper.props().value).toBe(defaultValue); 14 | }); 15 | 16 | it("should not overwrite context if no prop provided", () => { 17 | let context = { value: "test" }; 18 | const Provider = provider(context); 19 | const wrapper = mount(Provider, { 20 | slots: { 21 | default: "Test" 22 | } 23 | }); 24 | expect(context.value).toBeDefined(); 25 | }); 26 | 27 | it("should update context when props change", () => { 28 | let context = { value: "test" }; 29 | const Provider = provider(context); 30 | const wrapper = mount(Provider, { 31 | slots: { 32 | default: "Test" 33 | } 34 | }); 35 | wrapper.setProps({ value: "123" }); 36 | expect(context.value).toBe("123"); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/createContext.js: -------------------------------------------------------------------------------- 1 | import Provider from "./Provider"; 2 | import Consumer from "./Consumer"; 3 | 4 | export const createContext = defaultValue => { 5 | let context = {}; 6 | return { 7 | Provider: Provider(context, defaultValue), 8 | Consumer: Consumer(context) 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { createContext } from "./createContext"; 2 | --------------------------------------------------------------------------------