├── .eslintignore ├── commitlint.config.js ├── .npmignore ├── .prettierrc ├── tsconfig.eslint.json ├── .github ├── assets │ └── material-ui.png ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md ├── .huskyrc ├── .lintstagedrc ├── .editorconfig ├── packages └── material-ui │ ├── tsconfig.json │ ├── lib │ ├── Switch │ │ ├── types.ts │ │ └── index.tsx │ ├── Checkbox │ │ ├── types.ts │ │ └── index.tsx │ ├── TextField │ │ ├── types.ts │ │ └── index.tsx │ ├── index.ts │ ├── debug.ts │ └── Select │ │ ├── types.ts │ │ └── index.tsx │ ├── jest.config.js │ ├── __tests__ │ ├── utils │ │ └── RenderTest.tsx │ └── components │ │ ├── Switch.spec.tsx │ │ ├── Checkbox.spec.tsx │ │ ├── TextField.spec.tsx │ │ └── Select.spec.tsx │ ├── package.json │ ├── CHANGELOG.md │ └── README.md ├── examples └── material-ui │ ├── src │ ├── index.tsx │ ├── Container │ │ ├── index.tsx │ │ └── styles.ts │ ├── App.tsx │ ├── Form │ │ ├── useRandomPerson.ts │ │ └── index.tsx │ └── styles.ts │ ├── babel.config.js │ ├── public │ └── index.html │ ├── webpack.config.js │ ├── package.json │ └── CHANGELOG.md ├── jest.config.js ├── .travis.yml ├── tsconfig.json ├── lerna.json ├── LICENCE ├── README.md ├── .gitignore ├── rollup.config.js ├── package.json └── .eslintrc.js /.eslintignore: -------------------------------------------------------------------------------- 1 | commitlint.config.js 2 | rollup.config.js 3 | jest.config.js 4 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['rocketseat'], 3 | }; 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn-error.log 3 | dist 4 | example 5 | __tests__ 6 | .github 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "arrowParens": "avoid" 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { "strict": true }, 3 | "include": ["packages/**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /.github/assets/material-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/italoiz/unform-community-packages/HEAD/.github/assets/material-ui.png -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "lint-staged", 4 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "packages/**/*.{js,jsx,ts,tsx}": [ 3 | "eslint --ext js,jsx,ts,tsx --fix", 4 | "prettier --write" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true -------------------------------------------------------------------------------- /packages/material-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["./lib/**/*"], 4 | "exclude": ["node_modules", "./__tests__/**/*"] 5 | } 6 | -------------------------------------------------------------------------------- /examples/material-ui/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | 4 | import App from './App'; 5 | 6 | render(, document.getElementById('app')); 7 | -------------------------------------------------------------------------------- /packages/material-ui/lib/Switch/types.ts: -------------------------------------------------------------------------------- 1 | import { SwitchProps as BaseSwitchProps } from '@material-ui/core/Switch/Switch'; 2 | 3 | export type SwitchProps = Omit & { name: string }; 4 | -------------------------------------------------------------------------------- /packages/material-ui/lib/Checkbox/types.ts: -------------------------------------------------------------------------------- 1 | import { CheckboxProps as BaseCheckboxProps } from '@material-ui/core/Checkbox/Checkbox'; 2 | 3 | export type CheckboxProps = Omit & { name: string }; 4 | -------------------------------------------------------------------------------- /packages/material-ui/lib/TextField/types.ts: -------------------------------------------------------------------------------- 1 | import { TextFieldProps as BaseTextFieldProps } from '@material-ui/core/TextField/TextField'; 2 | 3 | export type TextFieldProps = BaseTextFieldProps & { 4 | name: string; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/material-ui/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TextField } from './TextField'; 2 | export { default as Checkbox } from './Checkbox'; 3 | export { default as Switch } from './Switch'; 4 | export { default as Select } from './Select'; 5 | -------------------------------------------------------------------------------- /examples/material-ui/src/Container/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { ContainerWrapper } from './styles'; 4 | 5 | const Container: React.FC = ({ children }) => ( 6 | {children} 7 | ); 8 | 9 | export default Container; 10 | -------------------------------------------------------------------------------- /examples/material-ui/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 10, 8 | }, 9 | }, 10 | ], 11 | '@babel/preset-react', 12 | '@babel/preset-typescript', 13 | ], 14 | }; 15 | -------------------------------------------------------------------------------- /packages/material-ui/lib/debug.ts: -------------------------------------------------------------------------------- 1 | export function printWarning(message: string): void { 2 | if (process.env.NODE_ENV !== 'production') { 3 | if (typeof console !== 'undefined') { 4 | console.error(`Warning: ${message}`); // eslint-disable-line 5 | } 6 | 7 | throw new Error(`Warning: ${message}`); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/material-ui/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Container from './Container'; 4 | import FormContainer from './Form'; 5 | import Styles from './styles'; 6 | 7 | const App: React.FC = () => ( 8 | 9 | 10 | 11 | 12 | ); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /examples/material-ui/src/Container/styles.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const ContainerWrapper = styled.main` 4 | width: 600px; 5 | margin: 30px auto; 6 | box-sizing: border-box; 7 | padding: 15px; 8 | background-color: #f4f4f4; 9 | 10 | h2 { 11 | font-size: 20px; 12 | font-weight: 400; 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /packages/material-ui/jest.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path'); 2 | 3 | const baseConfig = require('../../jest.config'); 4 | const pkg = require('./package.json'); 5 | 6 | delete baseConfig.projects; 7 | 8 | module.exports = { 9 | ...baseConfig, 10 | displayName: pkg.name, 11 | testMatch: [join(__dirname, '__tests__/**/*.spec.{ts,tsx}')], 12 | }; 13 | -------------------------------------------------------------------------------- /examples/material-ui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Material UI Examples 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/material-ui/lib/Select/types.ts: -------------------------------------------------------------------------------- 1 | import { SelectProps as BaseSelectProps } from '@material-ui/core/Select/Select'; 2 | 3 | export interface SelectOption { 4 | value: string | number; 5 | text: string | React.ReactNode; 6 | } 7 | 8 | export interface SelectProps extends Omit { 9 | name: string; 10 | options?: SelectOption[]; 11 | } 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bail: true, 3 | clearMocks: true, 4 | collectCoverage: true, 5 | collectCoverageFrom: ['packages/**/lib/**/*.{js,jsx,ts,tsx}'], 6 | coverageReporters: ['json', 'lcov'], 7 | projects: ['/packages/*/jest.config.js'], 8 | transform: { 9 | '^.+\\.(ts|tsx)$': 'ts-jest', 10 | }, 11 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 12 | }; 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '10' 5 | 6 | cache: 7 | yarn: true 8 | directories: 9 | - node_modules 10 | 11 | install: 12 | - yarn 13 | 14 | script: 15 | - commitlint-travis 16 | - yarn coveralls 17 | 18 | before_deploy: 19 | - yarn build 20 | 21 | deploy: 22 | skip_cleanup: true 23 | provider: npm 24 | email: $EMAIL 25 | api_key: 26 | secure: $API_KEY 27 | on: 28 | tags: true 29 | repo: italoiz/unform-community-packages 30 | -------------------------------------------------------------------------------- /packages/material-ui/__tests__/utils/RenderTest.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { render as rtlRender } from '@testing-library/react'; 4 | import { Form } from '@unform/web'; 5 | 6 | export default function RenderTest( 7 | children: React.ReactNode, 8 | props: Record = {}, 9 | ): any { 10 | const mockFunction = jest.fn(); 11 | return rtlRender( 12 |
13 | {children} 14 |
, 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /examples/material-ui/src/Form/useRandomPerson.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from 'react'; 2 | 3 | export function useRandomPerson() { 4 | const [loading, setLoading] = useState(false); 5 | 6 | const loadNewPerson = useCallback(async () => { 7 | setLoading(true); 8 | const data = await fetch('https://randomuser.me/api/?results=1') 9 | .then(res => { 10 | return res.json(); 11 | }) 12 | .then(res => res.results[0]); 13 | setLoading(false); 14 | return data; 15 | }, []); 16 | 17 | return { loading, loadNewPerson }; 18 | } 19 | -------------------------------------------------------------------------------- /examples/material-ui/src/styles.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | 3 | export default createGlobalStyle` 4 | * { 5 | outline: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | code { 10 | padding: 8px; 11 | background: #333; 12 | color: #f4f4f4; 13 | width: 100%; 14 | display: block; 15 | font-size: 16px; 16 | font-weight: 500; 17 | border-radius: 4px; 18 | overflow: auto; 19 | } 20 | 21 | div.action-buttons { 22 | margin: 20px 0px; 23 | button + button { 24 | margin-left: 10px; 25 | } 26 | } 27 | `; 28 | -------------------------------------------------------------------------------- /examples/material-ui/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: path.resolve(__dirname, 'src/index.tsx'), 5 | output: { 6 | path: path.resolve(__dirname, 'public'), 7 | filename: 'bundle.js', 8 | }, 9 | devServer: { 10 | contentBase: path.resolve(__dirname, 'public'), 11 | }, 12 | resolve: { 13 | extensions: ['.ts', '.tsx', '.js', '.jsx'], 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.tsx?$/, 19 | exclude: /node_modules/, 20 | use: { 21 | loader: 'babel-loader', 22 | }, 23 | }, 24 | ], 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "module": "esnext", 5 | "target": "es5", 6 | "lib": ["es6", "dom", "es2016", "es2017"], 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "declaration": true, 11 | "moduleResolution": "node", 12 | "forceConsistentCasingInFileNames": true, 13 | "noImplicitReturns": true, 14 | "noImplicitThis": true, 15 | "noImplicitAny": false, 16 | "strictNullChecks": true, 17 | "suppressImplicitAnyIndexErrors": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "allowSyntheticDefaultImports": true, 21 | "esModuleInterop": true, 22 | "baseUrl": "." 23 | }, 24 | "include": ["packages/**/*", "examples/**/*"], 25 | "exclude": ["node_modules", "packages/**/__tests__"] 26 | } 27 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "yarn", 3 | "useWorkspaces": true, 4 | "packages": ["packages/*"], 5 | "version": "independent", 6 | "command": { 7 | "version": { 8 | "allowBranch": "master", 9 | "message": "chore(release): Bump version", 10 | "tagVersionPrefix": "v", 11 | "conventionalCommits": true 12 | } 13 | }, 14 | "options": { 15 | "preset": { 16 | "name": "conventionalcommits", 17 | "types": [ 18 | { 19 | "type": "feat", 20 | "section": ":sparkles: Features", 21 | "hidden": false 22 | }, 23 | { "type": "fix", "section": ":bug: Bug Fixes", "hidden": false }, 24 | { "type": "docs", "section": ":memo: Docs", "hidden": false }, 25 | { "type": "test", "hidden": true }, 26 | { "type": "ci", "hidden": true }, 27 | { "type": "chore", "hidden": true } 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/material-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unform-material-ui-examples", 3 | "private": true, 4 | "version": "1.0.3", 5 | "main": "index.js", 6 | "author": "Italo Izaac ", 7 | "license": "MIT", 8 | "scripts": { 9 | "dev": "webpack-dev-server" 10 | }, 11 | "dependencies": { 12 | "@material-ui/core": "^4.11.0", 13 | "@unform/core": "^2.1.3", 14 | "@unform/web": "^2.1.3", 15 | "react": "^16.13.1", 16 | "react-dom": "^16.13.1", 17 | "styled-components": "^5.1.1", 18 | "unform-material-ui": "file:../../packages/material-ui" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.10.5", 22 | "@babel/preset-env": "^7.10.4", 23 | "@babel/preset-react": "^7.10.4", 24 | "@babel/preset-typescript": "^7.10.4", 25 | "@types/styled-components": "^5.1.1", 26 | "babel-loader": "^8.1.0", 27 | "webpack": "^4.43.0", 28 | "webpack-cli": "^3.3.12", 29 | "webpack-dev-server": "^3.11.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/material-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unform-material-ui", 3 | "version": "1.0.5", 4 | "author": "Italo Izaac ", 5 | "license": "MIT", 6 | "main": "dist/index.js", 7 | "module": "dist/index.es.js", 8 | "types": "typings/index.d.ts", 9 | "files": [ 10 | "dist", 11 | "typings" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/italoiz/unform-community-packages.git", 16 | "directory": "packages/material-ui" 17 | }, 18 | "scripts": { 19 | "test": "jest", 20 | "build": "rollup -c ../../rollup.config.js" 21 | }, 22 | "peerDependencies": { 23 | "@material-ui/core": "^4.10.0", 24 | "@unform/core": "^2.1.0", 25 | "react": "^16.8.0", 26 | "react-dom": "^16.8.0" 27 | }, 28 | "devDependencies": { 29 | "@testing-library/jest-dom": "^5.11.1", 30 | "@testing-library/react": "^10.4.7", 31 | "@testing-library/user-event": "^10.3.5", 32 | "@unform/web": "^2.1.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rocketseat 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 | -------------------------------------------------------------------------------- /packages/material-ui/lib/Switch/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | 3 | import { Switch as BaseSwitch } from '@material-ui/core'; 4 | import { useField } from '@unform/core'; 5 | 6 | import { printWarning } from '../debug'; 7 | import { SwitchProps } from './types'; 8 | 9 | const Switch: React.FC = ({ 10 | name, 11 | defaultChecked, 12 | ...restProps 13 | }) => { 14 | if (!name) { 15 | printWarning( 16 | 'Switch component must have a `name` property for correctly working.', 17 | ); 18 | } 19 | 20 | const inputRef = useRef(null); 21 | const { fieldName, defaultValue = false, registerField } = useField(name); 22 | 23 | useEffect(() => { 24 | if (fieldName) { 25 | registerField({ 26 | name: fieldName, 27 | ref: inputRef.current, 28 | path: 'checked', 29 | }); 30 | } 31 | }, [fieldName, registerField]); 32 | 33 | return ( 34 | 40 | ); 41 | }; 42 | 43 | export default Switch; 44 | -------------------------------------------------------------------------------- /examples/material-ui/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.3](https://github.com/italoiz/unform-community-packages/compare/unform-material-ui-examples@1.0.2...unform-material-ui-examples@1.0.3) (2020-09-22) 7 | 8 | **Note:** Version bump only for package unform-material-ui-examples 9 | 10 | 11 | 12 | 13 | 14 | ## [1.0.2](https://github.com/italoiz/unform-community-packages/compare/unform-material-ui-examples@1.0.1...unform-material-ui-examples@1.0.2) (2020-09-13) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * **select:** Shrink select field when zero value is present ([c5fb062](https://github.com/italoiz/unform-community-packages/commit/c5fb0625420b1d775926e58d8321b6e271127860)) 20 | 21 | 22 | 23 | 24 | 25 | ## 1.0.1 (2020-09-11) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * Fix the input label not shriking when input focus ([74f218f](https://github.com/italoiz/unform-community-packages/commit/74f218fadae5d3393dbe035c3e0936225ba0b314)), closes [#26](https://github.com/italoiz/unform-community-packages/issues/26) 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Community Packages for Unform Library 3 |

4 | 5 | ## Overview 6 | 7 | This library uses [Unform](https://github.com/Rocketseat/unform) to integrate with other libraries of the community to provide fast and simple development. An example is the [Material UI](https://material-ui.com) library. 8 | 9 | ## Integrations 10 | 11 | - [Material UI](packages/material-ui) 12 | 13 | ## Contributing 14 | 15 | Thanks for being interested on making this package better. We encourage everyone to help improving this project with some new features, bug fixes and performance issues. Please take a little bit of your time to read our guides, so this process can be faster and easier. 16 | 17 | ### Contribution Guidelines 18 | 19 | Take a moment to read about our [Contribution Guidelines](/.github/CONTRIBUTING.md) so you can understand how to submit an issue, commit and create pull requests. 20 | 21 | ### Code of Conduct 22 | 23 | We expect you to follow our [Code of Conduct](/.github/CODE_OF_CONDUCT.md). You can read it to understand what kind of behaviour will and will not be tolerated. 24 | 25 | ## License 26 | 27 | MIT © [Italo Izaac](https://github.com/italoiz) 28 | -------------------------------------------------------------------------------- /packages/material-ui/lib/Checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | 3 | import { Checkbox as BaseCheckbox } from '@material-ui/core'; 4 | import { useField } from '@unform/core'; 5 | 6 | import { printWarning } from '../debug'; 7 | import { CheckboxProps } from './types'; 8 | 9 | const Checkbox: React.FC = ({ 10 | name, 11 | defaultChecked, 12 | ...restProps 13 | }) => { 14 | if (!name) { 15 | printWarning( 16 | 'Checkbox component must have a `name` property for correctly working.', 17 | ); 18 | } 19 | 20 | const inputRef = useRef(null); 21 | const { fieldName, defaultValue = false, registerField } = useField(name); 22 | 23 | useEffect(() => { 24 | if (fieldName) { 25 | registerField({ 26 | name: fieldName, 27 | ref: inputRef.current, 28 | path: 'checked', 29 | }); 30 | } 31 | }, [fieldName, registerField]); 32 | 33 | return ( 34 | 40 | ); 41 | }; 42 | 43 | export default Checkbox; 44 | -------------------------------------------------------------------------------- /.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 (http://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 | # dotenv environment variable files 55 | .env* 56 | 57 | # Library 58 | dist/ 59 | typings/ 60 | 61 | # gatsby files 62 | .cache/ 63 | public/ 64 | 65 | # Mac files 66 | .DS_Store 67 | 68 | # Yarn 69 | yarn-error.log 70 | .pnp/ 71 | .pnp.js 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # examples files 77 | !examples/*/public/ -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import { terser } from 'rollup-plugin-terser'; 5 | import typescript from 'rollup-plugin-typescript2'; 6 | import url from '@rollup/plugin-url'; 7 | import path from 'path'; 8 | 9 | const PACKAGE_ROOT_PATH = process.cwd(); 10 | const INPUT_FILE = path.join(PACKAGE_ROOT_PATH, 'lib/index.ts'); 11 | const pkg = require(path.join(PACKAGE_ROOT_PATH, 'package.json')); 12 | 13 | function makeExternalPredicate(externalArr) { 14 | if (!externalArr.length) { 15 | return () => false; 16 | } 17 | const pattern = new RegExp(`^(${externalArr.join('|')})($|/)`); 18 | return id => pattern.test(id); 19 | } 20 | 21 | function getExternal() { 22 | const external = Object.keys(pkg.peerDependencies || {}); 23 | const allExternal = [...external, ...Object.keys(pkg.dependencies || {})]; 24 | 25 | return makeExternalPredicate(allExternal); 26 | } 27 | 28 | export default { 29 | input: INPUT_FILE, 30 | external: getExternal(), 31 | output: [ 32 | { 33 | file: path.resolve(PACKAGE_ROOT_PATH, 'dist/index.js'), 34 | format: 'cjs', 35 | sourcemap: true, 36 | }, 37 | { 38 | file: path.resolve(PACKAGE_ROOT_PATH, 'dist/index.es.js'), 39 | format: 'es', 40 | sourcemap: true, 41 | }, 42 | ], 43 | plugins: [ 44 | url(), 45 | resolve(), 46 | babel({ 47 | exclude: 'node_modules/**', 48 | }), 49 | typescript({ 50 | tsconfigOverride: { 51 | compilerOptions: { 52 | declarationDir: path.resolve(PACKAGE_ROOT_PATH, 'typings'), 53 | declarationMap: true, 54 | }, 55 | include: [path.resolve(PACKAGE_ROOT_PATH, 'lib/**/*')], 56 | }, 57 | rollupCommonJSResolveHack: true, 58 | useTsconfigDeclarationDir: true, 59 | objectHashIgnoreUnknownHack: true, 60 | }), 61 | commonjs(), 62 | terser(), 63 | ], 64 | }; 65 | -------------------------------------------------------------------------------- /packages/material-ui/__tests__/components/Switch.spec.tsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | import React from 'react'; 3 | 4 | import { fireEvent } from '@testing-library/react'; 5 | 6 | import { Switch } from '../../lib'; 7 | import render from '../utils/RenderTest'; 8 | 9 | describe(' Component', () => { 10 | it('should render correctly', () => { 11 | const { container } = render(); 12 | 13 | const input = container.querySelector('input[name=terms][type=checkbox]'); 14 | 15 | expect(!!input).toBe(true); 16 | }); 17 | 18 | it('should render with `defaultChecked` property when exists', () => { 19 | const { container } = render(); 20 | 21 | const input: any = container.querySelector('input[name=terms]'); 22 | expect(input.checked).toBe(true); 23 | }); 24 | 25 | it('should render with initial data when `initialData` property exists', () => { 26 | const { container } = render(, { 27 | initialData: { terms: true }, 28 | }); 29 | 30 | const input: any = container.querySelector('input[name=terms]'); 31 | expect(input.checked).toBe(true); 32 | }); 33 | 34 | it('should return form data on submit form', () => { 35 | const submitMock = jest.fn(); 36 | 37 | const { container, getByTestId } = render(, { 38 | onSubmit: submitMock, 39 | }); 40 | 41 | const input: any = container.querySelector('input[name=terms]'); 42 | 43 | fireEvent.change(input, { target: { checked: true } }); 44 | fireEvent.submit(getByTestId('form')); 45 | 46 | expect(submitMock).toHaveBeenCalledWith( 47 | { terms: true }, 48 | expect.any(Object), 49 | expect.any(Object), 50 | ); 51 | }); 52 | 53 | it('should throw an error when `name` property not passed', () => { 54 | console.error = jest.fn(); // eslint-disable-line no-console 55 | 56 | expect(() => { 57 | const props = {} as any; 58 | render(); 59 | }).toThrow( 60 | 'Switch component must have a `name` property for correctly working.', 61 | ); 62 | 63 | expect(console.error).toHaveBeenCalled(); // eslint-disable-line no-console 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /packages/material-ui/__tests__/components/Checkbox.spec.tsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | import React from 'react'; 3 | 4 | import { fireEvent } from '@testing-library/react'; 5 | 6 | import { Checkbox } from '../../lib'; 7 | import render from '../utils/RenderTest'; 8 | 9 | describe(' Component', () => { 10 | it('should render correctly', () => { 11 | const { container } = render(); 12 | 13 | const input = container.querySelector('input[name=terms][type=checkbox]'); 14 | 15 | expect(!!input).toBe(true); 16 | }); 17 | 18 | it('should render with `defaultChecked` property when exists', () => { 19 | const { container } = render(); 20 | 21 | const input: any = container.querySelector('input[name=terms]'); 22 | expect(input.checked).toBe(true); 23 | }); 24 | 25 | it('should render with initial data when `initialData` property exists', () => { 26 | const { container } = render(, { 27 | initialData: { terms: true }, 28 | }); 29 | 30 | const input: any = container.querySelector('input[name=terms]'); 31 | expect(input.checked).toBe(true); 32 | }); 33 | 34 | it('should return form data on submit form', () => { 35 | const submitMock = jest.fn(); 36 | 37 | const { container, getByTestId } = render(, { 38 | onSubmit: submitMock, 39 | }); 40 | 41 | const input: any = container.querySelector('input[name=terms]'); 42 | 43 | fireEvent.change(input, { target: { checked: true } }); 44 | fireEvent.submit(getByTestId('form')); 45 | 46 | expect(submitMock).toHaveBeenCalledWith( 47 | { terms: true }, 48 | expect.any(Object), 49 | expect.any(Object), 50 | ); 51 | }); 52 | 53 | it('should throw an error when `name` property not passed', () => { 54 | console.error = jest.fn(); // eslint-disable-line no-console 55 | 56 | expect(() => { 57 | const props = {} as any; 58 | render(); 59 | }).toThrow( 60 | 'Checkbox component must have a `name` property for correctly working', 61 | ); 62 | 63 | expect(console.error).toHaveBeenCalled(); // eslint-disable-line no-console 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unform-community-packages", 3 | "version": "1.0.1", 4 | "private": true, 5 | "workspaces": { 6 | "packages": [ 7 | "packages/*", 8 | "examples/*" 9 | ] 10 | }, 11 | "license": "MIT", 12 | "scripts": { 13 | "prebuild": "lerna exec --parallel -- rimraf dist", 14 | "build": "lerna run --parallel --stream build", 15 | "test": "jest", 16 | "coveralls": "jest && cat ./coverage/lcov.info | coveralls", 17 | "prepublish": "yarn build" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.8.4", 21 | "@commitlint/cli": "^8.3.5", 22 | "@commitlint/config-conventional": "^8.3.4", 23 | "@commitlint/travis-cli": "^8.3.5", 24 | "@material-ui/core": "^4.10.0", 25 | "@rollup/plugin-commonjs": "^11.0.2", 26 | "@rollup/plugin-node-resolve": "^7.1.1", 27 | "@rollup/plugin-url": "^4.0.2", 28 | "@types/jest": "^25.1.3", 29 | "@types/react": "^16.9.22", 30 | "@types/react-dom": "^16.9.5", 31 | "@types/react-test-renderer": "^16.9.2", 32 | "@typescript-eslint/eslint-plugin": "^3.6.1", 33 | "@typescript-eslint/parser": "^3.6.1", 34 | "@unform/core": "^2.1.0", 35 | "@unform/web": "^2.1.0", 36 | "commitlint-config-rocketseat": "^0.0.1", 37 | "coveralls": "^3.0.9", 38 | "eslint": "^6.8.0", 39 | "eslint-config-airbnb": "^18.0.1", 40 | "eslint-config-prettier": "^6.10.0", 41 | "eslint-import-resolver-typescript": "^2.0.0", 42 | "eslint-plugin-import": "^2.20.1", 43 | "eslint-plugin-import-helpers": "^1.0.2", 44 | "eslint-plugin-jest": "^23.8.0", 45 | "eslint-plugin-jsx-a11y": "^6.2.3", 46 | "eslint-plugin-prettier": "^3.1.2", 47 | "eslint-plugin-react": "^7.18.3", 48 | "eslint-plugin-react-hooks": "^2.4.0", 49 | "husky": "^4.2.3", 50 | "jest": "^25.1.0", 51 | "jest-dom": "^4.0.0", 52 | "lerna": "^3.20.2", 53 | "lint-staged": "^10.0.7", 54 | "npm-run-all": "^4.1.5", 55 | "prettier": "^1.19.1", 56 | "react": "^16.12.0", 57 | "react-dom": "^16.12.0", 58 | "react-scripts": "^3.4.1", 59 | "react-test-renderer": "^16.12.0", 60 | "rimraf": "^3.0.2", 61 | "rollup": "^1.31.1", 62 | "rollup-plugin-babel": "^4.3.3", 63 | "rollup-plugin-terser": "^5.2.0", 64 | "rollup-plugin-typescript2": "^0.26.0", 65 | "ts-jest": "^25.2.1", 66 | "typescript": "^3.9.7" 67 | }, 68 | "repository": { 69 | "type": "git", 70 | "url": "https://github.com/italoiz/unform-community-packages.git" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | module.exports = { 4 | root: true, 5 | env: { 6 | browser: true, 7 | es6: true, 8 | jest: true, 9 | }, 10 | globals: { 11 | Atomics: 'readonly', 12 | SharedArrayBuffer: 'readonly', 13 | }, 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | tsx: true, 18 | }, 19 | ecmaVersion: 2018, 20 | sourceType: 'module', 21 | }, 22 | parser: '@typescript-eslint/parser', 23 | plugins: [ 24 | '@typescript-eslint', 25 | 'import', 26 | 'import-helpers', 27 | 'react-hooks', 28 | 'jest', 29 | 'prettier', 30 | ], 31 | extends: [ 32 | 'airbnb', 33 | 'plugin:@typescript-eslint/recommended', 34 | 'prettier/@typescript-eslint', 35 | 'plugin:prettier/recommended', 36 | ], 37 | rules: { 38 | 'prettier/prettier': 'error', 39 | 'class-methods-use-this': 'off', 40 | '@typescript-eslint/no-explicit-any': 'off', 41 | '@typescript-eslint/interface-name-prefix': 'off', 42 | '@typescript-eslint/no-var-requires': 'off', 43 | '@typescript-eslint/camelcase': 'off', 44 | '@typescript-eslint/explicit-function-return-type': 'off', 45 | 'react/jsx-filename-extension': [ 46 | 'warn', 47 | { 48 | extensions: ['.jsx', '.tsx'], 49 | }, 50 | ], 51 | 'import-helpers/order-imports': [ 52 | 'warn', 53 | { 54 | newlinesBetween: 'always', 55 | groups: [ 56 | ['/^react/'], 57 | 'module', 58 | '/^@/', 59 | ['parent', 'sibling', 'index'], 60 | ], 61 | alphabetize: { order: 'asc', ignoreCase: true }, 62 | }, 63 | ], 64 | 'import/no-dynamic-require': 'off', 65 | 'no-param-reassign': 'off', 66 | 'no-unused-expressions': 'off', 67 | 'no-underscore-dangle': 'off', 68 | 'react/prop-types': 'off', 69 | 'jsx-a11y/label-has-for': 'off', 70 | 'import/prefer-default-export': 'off', 71 | 'react-hooks/rules-of-hooks': 'error', 72 | 'react-hooks/exhaustive-deps': 'warn', 73 | 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], 74 | 'import/extensions': [ 75 | 'error', 76 | 'ignorePackages', 77 | { 78 | ts: 'never', 79 | tsx: 'never', 80 | }, 81 | ], 82 | 'react/jsx-props-no-spreading': 'off', 83 | }, 84 | settings: { 85 | 'import/extensions': ['.js', '.jsx', '.ts', '.tsx'], 86 | 'import/parsers': { 87 | '@typescript-eslint/parser': ['.js', '.jsx', '.ts', '.tsx'], 88 | }, 89 | 'import/resolver': { 90 | typescript: {}, 91 | }, 92 | }, 93 | }; 94 | -------------------------------------------------------------------------------- /packages/material-ui/lib/TextField/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect, useState } from 'react'; 2 | 3 | import { TextField as BaseTextField } from '@material-ui/core'; 4 | import { useField } from '@unform/core'; 5 | 6 | import { printWarning } from '../debug'; 7 | import { TextFieldProps } from './types'; 8 | 9 | const TextField: React.FC = ({ 10 | name, 11 | helperText, 12 | defaultValue, 13 | InputLabelProps, 14 | ...restProps 15 | }) => { 16 | if (!name) { 17 | printWarning( 18 | 'TextField component must have a `name` property for correctly working.', 19 | ); 20 | } 21 | 22 | const inputRef = useRef(null); 23 | const { 24 | fieldName, 25 | defaultValue: defaultFieldValue, 26 | registerField, 27 | error, 28 | } = useField(name); 29 | const defaultInputValue = defaultValue ?? defaultFieldValue; 30 | const [shrink, setShrink] = useState(!!defaultInputValue); 31 | 32 | useEffect(() => { 33 | if (fieldName) { 34 | registerField({ 35 | name: fieldName, 36 | ref: inputRef.current, 37 | path: 'value', 38 | clearValue(ref, resetValue: string) { 39 | const newValue = resetValue ?? defaultInputValue ?? ''; 40 | ref.value = newValue; 41 | setShrink(!!newValue); 42 | }, 43 | setValue(ref: HTMLInputElement, value: string) { 44 | if (ref) { 45 | const newValue = value ?? ''; 46 | ref.value = newValue; 47 | setShrink(!!newValue); 48 | } 49 | }, 50 | }); 51 | } 52 | }, [fieldName, registerField, defaultInputValue, setShrink]); 53 | 54 | useEffect(() => { 55 | const input = inputRef.current; 56 | 57 | function handlerFocusEvent(evt: FocusEvent) { 58 | const inputValue = (evt.currentTarget as HTMLInputElement).value; 59 | if (!inputValue) setShrink(true); 60 | } 61 | 62 | function handlerBlurEvent(evt: FocusEvent) { 63 | const inputValue = (evt.target as HTMLInputElement).value; 64 | if (!inputValue) setShrink(false); 65 | } 66 | 67 | if (input) { 68 | input.addEventListener('focus', handlerFocusEvent); 69 | input.addEventListener('blur', handlerBlurEvent); 70 | } 71 | 72 | return () => { 73 | if (input) { 74 | input.removeEventListener('focus', handlerFocusEvent); 75 | input.removeEventListener('blur', handlerBlurEvent); 76 | } 77 | }; 78 | }, [inputRef]); 79 | 80 | return ( 81 | 93 | ); 94 | }; 95 | 96 | export default React.memo(TextField); 97 | -------------------------------------------------------------------------------- /packages/material-ui/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [1.0.5](https://github.com/italoiz/unform-community-packages/compare/unform-material-ui@1.0.4...unform-material-ui@1.0.5) (2020-09-22) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **material-ui:** Fix the package typings output correctly ([c2ce799](https://github.com/italoiz/unform-community-packages/commit/c2ce79915fda832259f71819b227d9a60ff2d9c4)), closes [#29](https://github.com/italoiz/unform-community-packages/issues/29) 12 | 13 | 14 | 15 | 16 | 17 | ## [1.0.4](https://github.com/italoiz/unform-community-packages/compare/unform-material-ui@1.0.3...unform-material-ui@1.0.4) (2020-09-13) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * **select:** Shrink select field when zero value is present ([c5fb062](https://github.com/italoiz/unform-community-packages/commit/c5fb0625420b1d775926e58d8321b6e271127860)) 23 | 24 | 25 | 26 | 27 | 28 | ## [1.0.3](https://github.com/italoiz/unform-community-packages/compare/unform-material-ui@1.0.2...unform-material-ui@1.0.3) (2020-09-11) 29 | 30 | 31 | ### Bug Fixes 32 | 33 | * Fix the 47 | Male 48 | Female 49 | 50 | 51 | 52 | 61 | 62 | 63 | 72 | 73 | 74 | 75 |
76 | 85 | 96 | 106 |
107 | 108 |
{JSON.stringify(data, null, 3)}
109 |
110 | 111 | ); 112 | }; 113 | 114 | export default FormWrapper; 115 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This Code of Conduct outlines our expectations for participants within the Rocketseat community as well as steps to reporting unacceptable behavior. Our goal is to make explicit what we expect from participants in this community as well as its leaders. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. 4 | 5 | Our community strives to: 6 | 7 | - **Be welcoming, friendly and patient**. 8 | - **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that you might not be communicating in someone else’s primary language. 9 | - **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. 10 | - **Be understandable**: Disagreements, both social and technical, happen all the time and Rocketseat is no exception. It is important that we resolve disagreements and differing views constructively. Remember that we're different. The strength of Rocketseat comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn't mean that they're wrong. Don't forget that it is human to err and blaming each other doesn't get us anywhere, rather offer to help resolving issues and to help learn from mistakes. 11 | 12 | This code serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter. 13 | 14 | ### Diversity Statement 15 | 16 | We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. 17 | 18 | Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities. 19 | 20 | ### Reporting Issues 21 | 22 | If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via italoiz.dev@gmail.com. All reports will be handled with discretion. In your report please include: 23 | 24 | - Your contact information. 25 | - Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record, please include a link. 26 | - Any additional information that may be helpful. 27 | 28 | After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse. 29 | 30 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning. 31 | 32 | _This Code Of Conduct follows the template established by [TODO Group](https://todogroup.org)_. 33 | -------------------------------------------------------------------------------- /packages/material-ui/lib/Select/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useEffect, 3 | useRef, 4 | useState, 5 | useMemo, 6 | useCallback, 7 | } from 'react'; 8 | 9 | import { 10 | Select as BaseSelect, 11 | FormControl, 12 | InputLabel, 13 | FormHelperText, 14 | } from '@material-ui/core'; 15 | import { useField } from '@unform/core'; 16 | 17 | import { printWarning } from '../debug'; 18 | import { SelectProps } from './types'; 19 | 20 | function getOptionsCollectionArray( 21 | options: HTMLOptionsCollection, 22 | ): HTMLOptionElement[] { 23 | const arr: HTMLOptionElement[] = []; 24 | for (let i = 0; i < options.length; i += 1) { 25 | arr.push(options[i]); 26 | } 27 | return arr; 28 | } 29 | 30 | function isValidValue(value: string | number | boolean): boolean { 31 | return typeof value !== 'undefined' && value !== ''; 32 | } 33 | 34 | const Select: React.FC = ({ 35 | name, 36 | label, 37 | style, 38 | className, 39 | defaultValue, 40 | children, 41 | native, 42 | onChange, 43 | value: valueProp, 44 | multiple, 45 | variant, 46 | ...restProps 47 | }) => { 48 | if (!name) { 49 | printWarning( 50 | 'Select component must have a `name` property for correctly working.', 51 | ); 52 | } 53 | 54 | const { 55 | fieldName, 56 | registerField, 57 | defaultValue: defaultFieldValue, 58 | error, 59 | } = useField(name); 60 | 61 | const inputRef = useRef(null); 62 | const defaultInputValue = useMemo(() => { 63 | if (multiple) { 64 | return defaultFieldValue || defaultValue || []; 65 | } 66 | return defaultFieldValue || defaultValue || ''; 67 | }, [defaultFieldValue, defaultValue, multiple]); 68 | const [inputValue, setInputValue] = useState(defaultInputValue); 69 | 70 | const _handleChange = useCallback( 71 | e => { 72 | const el = e.target; 73 | let value: number | number[] | string | string[]; 74 | 75 | if (native && multiple) { 76 | value = getOptionsCollectionArray(el.options) 77 | .filter(opt => opt.selected) 78 | .map(opt => opt.value); 79 | } else { 80 | value = el.value; 81 | } 82 | 83 | if (valueProp === undefined && onChange === undefined) { 84 | setInputValue(() => value); 85 | } 86 | 87 | if (valueProp === undefined && typeof onChange === 'function') { 88 | setInputValue(() => value); 89 | onChange(e, null); 90 | } 91 | 92 | if (valueProp !== undefined && typeof onChange === 'function') { 93 | onChange(e, null); 94 | } 95 | }, 96 | [valueProp, onChange, setInputValue, multiple, native], 97 | ); 98 | 99 | useEffect(() => { 100 | if (fieldName) { 101 | registerField({ 102 | name: fieldName, 103 | ref: inputRef.current, 104 | getValue() { 105 | return valueProp || inputValue; 106 | }, 107 | setValue(_, newValue: string | string[] | number[]) { 108 | _handleChange({ 109 | target: { value: newValue }, 110 | }); 111 | }, 112 | }); 113 | } 114 | }, [fieldName, registerField, _handleChange, native, valueProp, inputValue]); 115 | 116 | const baseSelectProps: SelectProps = useMemo( 117 | () => ({ 118 | value: !valueProp ? inputValue : valueProp, 119 | inputProps: { 120 | ...restProps.inputProps, 121 | ref: inputRef, 122 | }, 123 | defaultValue: defaultInputValue || inputValue, 124 | onChange: _handleChange, 125 | name, 126 | multiple, 127 | label, 128 | ...restProps, 129 | }), 130 | [ 131 | inputValue, 132 | defaultInputValue, 133 | name, 134 | restProps, 135 | _handleChange, 136 | valueProp, 137 | multiple, 138 | label, 139 | ], 140 | ); 141 | 142 | const shrink = useMemo(() => { 143 | if (native) { 144 | return true; 145 | } 146 | 147 | if (multiple) { 148 | return !!(valueProp || inputValue).length; 149 | } 150 | 151 | return isValidValue(valueProp as any) || !!isValidValue(inputValue); 152 | }, [native, multiple, inputValue, valueProp]); 153 | 154 | return ( 155 | 161 | {!!label && ( 162 | 163 | {label} 164 | 165 | )} 166 | 167 | 168 | {children} 169 | 170 | 171 | {!!error && {error}} 172 | 173 | ); 174 | }; 175 | 176 | export default React.memo(Select); 177 | -------------------------------------------------------------------------------- /packages/material-ui/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | ![](../../.github/assets/material-ui.png) 4 | 5 |

6 | 7 |
8 | 9 | [![npm](https://img.shields.io/npm/v/unform-material-ui.svg)](https://www.npmjs.com/package/unform-material-ui) 10 | [![Build Status](https://travis-ci.org/italoiz/unform-material-ui.svg?branch=master)](https://travis-ci.org/italoiz/unform-material-ui) 11 | [![Coverage Status](https://coveralls.io/repos/github/italoiz/unform-material-ui/badge.svg?branch=master)](https://coveralls.io/github/italoiz/unform-material-ui?branch=master) 12 | 13 |
14 | 15 | ## Overview 16 | 17 | This library uses [Unform](https://github.com/Rocketseat/unform) + [Material UI](https://material-ui.com) styles to create super beautiful forms easily. 18 | 19 | ## Table of contents 20 | 21 | - [Overview](#overview) 22 | - [Table of contents](#table-of-contents) 23 | - [Roadmap](#roadmap) 24 | - [Installation](#installation) 25 | - [Guides](#guides) 26 | - [Basics](#basics) 27 | - [Components](#components) 28 | - [`` Component](#textfield--component) 29 | - [``. See the component documentation [here](https://material-ui.com/api/text-field/) for more information. 66 | 67 | ```jsx 68 | import React from 'react'; 69 | import { Form } from '@unform/web'; 70 | import { TextField } from 'unform-material-ui'; 71 | 72 | function App() { 73 | function handleSubmit(data) {} 74 | 75 | return ( 76 |
77 | 78 | 79 | 80 | 81 | 82 | ); 83 | } 84 | ``` 85 | 86 | #### `` component, is similar to the default component ` 109 | Node 110 | React 111 | 112 | 113 | 117 | 118 | 119 | 120 | ); 121 | } 122 | ``` 123 | 124 | #### `` Component 125 | 126 | The `` component, is similar to the default component ``. See the component documentation [here](https://material-ui.com/api/checkboxes/) for more information. 127 | 128 | ```jsx 129 | import React from 'react'; 130 | import { Form } from '@rocketseat/unform'; 131 | import { Checkbox } from 'unform-material-ui'; 132 | 133 | function App() { 134 | function handleSubmit(data) { 135 | /** 136 | * { 137 | * "terms": true, 138 | * "acceptEmails": true 139 | * } 140 | */ 141 | } 142 | 143 | return ( 144 |
145 | {/* not controlled */} 146 | 147 | 148 | {/* internally controlled */} 149 | 150 | 151 | 152 | 153 | ); 154 | } 155 | ``` 156 | 157 | #### `` Component 158 | 159 | The `` component, is similar to the default component ``. See the component documentation [here](https://material-ui.com/api/switch/) for more information. 160 | 161 | ```jsx 162 | import React from 'react'; 163 | import { Form } from '@rocketseat/unform'; 164 | import { Switch } from 'unform-material-ui'; 165 | 166 | function App() { 167 | function handleSubmit(data) { 168 | /** 169 | * { 170 | * "terms": true, 171 | * "acceptEmails": true 172 | * } 173 | */ 174 | } 175 | 176 | return ( 177 |
178 | {/* not controlled */} 179 | 180 | 181 | {/* internally controlled */} 182 | 183 | 184 | 185 | 186 | ); 187 | } 188 | ``` 189 | 190 | ## Contributing 191 | 192 | Thanks for being interested on making this package better. We encourage everyone to help improving this project with some new features, bug fixes and performance issues. Please take a little bit of your time to read our guides, so this process can be faster and easier. 193 | 194 | ### Contribution Guidelines 195 | 196 | Take a moment to read about our [Contribution Guidelines](/.github/CONTRIBUTING.md) so you can understand how to submit an issue, commit and create pull requests. 197 | 198 | ### Code of Conduct 199 | 200 | We expect you to follow our [Code of Conduct](/.github/CODE_OF_CONDUCT.md). You can read it to understand what kind of behaviour will and will not be tolerated. 201 | 202 | ## License 203 | 204 | MIT © [Italo Izaac](https://github.com/italoiz) 205 | -------------------------------------------------------------------------------- /packages/material-ui/__tests__/components/TextField.spec.tsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | import React, { RefObject } from 'react'; 3 | 4 | import { fireEvent, act } from '@testing-library/react'; 5 | import { FormHandles } from '@unform/core'; 6 | 7 | import { TextField } from '../../lib'; 8 | import render from '../utils/RenderTest'; 9 | 10 | describe(' Component', () => { 11 | it('should render correctly', () => { 12 | const { container } = render(); 13 | 14 | expect(!!container.querySelector('input[name=name]')).toBe(true); 15 | }); 16 | 17 | it('should render with `defaultValue` property when exists', () => { 18 | const { container } = render( 19 | , 20 | ); 21 | 22 | expect(container.querySelector('input[name=name]')).toHaveAttribute( 23 | 'value', 24 | 'foo bar', 25 | ); 26 | }); 27 | 28 | it('should render with initial data when `initialData` property exists', () => { 29 | const { container } = render(, { 30 | initialData: { name: 'foo bar' }, 31 | }); 32 | 33 | expect(container.querySelector('input[name=name]')).toHaveAttribute( 34 | 'value', 35 | 'foo bar', 36 | ); 37 | }); 38 | 39 | it('should return form data on submit form', () => { 40 | const submitMock = jest.fn(); 41 | 42 | const { container, getByTestId } = render(, { 43 | onSubmit: submitMock, 44 | }); 45 | 46 | const input: any = container.querySelector('input[name=name]'); 47 | 48 | fireEvent.change(input, { target: { value: 'foo bar' } }); 49 | fireEvent.submit(getByTestId('form')); 50 | 51 | expect(submitMock).toHaveBeenCalledWith( 52 | { name: 'foo bar' }, 53 | expect.any(Object), 54 | expect.any(Object), 55 | ); 56 | }); 57 | 58 | it('should display the error when the field error exists.', () => { 59 | const formRef: RefObject = { current: null }; 60 | 61 | const { getByText } = render(, { 62 | ref: formRef, 63 | }); 64 | 65 | act(() => { 66 | if (formRef.current) { 67 | formRef.current.setFieldError('name', 'Name is required'); 68 | } 69 | }); 70 | 71 | expect(!!getByText('Name is required')).toBe(true); 72 | }); 73 | 74 | it('should throw an error when `name` property not passed', () => { 75 | console.error = jest.fn(); // eslint-disable-line no-console 76 | 77 | expect(() => { 78 | const props = {} as any; 79 | render(); 80 | }).toThrow( 81 | 'TextField component must have a `name` property for correctly working.', 82 | ); 83 | 84 | expect(console.error).toHaveBeenCalled(); // eslint-disable-line no-console 85 | }); 86 | 87 | it('should shrink label when focus on input', () => { 88 | const { getByTestId } = render( 89 | , 95 | ); 96 | 97 | const input = getByTestId('input'); 98 | const label = getByTestId('input-label'); 99 | 100 | act(() => { 101 | fireEvent.focus(input); 102 | }); 103 | expect(label).toHaveAttribute('data-shrink', 'true'); 104 | 105 | act(() => { 106 | fireEvent.blur(input); 107 | }); 108 | expect(label).toHaveAttribute('data-shrink', 'false'); 109 | }); 110 | 111 | it('should shrink label when value is change via unform api', () => { 112 | const formRef: RefObject = { current: null }; 113 | 114 | const { getByTestId } = render( 115 | , 120 | { 121 | ref: formRef, 122 | }, 123 | ); 124 | 125 | const label = getByTestId('input-label'); 126 | 127 | act(() => { 128 | if (formRef.current) { 129 | formRef.current.setData({ name: 'foo bar' }); 130 | } 131 | }); 132 | 133 | expect(label).toHaveAttribute('data-shrink', 'true'); 134 | }); 135 | 136 | it('should not shrink label when value is empty', () => { 137 | const formRef: RefObject = { current: null }; 138 | 139 | const { getByTestId } = render( 140 | , 145 | { 146 | ref: formRef, 147 | }, 148 | ); 149 | 150 | const label = getByTestId('input-label'); 151 | 152 | act(() => { 153 | if (formRef.current) { 154 | formRef.current.setData({ name: '' }); 155 | } 156 | }); 157 | 158 | expect(label).toHaveAttribute('data-shrink', 'false'); 159 | }); 160 | 161 | it('should not shrink label on reset input value', () => { 162 | const formRef: RefObject = { current: null }; 163 | 164 | const { getByTestId } = render( 165 | , 170 | { 171 | ref: formRef, 172 | }, 173 | ); 174 | 175 | const label = getByTestId('input-label'); 176 | 177 | act(() => { 178 | if (formRef.current) { 179 | formRef.current.reset(); 180 | } 181 | }); 182 | 183 | expect(label).toHaveAttribute('data-shrink', 'false'); 184 | }); 185 | 186 | it('should put reset value on input when data is passed to the reset function', () => { 187 | const formRef: RefObject = { current: null }; 188 | const submitMock = jest.fn(); 189 | 190 | const { getByTestId } = render( 191 | , 197 | { 198 | ref: formRef, 199 | onSubmit: submitMock, 200 | }, 201 | ); 202 | 203 | act(() => { 204 | if (formRef.current) { 205 | formRef.current.reset({ name: 'foo bar reseted' }); 206 | } 207 | }); 208 | 209 | fireEvent.submit(getByTestId('form')); 210 | expect(submitMock).toHaveBeenCalledWith( 211 | { name: 'foo bar reseted' }, 212 | expect.any(Object), 213 | expect.any(Object), 214 | ); 215 | }); 216 | 217 | it('should use prop `shrink` instead of default shrink behavior when property exists', () => { 218 | const { getByTestId } = render( 219 | , 224 | ); 225 | 226 | const label = getByTestId('input-label'); 227 | expect(label).toHaveAttribute('data-shrink', 'true'); 228 | }); 229 | 230 | it('should use empty value instead of `undefined` when use the `setData` function with inexistent property value', () => { 231 | const formRef: RefObject = { current: null }; 232 | const submitMock = jest.fn(); 233 | const { getByTestId } = render(, { 234 | ref: formRef, 235 | onSubmit: submitMock, 236 | }); 237 | 238 | act(() => { 239 | if (formRef.current) { 240 | formRef.current.setData({ 241 | email: 'foo@bar.com', 242 | }); 243 | } 244 | }); 245 | 246 | fireEvent.submit(getByTestId('form')); 247 | 248 | expect(submitMock).toHaveBeenCalledWith( 249 | { name: '' }, 250 | expect.any(Object), 251 | expect.any(Object), 252 | ); 253 | }); 254 | }); 255 | -------------------------------------------------------------------------------- /packages/material-ui/__tests__/components/Select.spec.tsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | import React, { RefObject } from 'react'; 3 | 4 | import { MenuItem } from '@material-ui/core'; 5 | import { fireEvent, act, screen } from '@testing-library/react'; 6 | import userEvent from '@testing-library/user-event'; 7 | import { FormHandles } from '@unform/core'; 8 | 9 | import { Select } from '../../lib'; 10 | import render from '../utils/RenderTest'; 11 | 12 | describe('); 15 | 16 | const input = container.querySelector('input[name=country]'); 17 | 18 | expect(!!input).toBe(true); 19 | }); 20 | 21 | it('should render select options correctly', () => { 22 | const { getByRole, getAllByRole } = render( 23 | , 27 | ); 28 | 29 | fireEvent.mouseDown(getByRole('button')); 30 | const options = getAllByRole('option'); 31 | expect(options.length).toBe(2); 32 | }); 33 | 34 | it('should render with `defaultValue` property when exists', () => { 35 | const { container, getByRole } = render( 36 | , 40 | ); 41 | 42 | const input: any = container.querySelector('input[name=country]'); 43 | const button = getByRole('button'); 44 | expect(input.value).toBe('us'); 45 | expect(button.textContent).toBe('United State'); 46 | }); 47 | 48 | it('should render with