From c0e8a68348c52aaee55168d8601fb534597b6313 Mon Sep 17 00:00:00 2001 From: Darren Eng Date: Fri, 11 Dec 2020 17:25:34 -0800 Subject: [PATCH] feat!: remove CustomInput - custom inputs no longer supported in bootstrap 5 https://getbootstrap.com/docs/5.0/migration/#forms-2 --- docs/lib/Components/FormPage.js | 32 --- docs/lib/examples/CustomControls.js | 105 --------- src/CustomFileInput.js | 128 ---------- src/CustomInput.js | 114 --------- src/__tests__/CustomInput.spec.js | 346 ---------------------------- src/index.js | 2 - types/index.d.ts | 2 - types/lib/CustomInput.d.ts | 30 --- types/lib/index.d.ts | 2 - types/reactstrap-tests.tsx | 227 ------------------ 10 files changed, 988 deletions(-) delete mode 100644 docs/lib/examples/CustomControls.js delete mode 100644 src/CustomFileInput.js delete mode 100644 src/CustomInput.js delete mode 100644 src/__tests__/CustomInput.spec.js delete mode 100644 types/lib/CustomInput.d.ts diff --git a/docs/lib/Components/FormPage.js b/docs/lib/Components/FormPage.js index 352027239..24ad36686 100644 --- a/docs/lib/Components/FormPage.js +++ b/docs/lib/Components/FormPage.js @@ -34,9 +34,6 @@ const InputGridSizingExampleSource = require('!!raw-loader!../examples/InputGrid import LabelHiddenExample from '../examples/LabelHidden'; const LabelHiddenExampleSource = require('!!raw-loader!../examples/LabelHidden'); -import CustomControlsExample from '../examples/CustomControls'; -const CustomControlsExampleSource = require('!!raw-loader!../examples/CustomControls'); - export default class FormPage extends React.Component { render() { return ( @@ -73,25 +70,6 @@ export default class FormPage extends React.Component { cssModule: PropTypes.object, }; -CustomInput.propTypes = { - className: PropTypes.string, - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - type: PropTypes.string.isRequired, // radio, checkbox, select, range, switch, file. - label: PropTypes.string, // used for checkbox and radios - inline: PropTypes.bool, - valid: PropTypes.bool, // applied the is-valid class when true, does nothing when false - invalid: PropTypes.bool, // applied the is-invalid class when true, does nothing when false - bsSize: PropTypes.string, - cssModule: PropTypes.object, - children: PropTypes.oneOfType([PropTypes.node, PropTypes.array, PropTypes.func]), // for type="select" - // innerRef would be referenced to select node or input DOM node, depends on type property - innerRef: PropTypes.oneOfType([ - PropTypes.object, - PropTypes.string, - PropTypes.func, - ]) -}; - Form.propTypes = { children: PropTypes.node, inline: PropTypes.bool, @@ -229,16 +207,6 @@ FormText.propTypes = { {LabelHiddenExampleSource} - - Custom Inputs -
- -
-
-          
-            {CustomControlsExampleSource}
-          
-        
); } diff --git a/docs/lib/examples/CustomControls.js b/docs/lib/examples/CustomControls.js deleted file mode 100644 index 2789865a3..000000000 --- a/docs/lib/examples/CustomControls.js +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react'; -import { CustomInput, Form, FormGroup, Label } from 'reactstrap'; - -const Example = (props) => { - return ( -
- - -
- - - - -
-
- - -
- - - - -
-
- - -
- - - - -
-
- - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- ); -} - -export default Example; diff --git a/src/CustomFileInput.js b/src/CustomFileInput.js deleted file mode 100644 index 6cca67f6f..000000000 --- a/src/CustomFileInput.js +++ /dev/null @@ -1,128 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { mapToCssModules } from './utils'; - -const propTypes = { - className: PropTypes.string, - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - label: PropTypes.node, - valid: PropTypes.bool, - invalid: PropTypes.bool, - bsSize: PropTypes.string, - htmlFor: PropTypes.string, - cssModule: PropTypes.object, - onChange: PropTypes.func, - children: PropTypes.oneOfType([ - PropTypes.node, - PropTypes.array, - PropTypes.func - ]), - innerRef: PropTypes.oneOfType([ - PropTypes.object, - PropTypes.string, - PropTypes.func - ]) -}; - -class CustomFileInput extends React.Component { - constructor(props) { - super(props); - - this.state = { - files: null - }; - - this.onChange = this.onChange.bind(this); - } - - onChange(e) { - let input = e.target; - let { onChange } = this.props; - let files = this.getSelectedFiles(input); - - if (typeof onChange === "function") { - onChange(...arguments); - } - - this.setState({ files }); - } - - getSelectedFiles(input) { - let { multiple } = this.props; - - if (multiple && input.files) { - let files = [].slice.call(input.files); - - return files.map(file => file.name).join(", "); - } - - if (input.value.indexOf("fakepath") !== -1) { - let parts = input.value.split("\\"); - - return parts[parts.length - 1]; - } - - return input.value; - } - - render() { - const { - className, - label, - valid, - invalid, - cssModule, - children, - bsSize, - innerRef, - htmlFor, - type, - onChange, - dataBrowse, - hidden, - ...attributes - } = this.props; - - const customClass = mapToCssModules( - classNames(className, `custom-file`), - cssModule - ); - - const validationClassNames = mapToCssModules( - classNames(invalid && "is-invalid", valid && "is-valid"), - cssModule - ); - - const labelHtmlFor = htmlFor || attributes.id; - const { files } = this.state; - - return ( - - ); - } -} - -CustomFileInput.propTypes = propTypes; - -export default CustomFileInput; diff --git a/src/CustomInput.js b/src/CustomInput.js deleted file mode 100644 index 3e415c7ad..000000000 --- a/src/CustomInput.js +++ /dev/null @@ -1,114 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { mapToCssModules } from './utils'; -import CustomFileInput from './CustomFileInput'; - -const propTypes = { - className: PropTypes.string, - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - type: PropTypes.string.isRequired, - label: PropTypes.node, - inline: PropTypes.bool, - valid: PropTypes.bool, - invalid: PropTypes.bool, - bsSize: PropTypes.string, - htmlFor: PropTypes.string, - cssModule: PropTypes.object, - children: PropTypes.oneOfType([PropTypes.node, PropTypes.array, PropTypes.func]), - innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.string, PropTypes.func]) -}; - -function CustomInput(props) { - const { - className, - label, - inline, - valid, - invalid, - cssModule, - children, - bsSize, - innerRef, - htmlFor, - ...attributes - } = props; - - const type = attributes.type; - - const customClass = mapToCssModules( - classNames(className, `custom-${type}`, bsSize ? `custom-${type}-${bsSize}` : false), - cssModule - ); - - const validationClassNames = mapToCssModules( - classNames(invalid && "is-invalid", valid && "is-valid"), - cssModule - ); - - const labelHtmlFor = htmlFor || attributes.id; - - if (type === "select") { - const { type, ...rest } = attributes; - return ( - - ); - } - - if (type === "file") { - return ; - } - - if (type !== "checkbox" && type !== "radio" && type !== "switch") { - return ( - - ); - } - - const wrapperClasses = classNames( - customClass, - mapToCssModules( - classNames("custom-control", { "custom-control-inline": inline }), - cssModule - ) - ); - - const { hidden, ...rest } = attributes; - return ( - - ); -} - -CustomInput.propTypes = propTypes; - -export default CustomInput; diff --git a/src/__tests__/CustomInput.spec.js b/src/__tests__/CustomInput.spec.js deleted file mode 100644 index 2f92cd5e3..000000000 --- a/src/__tests__/CustomInput.spec.js +++ /dev/null @@ -1,346 +0,0 @@ -import React from 'react'; -import { shallow, mount } from 'enzyme'; -import { CustomInput } from '../'; - -describe('Custom Inputs', () => { - describe('CustomCheckbox', () => { - it('should render an optional label', () => { - const checkbox = mount(); - expect(checkbox.find('label').text()).toBe('Yo!'); - }); - - it('should render children in the outer div', () => { - const checkbox = shallow(); - expect(checkbox.type()).toBe('div'); - }); - - it('should render an input with the type of checkbox', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('type')).toBe('checkbox'); - }); - - it('should pass id to both the input and label nodes', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('id')).toBe('yo'); - expect(checkbox.find('label').prop('htmlFor')).toBe('yo'); - }); - - it('should pass id to both the input and label nodes, with an overriden for on the label node', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('id')).toBe('yo'); - expect(checkbox.find('label').prop('htmlFor')).toBe('custom-for'); - }); - - it('should pass classNames to the outer div', () => { - const checkbox = mount(); - expect(checkbox.find('.custom-control').prop('className').indexOf('yo') > -1).toBeTruthy(); - }); - - it('should add class is-invalid when invalid is true', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('className').indexOf('is-invalid') > -1).toBeTruthy(); - }); - - it('should add class is-valid when valid is true', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('className').indexOf('is-valid') > -1).toBeTruthy(); - }); - - it('should pass all other props to the input node', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('data-testprop')).toBe('yo'); - }); - - it('should reference innerRef to the input node', () => { - const ref = React.createRef(); - mount(); - expect(ref.current).not.toBeNull(); - expect(ref.current).toBeInstanceOf(HTMLInputElement); - }); - }); - - describe('CustomRadio', () => { - it('should render an optional label', () => { - const radio = mount(); - expect(radio.find('label').text()).toBe('Yo!'); - }); - - it('should render children in the outer div', () => { - const radio = shallow(); - expect(radio.type()).toBe('div'); - }); - - it('should render an input with the type of radio', () => { - const radio = mount(); - expect(radio.find('input').prop('type')).toBe('radio'); - }); - - it('should add class is-invalid when invalid is true', () => { - const radio = mount(); - expect(radio.find('input').prop('className').indexOf('is-invalid') > -1).toBeTruthy(); - }); - - it('should add class is-valid when valid is true', () => { - const radio = mount(); - expect(radio.find('input').prop('className').indexOf('is-valid') > -1).toBeTruthy(); - }); - - it('should pass id to both the input and label nodes', () => { - const radio = mount(); - expect(radio.find('input').prop('id')).toBe('yo'); - expect(radio.find('label').prop('htmlFor')).toBe('yo'); - }); - - it('should pass id to both the input and label nodes, with an overriden for on the label node', () => { - const radio = mount(); - expect(radio.find('input').prop('id')).toBe('yo'); - expect(radio.find('label').prop('htmlFor')).toBe('custom-for'); - }); - - it('should pass classNames to the outer div', () => { - const radio = mount(); - expect(radio.find('.custom-control').prop('className').indexOf('yo') > -1).toBeTruthy(); - }); - - it('should pass all other props to the input node', () => { - const radio = mount(); - expect(radio.find('input').prop('data-testprop')).toBe('yo'); - }); - - it('should reference innerRef to the input node', () => { - const ref = React.createRef(); - mount(); - expect(ref.current).not.toBeNull(); - expect(ref.current).toBeInstanceOf(HTMLInputElement); - }); - }); - - describe('CustomSwitch', () => { - it('should render an optional label', () => { - const checkbox = mount(); - expect(checkbox.find('label').text()).toBe('Yo!'); - }); - - it('should render children in the outer div', () => { - const checkbox = shallow(); - expect(checkbox.type()).toBe('div'); - }); - - it('should render an input with the type of checkbox', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('type')).toBe('checkbox'); - }); - - it('should pass id to both the input and label nodes', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('id')).toBe('yo'); - expect(checkbox.find('label').prop('htmlFor')).toBe('yo'); - }); - - it('should pass id to both the input and label nodes, with an overriden for on the label node', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('id')).toBe('yo'); - expect(checkbox.find('label').prop('htmlFor')).toBe('custom-for'); - }); - - it('should pass classNames to the outer div', () => { - const checkbox = mount(); - expect(checkbox.find('.custom-control').prop('className').indexOf('yo') > -1).toBeTruthy(); - }); - - it('should add class is-invalid when invalid is true', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('className').indexOf('is-invalid') > -1).toBeTruthy(); - }); - - it('should add class is-valid when valid is true', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('className').indexOf('is-valid') > -1).toBeTruthy(); - }); - - it('should pass all other props to the input node', () => { - const checkbox = mount(); - expect(checkbox.find('input').prop('data-testprop')).toBe('yo'); - }); - - it('should reference innerRef to the input node', () => { - const ref = React.createRef(); - mount(); - expect(ref.current).not.toBeNull(); - expect(ref.current).toBeInstanceOf(HTMLInputElement); - }); - }); - - describe('CustomSelect', () => { - it('should render children in the outer div', () => { - const select = shallow(); - expect(select.type()).toBe('select'); - }); - - it('should add class is-invalid when invalid is true', () => { - const select = mount(); - expect(select.find('select').prop('className').indexOf('is-invalid') > -1).toBeTruthy(); - }); - - it('should add class is-valid when valid is true', () => { - const select = mount(); - expect(select.find('select').prop('className').indexOf('is-valid') > -1).toBeTruthy(); - }); - - it('should add the size class when bsSize is provided', () => { - const select = mount(); - expect(select.find('select').prop('className').indexOf('custom-select-lg') > -1).toBeTruthy(); - }); - - it('should pass classNames to the outer div', () => { - const select = mount(); - expect(select.find('.custom-select').prop('className').indexOf('yo') > -1).toBeTruthy(); - }); - - it('should pass all other props to the input node', () => { - const select = mount(); - expect(select.find('select').prop('data-testprop')).toBe('yo'); - }); - - it('should remove type prop from the input node', () => { - const select = mount(); - expect(select.find('select').prop('type')).toBeUndefined(); - }); - - it('should reference innerRef to the select node', () => { - const ref = React.createRef(); - mount(); - expect(ref.current).not.toBeNull(); - expect(ref.current).toBeInstanceOf(HTMLSelectElement); - }); - }); - - describe('CustomFile', () => { - it('should render children in the outer div', () => { - const file = mount(); - expect(file.find('.custom-file').first().type()).toBe('div'); - }); - - it('should add class is-invalid when invalid is true', () => { - const file = mount(); - expect(file.find('input').prop('className').indexOf('is-invalid') > -1).toBeTruthy(); - }); - - it('should add class is-valid when valid is true', () => { - const file = mount(); - expect(file.find('input').prop('className').indexOf('is-valid') > -1).toBeTruthy(); - }); - - it('should render an input with the type of file', () => { - const file = mount(); - expect(file.find('input').prop('type')).toBe('file'); - }); - - it('should pass id to both the input and label nodes', () => { - const file = mount(); - expect(file.find('input').prop('id')).toBe('yo'); - expect(file.find('label').prop('htmlFor')).toBe('yo'); - }); - - it('should pass id to both the input and label nodes, with an overriden for on the label node', () => { - const file = mount(); - expect(file.find('input').prop('id')).toBe('yo'); - expect(file.find('label').prop('htmlFor')).toBe('custom-for'); - }); - - it('should pass classNames to the outer div', () => { - const file = mount(); - expect(file.find('.custom-file').prop('className').indexOf('yo') > -1).toBeTruthy(); - }); - - it('should set the label when provided', () => { - const file = mount(); - expect(file.find('label').text()).toBe('yo'); - }); - - it('should pass all other props to the input node', () => { - const file = mount(); - expect(file.find('input').prop('data-testprop')).toBe('yo'); - }); - - it('should reference innerRef to the input node', () => { - const ref = React.createRef(); - mount(); - expect(ref.current).not.toBeNull(); - expect(ref.current).toBeInstanceOf(HTMLInputElement); - }); - - describe('onChange', () => { - it('calls props.onChange if it exists', () => { - const onChange = jest.fn(); - const file = mount(); - - file.find('input').hostNodes().simulate('change'); - expect(onChange).toHaveBeenCalled(); - }); - }); - - it('removes fakepath from file name', () => { - const file = mount(); - - file.find('input').hostNodes().simulate('change', { - target:{ - value:'C:\\fakepath\\test.txt' - } - }); - - expect(file.find('.custom-file-label').text()).toBe('test.txt'); - }); - - it('lists multiple files when supported', () => { - const file = mount(); - - file.find('input').hostNodes().simulate('change', { - target:{ - value:'C:\\fakepath\\file1.txt', - files:[ - {name:"file1.txt"}, - {name:'file2.txt'}, - {name:'file3.txt'}, - ] - } - }) - - expect(file.find('.custom-file-label').text()).toBe('file1.txt, file2.txt, file3.txt'); - }) - }); - - describe('CustomRange', () => { - it('should render children in the outer div', () => { - const range = shallow(); - expect(range.type()).toBe('input'); - }); - - it('should add class is-invalid when invalid is true', () => { - const range = mount(); - expect(range.find('input').prop('className').indexOf('is-invalid') > -1).toBeTruthy(); - }); - - it('should add class is-valid when valid is true', () => { - const range = mount(); - expect(range.find('input').prop('className').indexOf('is-valid') > -1).toBeTruthy(); - }); - - it('should render an input with the type of range', () => { - const range = mount(); - expect(range.find('input').prop('type')).toBe('range'); - }); - - it('should pass all other props to the input node', () => { - const range = mount(); - expect(range.find('input').prop('data-testprop')).toBe('yo'); - }); - - it('should reference innerRef to the input node', () => { - const ref = React.createRef(); - mount(); - expect(ref.current).not.toBeNull(); - expect(ref.current).toBeInstanceOf(HTMLInputElement); - }); - }); -}); diff --git a/src/index.js b/src/index.js index 8e0a63dc4..e9e4416ef 100644 --- a/src/index.js +++ b/src/index.js @@ -41,8 +41,6 @@ export CarouselCaption from './CarouselCaption'; export CardSubtitle from './CardSubtitle'; export CardText from './CardText'; export CardTitle from './CardTitle'; -export CustomFileInput from './CustomFileInput'; -export CustomInput from './CustomInput'; export PopperContent from './PopperContent'; export PopperTargetHelper from './PopperTargetHelper'; export Popover from './Popover'; diff --git a/types/index.d.ts b/types/index.d.ts index bb438a54e..a9a654c09 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -58,8 +58,6 @@ export { default as Collapse } from './lib/Collapse'; export { CollapseProps } from './lib/Collapse'; export { default as Container } from './lib/Container'; export { ContainerProps } from './lib/Container'; -export { default as CustomInput } from './lib/CustomInput'; -export { CustomInputProps } from './lib/CustomInput'; export { default as Dropdown } from './lib/Dropdown'; export { DropdownProps } from './lib/Dropdown'; export { default as DropdownItem } from './lib/DropdownItem'; diff --git a/types/lib/CustomInput.d.ts b/types/lib/CustomInput.d.ts deleted file mode 100644 index dacce6820..000000000 --- a/types/lib/CustomInput.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from 'react'; -import { CSSModule } from './index'; - -type Omit = Pick>; - -export type CustomInputType = - | 'select' - | 'file' - | 'radio' - | 'checkbox' - | 'switch' - | 'range'; - -export interface CustomInputProps - extends Omit, 'id'> { - [key: string]: any; - id: string | number; - type: CustomInputType; - label?: React.ReactNode; - inline?: boolean; - valid?: boolean; - invalid?: boolean; - bsSize?: 'lg' | 'sm'; - htmlFor?: string; - cssModule?: CSSModule; - innerRef?: React.Ref; -} - -declare class CustomInput extends React.Component {} -export default CustomInput; diff --git a/types/lib/index.d.ts b/types/lib/index.d.ts index f19c2fecf..31895b11f 100644 --- a/types/lib/index.d.ts +++ b/types/lib/index.d.ts @@ -62,8 +62,6 @@ export { default as Collapse } from './Collapse'; export { CollapseProps } from './Collapse'; export { default as Container } from './Container'; export { ContainerProps } from './Container'; -export { default as CustomInput } from './CustomInput'; -export { CustomInputProps } from './CustomInput'; export { default as Dropdown } from './Dropdown'; export { DropdownProps } from './Dropdown'; export { default as DropdownItem } from './DropdownItem'; diff --git a/types/reactstrap-tests.tsx b/types/reactstrap-tests.tsx index 4180ac8c3..625e0c53a 100644 --- a/types/reactstrap-tests.tsx +++ b/types/reactstrap-tests.tsx @@ -36,7 +36,6 @@ import { Col, Container, Collapse, - CustomInput, Fade, Form, FormFeedback, @@ -4786,7 +4785,6 @@ import { default as CarouselCaption_ } from './lib/CarouselCaption'; /* tslint:d import { default as Col_ } from './lib/Col'; /* tslint:disable-line: no-relative-import-in-test */ import { default as Collapse_ } from './lib/Collapse'; /* tslint:disable-line: no-relative-import-in-test */ import { default as Container_ } from './lib/Container'; /* tslint:disable-line: no-relative-import-in-test */ -import { default as CustomInput_ } from './lib/CustomInput'; /* tslint:disable-line: no-relative-import-in-test */ import { default as Dropdown_ } from './lib/Dropdown'; /* tslint:disable-line: no-relative-import-in-test */ import { default as DropdownItem_ } from './lib/DropdownItem'; /* tslint:disable-line: no-relative-import-in-test */ import { default as DropdownMenu_ } from './lib/DropdownMenu'; /* tslint:disable-line: no-relative-import-in-test */ @@ -4886,7 +4884,6 @@ function AnyPropExample() { - @@ -4949,219 +4946,6 @@ interface GenericInterface { foobar?: string; } -class Example119 extends React.Component { - render() { - return ( -
- - -
- - - Or this one} - /> - - -
-
- - -
- - - Or this one} - /> - - -
-
- - -
- - - and this one} - inline - /> -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Yo, pick a file!} - /> - - - - - -
- ); - } -} - class Example120 extends React.Component { render() { return ( @@ -5511,11 +5295,6 @@ class Example130 extends React.Component { } } -const CustomInputTestInnerRef = () => { - const ref = React.createRef(); - return ; -}; - const PopoverTestInnerRef = () => { const target = React.createRef(); const container = React.createRef(); @@ -5627,12 +5406,6 @@ const MegaTest = () => { ()} {...htmlProps} /> ()} {...htmlProps} /> ()} {...htmlProps} /> - ()} - {...htmlProps} - type="checkbox" - /> ()} {...htmlProps} /> ()} {...htmlProps} /> ()} {...htmlProps} />