├── .prettierrc ├── .gitignore ├── todo-list-screenshot.png ├── .vscode └── settings.json ├── .babelrc ├── src ├── context-easy.css ├── index.js ├── select.js ├── textarea.js ├── checkbox.js ├── checkboxes.js ├── radio-buttons.js ├── input.js ├── context-easy.test.js └── context-easy.js ├── .eslintrc.json ├── LICENSE ├── talk-abstract.txt ├── package.json ├── README.md └── hooks.md /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /coverage 3 | /lib 4 | /node_modules 5 | .DS_Store 6 | npm-debug.log* 7 | -------------------------------------------------------------------------------- /todo-list-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mvolkmann/context-easy/HEAD/todo-list-screenshot.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Dodds", 4 | "Vitullo", 5 | "hypot" 6 | ] 7 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", {"useBuiltIns": false}], 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties", 8 | "@babel/plugin-transform-runtime" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/context-easy.css: -------------------------------------------------------------------------------- 1 | .context-easy-checkbox, 2 | .context-easy-radio-buttons { 3 | display: flex; 4 | align-items: center; 5 | } 6 | 7 | .context-easy-checkbox > div { 8 | margin-left: 5px; 9 | } 10 | 11 | .context-easy-checkbox > input[type='checkbox'] { 12 | margin-left: 0; 13 | } 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export {default as Checkbox} from './checkbox'; 2 | export {default as Checkboxes} from './checkboxes'; 3 | export {default as Input} from './input'; 4 | export {default as RadioButtons} from './radio-buttons'; 5 | export {default as Select} from './select'; 6 | export {default as TextArea} from './textarea'; 7 | export * from './context-easy'; 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true, 6 | "node": true 7 | }, 8 | 9 | "parser": "babel-eslint", 10 | 11 | "parserOptions": { 12 | "ecmaVersion": 7, 13 | "sourceType": "module", 14 | "ecmaFeatures": { 15 | "jsx": true 16 | } 17 | }, 18 | 19 | "extends": [ 20 | "eslint:recommended", 21 | "plugin:import/recommended", 22 | "plugin:jsx-a11y/recommended", 23 | "plugin:prettier/recommended", 24 | "plugin:react/recommended", 25 | "prettier" 26 | ], 27 | 28 | "plugins": ["html", "jsx-a11y", "prettier", "react"], 29 | 30 | "settings": { 31 | "react": { 32 | "version": "detect" 33 | } 34 | }, 35 | 36 | "rules": { 37 | "no-console": "off" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/select.js: -------------------------------------------------------------------------------- 1 | import {bool, func, node, string} from 'prop-types'; 2 | import React, {useContext} from 'react'; 3 | 4 | import {EasyContext} from './context-easy'; 5 | 6 | export default function Select(props) { 7 | const context = useContext(EasyContext); 8 | 9 | const handleChange = event => { 10 | const {onChange, path} = props; 11 | const {value} = event.target; 12 | if (path) context.set(path, value); 13 | if (onChange) onChange(event); 14 | }; 15 | 16 | const {children, path} = props; 17 | 18 | let value = context.get(path); 19 | if (value === undefined) value = ''; 20 | 21 | const selectProps = {...props, value}; 22 | delete selectProps.dispatch; 23 | 24 | return ( 25 | 28 | ); 29 | } 30 | 31 | Select.propTypes = { 32 | children: node, 33 | className: string, 34 | multiple: bool, 35 | onChange: func, 36 | path: string 37 | }; 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mark Volkmann 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 | -------------------------------------------------------------------------------- /src/textarea.js: -------------------------------------------------------------------------------- 1 | import {func, string} from 'prop-types'; 2 | import React, {useContext, useEffect, useRef} from 'react'; 3 | 4 | import {EasyContext} from './context-easy'; 5 | 6 | export default function TextArea(props) { 7 | const context = useContext(EasyContext); 8 | 9 | const cursorRef = useRef(); 10 | const textAreaRef = useRef(); 11 | 12 | useEffect(() => { 13 | const {current} = cursorRef; 14 | if (current) { 15 | textAreaRef.current.setSelectionRange(current, current); 16 | } 17 | }); 18 | 19 | const handleChange = event => { 20 | const {onChange, path} = props; 21 | const {value} = event.target; 22 | 23 | cursorRef.current = textAreaRef.current.selectionStart; 24 | 25 | if (path) context.set(path, value); 26 | if (onChange) onChange(event); 27 | }; 28 | 29 | const {path} = props; 30 | const value = context.get(path); 31 | const textAreaProps = {...props, value}; 32 | return ( 33 |