@hyphen/hyphen-components 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/package.json +138 -0
- package/src/components/Alert/Alert.constants.ts +19 -0
- package/src/components/Alert/Alert.mdx +29 -0
- package/src/components/Alert/Alert.module.scss +74 -0
- package/src/components/Alert/Alert.stories.tsx +102 -0
- package/src/components/Alert/Alert.test.tsx +187 -0
- package/src/components/Alert/Alert.tsx +157 -0
- package/src/components/Alert/Alert.types.ts +14 -0
- package/src/components/Badge/Badge.mdx +28 -0
- package/src/components/Badge/Badge.module.scss +155 -0
- package/src/components/Badge/Badge.stories.tsx +52 -0
- package/src/components/Badge/Badge.test.tsx +74 -0
- package/src/components/Badge/Badge.tsx +70 -0
- package/src/components/Box/Box.mdx +259 -0
- package/src/components/Box/Box.module.scss +16 -0
- package/src/components/Box/Box.stories.tsx +1679 -0
- package/src/components/Box/Box.test.tsx +478 -0
- package/src/components/Box/Box.tsx +636 -0
- package/src/components/Button/Button.constants.ts +10 -0
- package/src/components/Button/Button.mdx +71 -0
- package/src/components/Button/Button.module.scss +312 -0
- package/src/components/Button/Button.stories.tsx +117 -0
- package/src/components/Button/Button.test.tsx +460 -0
- package/src/components/Button/Button.tsx +241 -0
- package/src/components/Card/Card.mdx +46 -0
- package/src/components/Card/Card.module.scss +6 -0
- package/src/components/Card/Card.stories.tsx +101 -0
- package/src/components/Card/Card.test.tsx +11 -0
- package/src/components/Card/Card.tsx +61 -0
- package/src/components/Card/components/CardFooter/CardFooter.test.tsx +11 -0
- package/src/components/Card/components/CardFooter/CardFooter.tsx +35 -0
- package/src/components/Card/components/CardHeader/CardHeader.test.tsx +23 -0
- package/src/components/Card/components/CardHeader/CardHeader.tsx +54 -0
- package/src/components/Card/components/CardSection/CardSection.test.tsx +28 -0
- package/src/components/Card/components/CardSection/CardSection.tsx +102 -0
- package/src/components/Card/components/index.ts +3 -0
- package/src/components/CheckboxInput/CheckboxInput.mdx +98 -0
- package/src/components/CheckboxInput/CheckboxInput.stories.tsx +254 -0
- package/src/components/CheckboxInput/CheckboxInput.test.tsx +436 -0
- package/src/components/CheckboxInput/CheckboxInput.tsx +171 -0
- package/src/components/CheckboxInput/components/Checkbox.module.scss +174 -0
- package/src/components/CheckboxInput/components/Checkbox.test.tsx +201 -0
- package/src/components/CheckboxInput/components/Checkbox.tsx +176 -0
- package/src/components/CheckboxInput/components/CheckboxIcon.tsx +71 -0
- package/src/components/DateInput/DateInput.mdx +61 -0
- package/src/components/DateInput/DateInput.stories.tsx +168 -0
- package/src/components/DateInput/DateInput.test.tsx +258 -0
- package/src/components/DateInput/DateInput.tsx +189 -0
- package/src/components/DatePicker/DatePicker.mdx +52 -0
- package/src/components/DatePicker/DatePicker.module.scss +603 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +199 -0
- package/src/components/DatePicker/DatePicker.test.tsx +26 -0
- package/src/components/DatePicker/DatePicker.tsx +138 -0
- package/src/components/Details/Details.mdx +30 -0
- package/src/components/Details/Details.module.scss +32 -0
- package/src/components/Details/Details.stories.tsx +38 -0
- package/src/components/Details/Details.test.tsx +189 -0
- package/src/components/Details/Details.tsx +51 -0
- package/src/components/Details/DetailsSummary.tsx +65 -0
- package/src/components/Drawer/Drawer.mdx +117 -0
- package/src/components/Drawer/Drawer.module.scss +96 -0
- package/src/components/Drawer/Drawer.stories.tsx +380 -0
- package/src/components/Drawer/Drawer.test.tsx +90 -0
- package/src/components/Drawer/Drawer.tsx +249 -0
- package/src/components/FormControl/FormControl.tsx +78 -0
- package/src/components/FormLabel/FormLabel.mdx +24 -0
- package/src/components/FormLabel/FormLabel.module.scss +19 -0
- package/src/components/FormLabel/FormLabel.stories.tsx +20 -0
- package/src/components/FormLabel/FormLabel.test.tsx +35 -0
- package/src/components/FormLabel/FormLabel.tsx +96 -0
- package/src/components/Formik/Formik.mdx +10 -0
- package/src/components/Formik/Formik.stories.tsx +307 -0
- package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.test.tsx +172 -0
- package/src/components/Formik/FormikCheckboxInput/FormikCheckboxInput.tsx +41 -0
- package/src/components/Formik/FormikRadioGroup/FormikRadioGroup.test.tsx +205 -0
- package/src/components/Formik/FormikRadioGroup/FormikRadioGroup.tsx +37 -0
- package/src/components/Formik/FormikSelectInput/FormikSelectInput.test.tsx +210 -0
- package/src/components/Formik/FormikSelectInput/FormikSelectInput.tsx +41 -0
- package/src/components/Formik/FormikSelectInputInset/FormikSelectInputInset.test.tsx +153 -0
- package/src/components/Formik/FormikSelectInputInset/FormikSelectInputInset.tsx +44 -0
- package/src/components/Formik/FormikSelectInputNative/FormikSelectInputNative.test.tsx +161 -0
- package/src/components/Formik/FormikSelectInputNative/FormikSelectInputNative.tsx +46 -0
- package/src/components/Formik/FormikTextInput/FormikTextInput.test.tsx +176 -0
- package/src/components/Formik/FormikTextInput/FormikTextInput.tsx +38 -0
- package/src/components/Formik/FormikTextInputInset/FormikTextInputInset.test.tsx +170 -0
- package/src/components/Formik/FormikTextInputInset/FormikTextInputInset.tsx +42 -0
- package/src/components/Formik/FormikTextareaInput/FormikTextareaInput.test.tsx +186 -0
- package/src/components/Formik/FormikTextareaInput/FormikTextareaInput.tsx +42 -0
- package/src/components/Formik/FormikTextareaInputInset/FormikTextareaInputInset.test.tsx +179 -0
- package/src/components/Formik/FormikTextareaInputInset/FormikTextareaInputInset.tsx +42 -0
- package/src/components/Formik/FormikTimePicker/FormikTimePicker.test.tsx +224 -0
- package/src/components/Formik/FormikTimePicker/FormikTimePicker.tsx +37 -0
- package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.test.tsx +175 -0
- package/src/components/Formik/FormikTimePickerNative/FormikTimePickerNative.tsx +38 -0
- package/src/components/Formik/FormikToggle/FormikToggle.test.tsx +172 -0
- package/src/components/Formik/FormikToggle/FormikToggle.tsx +38 -0
- package/src/components/Heading/Heading.constants.ts +19 -0
- package/src/components/Heading/Heading.mdx +35 -0
- package/src/components/Heading/Heading.module.scss +5 -0
- package/src/components/Heading/Heading.stories.tsx +90 -0
- package/src/components/Heading/Heading.test.tsx +67 -0
- package/src/components/Heading/Heading.tsx +67 -0
- package/src/components/HelpText/HelpText.module.scss +14 -0
- package/src/components/HelpText/HelpText.tsx +33 -0
- package/src/components/Icon/Icon.mdx +40 -0
- package/src/components/Icon/Icon.stories.tsx +72 -0
- package/src/components/Icon/Icon.test.tsx +30 -0
- package/src/components/Icon/Icon.tsx +61 -0
- package/src/components/InputValidationMessage/InputValidationMessage.module.scss +3 -0
- package/src/components/InputValidationMessage/InputValidationMessage.tsx +27 -0
- package/src/components/Modal/Modal.mdx +60 -0
- package/src/components/Modal/Modal.module.scss +135 -0
- package/src/components/Modal/Modal.stories.tsx +194 -0
- package/src/components/Modal/Modal.test.tsx +81 -0
- package/src/components/Modal/Modal.tsx +174 -0
- package/src/components/Modal/components/ModalBody/ModalBody.test.tsx +20 -0
- package/src/components/Modal/components/ModalBody/ModalBody.tsx +24 -0
- package/src/components/Modal/components/ModalFooter/ModalFooter.test.tsx +32 -0
- package/src/components/Modal/components/ModalFooter/ModalFooter.tsx +37 -0
- package/src/components/Modal/components/ModalHeader/ModalHeader.test.tsx +29 -0
- package/src/components/Modal/components/ModalHeader/ModalHeader.tsx +58 -0
- package/src/components/Modal/components/index.ts +5 -0
- package/src/components/Pagination/Pagination.mdx +26 -0
- package/src/components/Pagination/Pagination.stories.tsx +55 -0
- package/src/components/Pagination/Pagination.test.tsx +225 -0
- package/src/components/Pagination/Pagination.tsx +162 -0
- package/src/components/Pagination/Pagination.utilities.test.ts +133 -0
- package/src/components/Pagination/Pagination.utilities.ts +101 -0
- package/src/components/Popover/Popover.mdx +104 -0
- package/src/components/Popover/Popover.module.scss +74 -0
- package/src/components/Popover/Popover.stories.tsx +471 -0
- package/src/components/Popover/Popover.test.tsx +128 -0
- package/src/components/Popover/Popover.tsx +277 -0
- package/src/components/RadioGroup/RadioGroup.mdx +81 -0
- package/src/components/RadioGroup/RadioGroup.module.scss +23 -0
- package/src/components/RadioGroup/RadioGroup.stories.tsx +375 -0
- package/src/components/RadioGroup/RadioGroup.test.tsx +282 -0
- package/src/components/RadioGroup/RadioGroup.tsx +145 -0
- package/src/components/RadioGroup/RadioInput/RadioInput.module.scss +114 -0
- package/src/components/RadioGroup/RadioInput/RadioInput.test.tsx +156 -0
- package/src/components/RadioGroup/RadioInput/RadioInput.tsx +148 -0
- package/src/components/RadioGroup/RadioInput/RadioInputIcon.tsx +59 -0
- package/src/components/ResponsiveProvider/ResponsiveProvider.mdx +36 -0
- package/src/components/ResponsiveProvider/ResponsiveProvider.stories.tsx +54 -0
- package/src/components/ResponsiveProvider/ResponsiveProvider.test.tsx +70 -0
- package/src/components/ResponsiveProvider/ResponsiveProvider.tsx +73 -0
- package/src/components/SelectInput/SelectInput.mdx +115 -0
- package/src/components/SelectInput/SelectInput.module.scss +357 -0
- package/src/components/SelectInput/SelectInput.stories.tsx +373 -0
- package/src/components/SelectInput/SelectInput.test.tsx +403 -0
- package/src/components/SelectInput/SelectInput.tsx +245 -0
- package/src/components/SelectInputInset/SelectInputInset.mdx +56 -0
- package/src/components/SelectInputInset/SelectInputInset.module.scss +397 -0
- package/src/components/SelectInputInset/SelectInputInset.stories.tsx +189 -0
- package/src/components/SelectInputInset/SelectInputInset.test.tsx +305 -0
- package/src/components/SelectInputInset/SelectInputInset.tsx +235 -0
- package/src/components/SelectInputNative/SelectInputNative.mdx +87 -0
- package/src/components/SelectInputNative/SelectInputNative.module.scss +356 -0
- package/src/components/SelectInputNative/SelectInputNative.stories.tsx +282 -0
- package/src/components/SelectInputNative/SelectInputNative.test.tsx +341 -0
- package/src/components/SelectInputNative/SelectInputNative.tsx +121 -0
- package/src/components/Spinner/Spinner.mdx +29 -0
- package/src/components/Spinner/Spinner.module.scss +16 -0
- package/src/components/Spinner/Spinner.stories.tsx +48 -0
- package/src/components/Spinner/Spinner.test.tsx +47 -0
- package/src/components/Spinner/Spinner.tsx +116 -0
- package/src/components/Table/Table.mdx +216 -0
- package/src/components/Table/Table.module.scss +61 -0
- package/src/components/Table/Table.stories.tsx +884 -0
- package/src/components/Table/Table.test.tsx +437 -0
- package/src/components/Table/Table.tsx +171 -0
- package/src/components/Table/TableBody/TableBody.module.scss +19 -0
- package/src/components/Table/TableBody/TableBody.test.tsx +38 -0
- package/src/components/Table/TableBody/TableBody.tsx +96 -0
- package/src/components/Table/TableBody/TableBodyCell/TableBodyCell.module.scss +47 -0
- package/src/components/Table/TableBody/TableBodyCell/TableBodyCell.test.tsx +81 -0
- package/src/components/Table/TableBody/TableBodyCell/TableBodyCell.tsx +94 -0
- package/src/components/Table/TableHead/TableHead.test.tsx +20 -0
- package/src/components/Table/TableHead/TableHead.tsx +78 -0
- package/src/components/Table/TableHead/TableHeaderCell/TableHeaderCell.module.scss +72 -0
- package/src/components/Table/TableHead/TableHeaderCell/TableHeaderCell.test.tsx +187 -0
- package/src/components/Table/TableHead/TableHeaderCell/TableHeaderCell.tsx +192 -0
- package/src/components/Table/common/TableRow/TableRow.module.scss +5 -0
- package/src/components/Table/common/TableRow/TableRow.test.tsx +52 -0
- package/src/components/Table/common/TableRow/TableRow.tsx +155 -0
- package/src/components/TextInput/TextInput.mdx +96 -0
- package/src/components/TextInput/TextInput.module.scss +405 -0
- package/src/components/TextInput/TextInput.stories.tsx +268 -0
- package/src/components/TextInput/TextInput.test.tsx +231 -0
- package/src/components/TextInput/TextInput.tsx +263 -0
- package/src/components/TextInputInset/TextInputInset.mdx +62 -0
- package/src/components/TextInputInset/TextInputInset.module.scss +418 -0
- package/src/components/TextInputInset/TextInputInset.stories.tsx +213 -0
- package/src/components/TextInputInset/TextInputInset.test.tsx +222 -0
- package/src/components/TextInputInset/TextInputInset.tsx +261 -0
- package/src/components/TextareaInput/TextareaInput.mdx +117 -0
- package/src/components/TextareaInput/TextareaInput.module.scss +275 -0
- package/src/components/TextareaInput/TextareaInput.stories.tsx +293 -0
- package/src/components/TextareaInput/TextareaInput.test.tsx +195 -0
- package/src/components/TextareaInput/TextareaInput.tsx +182 -0
- package/src/components/TextareaInputInset/TextareaInputInset.mdx +55 -0
- package/src/components/TextareaInputInset/TextareaInputInset.module.scss +337 -0
- package/src/components/TextareaInputInset/TextareaInputInset.stories.tsx +160 -0
- package/src/components/TextareaInputInset/TextareaInputInset.test.tsx +199 -0
- package/src/components/TextareaInputInset/TextareaInputInset.tsx +213 -0
- package/src/components/ThemeProvider/ThemeProvider.mdx +11 -0
- package/src/components/ThemeProvider/ThemeProvider.stories.tsx +56 -0
- package/src/components/ThemeProvider/ThemeProvider.tsx +75 -0
- package/src/components/TimePicker/TimePicker.mdx +75 -0
- package/src/components/TimePicker/TimePicker.stories.tsx +149 -0
- package/src/components/TimePicker/TimePicker.test.tsx +97 -0
- package/src/components/TimePicker/TimePicker.tsx +83 -0
- package/src/components/TimePickerNative/TimePickerNative.mdx +67 -0
- package/src/components/TimePickerNative/TimePickerNative.stories.tsx +151 -0
- package/src/components/TimePickerNative/TimePickerNative.test.tsx +117 -0
- package/src/components/TimePickerNative/TimePickerNative.tsx +93 -0
- package/src/components/Toast/Toast.mdx +134 -0
- package/src/components/Toast/Toast.store.ts +280 -0
- package/src/components/Toast/Toast.stories.tsx +283 -0
- package/src/components/Toast/Toast.test.tsx +784 -0
- package/src/components/Toast/Toast.types.ts +98 -0
- package/src/components/Toast/ToastContainer.tsx +170 -0
- package/src/components/Toast/ToastNotification.module.scss +63 -0
- package/src/components/Toast/ToastNotification.tsx +176 -0
- package/src/components/Toast/index.ts +4 -0
- package/src/components/Toast/toast.ts +102 -0
- package/src/components/Toast/useToasts.ts +102 -0
- package/src/components/Toggle/Toggle.mdx +51 -0
- package/src/components/Toggle/Toggle.module.scss +294 -0
- package/src/components/Toggle/Toggle.stories.tsx +128 -0
- package/src/components/Toggle/Toggle.test.tsx +308 -0
- package/src/components/Toggle/Toggle.tsx +184 -0
- package/src/constants/keyCodes.ts +2 -0
- package/src/docs/Brands.mdx +153 -0
- package/src/docs/Colors.mdx +158 -0
- package/src/docs/DesignTokens.mdx +415 -0
- package/src/docs/GetStarted.mdx +47 -0
- package/src/docs/intro.mdx +12 -0
- package/src/fonts/AvenirBold.otf +0 -0
- package/src/fonts/AvenirBold.woff +0 -0
- package/src/fonts/AvenirBold.woff2 +0 -0
- package/src/fonts/AvenirLight.otf +0 -0
- package/src/fonts/AvenirLight.woff +0 -0
- package/src/fonts/AvenirLight.woff2 +0 -0
- package/src/fonts/AvenirRegular.otf +0 -0
- package/src/fonts/AvenirRegular.woff +0 -0
- package/src/fonts/AvenirRegular.woff2 +0 -0
- package/src/fonts/Geist-Bold.otf +0 -0
- package/src/fonts/Geist-Bold.woff +0 -0
- package/src/fonts/Geist-Bold.woff2 +0 -0
- package/src/fonts/Geist-Medium.otf +0 -0
- package/src/fonts/Geist-Medium.woff +0 -0
- package/src/fonts/Geist-Medium.woff2 +0 -0
- package/src/fonts/Geist-Regular.otf +0 -0
- package/src/fonts/Geist-Regular.woff +0 -0
- package/src/fonts/Geist-Regular.woff2 +0 -0
- package/src/fonts/Geist-SemiBold.otf +0 -0
- package/src/fonts/Geist-SemiBold.woff +0 -0
- package/src/fonts/Geist-SemiBold.woff2 +0 -0
- package/src/fonts/GeistMono-Regular.otf +0 -0
- package/src/fonts/GeistMono-Regular.woff +0 -0
- package/src/fonts/GeistMono-Regular.woff2 +0 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useBreakpoint/useBreakpoint.mdx +26 -0
- package/src/hooks/useBreakpoint/useBreakpoint.stories.tsx +30 -0
- package/src/hooks/useBreakpoint/useBreakpoint.test.tsx +19 -0
- package/src/hooks/useBreakpoint/useBreakpoint.ts +50 -0
- package/src/hooks/useIsomorphicLayoutEffect/useIsomorphicLayouEffect.ts +5 -0
- package/src/hooks/useOpenClose/useOpenClose.mdx +15 -0
- package/src/hooks/useOpenClose/useOpenClose.stories.tsx +41 -0
- package/src/hooks/useOpenClose/useOpenClose.test.tsx +119 -0
- package/src/hooks/useOpenClose/useOpenClose.tsx +95 -0
- package/src/hooks/useWindowSize/useWindowSize.mdx +25 -0
- package/src/hooks/useWindowSize/useWindowSize.stories.tsx +35 -0
- package/src/hooks/useWindowSize/useWindowSize.ts +24 -0
- package/src/index.ts +48 -0
- package/src/lib/cssShorthandToClasses.test.ts +149 -0
- package/src/lib/cssShorthandToClasses.ts +133 -0
- package/src/lib/doesStringIncludeCssUnit.ts +6 -0
- package/src/lib/generateResponsiveClasses.test.ts +24 -0
- package/src/lib/generateResponsiveClasses.ts +30 -0
- package/src/lib/getAutoCompleteValue.test.ts +27 -0
- package/src/lib/getAutoCompleteValue.ts +12 -0
- package/src/lib/getColumnKeys.ts +27 -0
- package/src/lib/getDimensionCss.test.ts +148 -0
- package/src/lib/getDimensionCss.ts +73 -0
- package/src/lib/getElementType.test.tsx +42 -0
- package/src/lib/getElementType.ts +42 -0
- package/src/lib/getFlexCss.test.ts +122 -0
- package/src/lib/getFlexCss.ts +67 -0
- package/src/lib/index.ts +15 -0
- package/src/lib/isFunction.ts +6 -0
- package/src/lib/mergeRefs.ts +15 -0
- package/src/lib/prefersReducedMotion.ts +12 -0
- package/src/lib/react-children-utilities/filter.ts +12 -0
- package/src/lib/react-children-utilities/index.ts +1 -0
- package/src/lib/reactRouterClickHandler.ts +37 -0
- package/src/lib/resolveValue.ts +7 -0
- package/src/lib/tokens.ts +139 -0
- package/src/modes.ts +8 -0
- package/src/styles/animation.scss +152 -0
- package/src/styles/cursor.scss +43 -0
- package/src/styles/display.scss +119 -0
- package/src/styles/flex.scss +453 -0
- package/src/styles/fonts.scss +44 -0
- package/src/styles/globals/utilities.scss +4 -0
- package/src/styles/mixins.scss +14 -0
- package/src/styles/overflow.scss +41 -0
- package/src/styles/position.scss +45 -0
- package/src/styles/reset.scss +108 -0
- package/src/styles/text-align.scss +21 -0
- package/src/styles/utilities.scss +9 -0
- package/src/styles/variables/forms.scss +71 -0
- package/src/styles/variables/index.scss +3 -0
- package/src/styles/white-space.scss +21 -0
- package/src/types/index.ts +201 -0
- package/src/types/lib.types.ts +3 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent, screen } from '@testing-library/react';
|
|
3
|
+
import { BreakpointSize } from '../../types';
|
|
4
|
+
import { SelectInputInset } from './SelectInputInset';
|
|
5
|
+
|
|
6
|
+
const selectOptions = [
|
|
7
|
+
{ value: 'chocolate', label: 'Chocolate' },
|
|
8
|
+
{ value: 'strawberry', label: 'Strawberry' },
|
|
9
|
+
{ value: 'vanilla', label: 'Vanilla' },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
describe('SelectInputInset', () => {
|
|
13
|
+
describe('Callback Handling', () => {
|
|
14
|
+
test('it fires onChange callback on change', async () => {
|
|
15
|
+
const mockedHandleChange = jest.fn();
|
|
16
|
+
|
|
17
|
+
const { getByLabelText } = render(
|
|
18
|
+
<SelectInputInset
|
|
19
|
+
id="testId"
|
|
20
|
+
onChange={mockedHandleChange}
|
|
21
|
+
placeholder="Test Placeholder"
|
|
22
|
+
label="onchange test"
|
|
23
|
+
options={selectOptions}
|
|
24
|
+
value={null}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
await fireEvent.change(getByLabelText('onchange test'));
|
|
29
|
+
|
|
30
|
+
expect(mockedHandleChange).toBeCalledTimes(1);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('it fires onFocus callback on focus', () => {
|
|
34
|
+
const mockedHandleChange = jest.fn();
|
|
35
|
+
const mockedHandleFocus = jest.fn();
|
|
36
|
+
|
|
37
|
+
render(
|
|
38
|
+
<SelectInputInset
|
|
39
|
+
id="testId"
|
|
40
|
+
onChange={mockedHandleChange}
|
|
41
|
+
onFocus={mockedHandleFocus}
|
|
42
|
+
placeholder="Test Placeholder"
|
|
43
|
+
options={selectOptions}
|
|
44
|
+
value={null}
|
|
45
|
+
label="onfocus test"
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
const select = screen.getByLabelText('onfocus test');
|
|
49
|
+
fireEvent.focus(select);
|
|
50
|
+
|
|
51
|
+
expect(mockedHandleFocus).toBeCalledTimes(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('it fires onBlur callback on blur', () => {
|
|
55
|
+
const mockedHandleChange = jest.fn();
|
|
56
|
+
const mockedHandleBlur = jest.fn();
|
|
57
|
+
|
|
58
|
+
render(
|
|
59
|
+
<SelectInputInset
|
|
60
|
+
id="testId"
|
|
61
|
+
onChange={mockedHandleChange}
|
|
62
|
+
onBlur={mockedHandleBlur}
|
|
63
|
+
placeholder="Test Placeholder"
|
|
64
|
+
options={selectOptions}
|
|
65
|
+
value={null}
|
|
66
|
+
label="onblur test"
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const select = screen.getByLabelText('onblur test');
|
|
71
|
+
fireEvent.blur(select);
|
|
72
|
+
|
|
73
|
+
expect(mockedHandleBlur).toBeCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('onClear', () => {
|
|
78
|
+
test('onClear prop renders clear icon when input has value', () => {
|
|
79
|
+
const mockedHandleChange = jest.fn();
|
|
80
|
+
render(
|
|
81
|
+
<SelectInputInset
|
|
82
|
+
id="testId"
|
|
83
|
+
onChange={mockedHandleChange}
|
|
84
|
+
options={selectOptions}
|
|
85
|
+
value="chocolate"
|
|
86
|
+
label="onClear test"
|
|
87
|
+
onClear={() => null}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
const clearButton = screen.getByTestId('text-input-clear-button');
|
|
91
|
+
expect(clearButton).toBeInTheDocument();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('onClear event fires callback function', () => {
|
|
95
|
+
const mockedHandleChange = jest.fn();
|
|
96
|
+
const mockedHandleClear = jest.fn(() => null);
|
|
97
|
+
|
|
98
|
+
render(
|
|
99
|
+
<SelectInputInset
|
|
100
|
+
id="testId"
|
|
101
|
+
onChange={mockedHandleChange}
|
|
102
|
+
options={selectOptions}
|
|
103
|
+
value="chocolate"
|
|
104
|
+
label="onClear test"
|
|
105
|
+
onClear={mockedHandleClear}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
const clearButton = screen.getByTestId('text-input-clear-button');
|
|
109
|
+
expect(clearButton).toBeInTheDocument();
|
|
110
|
+
|
|
111
|
+
fireEvent.click(clearButton);
|
|
112
|
+
expect(mockedHandleClear).toHaveBeenCalledTimes(1);
|
|
113
|
+
fireEvent.keyUp(clearButton, { keyCode: 13 });
|
|
114
|
+
expect(mockedHandleClear).toHaveBeenCalledTimes(2);
|
|
115
|
+
fireEvent.keyUp(clearButton, { keyCode: 99 });
|
|
116
|
+
expect(mockedHandleClear).toHaveBeenCalledTimes(2);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('States', () => {
|
|
121
|
+
describe('With a label, and no custom placeholder', () => {
|
|
122
|
+
test('it renders input with a label, and with a default placeholder', () => {
|
|
123
|
+
const mockedHandleChange = jest.fn();
|
|
124
|
+
|
|
125
|
+
render(
|
|
126
|
+
<SelectInputInset
|
|
127
|
+
id="testId"
|
|
128
|
+
onChange={mockedHandleChange}
|
|
129
|
+
label="Select Label"
|
|
130
|
+
options={selectOptions}
|
|
131
|
+
value={selectOptions[1].value}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(screen.getByLabelText('Select Label')).toBeInTheDocument();
|
|
136
|
+
expect(screen.getByText('Select...')).toBeInTheDocument();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('assigns the "aria-labelledby" attribute and renders label correct id, when a label is provided', () => {
|
|
140
|
+
render(
|
|
141
|
+
<SelectInputInset
|
|
142
|
+
id="testInput"
|
|
143
|
+
label="test label"
|
|
144
|
+
options={selectOptions}
|
|
145
|
+
value={null}
|
|
146
|
+
onChange={() => null}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
const inputElement = screen.getByLabelText('test label');
|
|
150
|
+
expect(inputElement).toHaveAttribute(
|
|
151
|
+
'aria-labelledby',
|
|
152
|
+
'testInputLabel'
|
|
153
|
+
);
|
|
154
|
+
expect(document.getElementById('testInputLabel')).toBeInTheDocument();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('Is Required', () => {
|
|
159
|
+
test('it sets the required and aria-required properties on the input', () => {
|
|
160
|
+
const mockedHandleChange = jest.fn();
|
|
161
|
+
|
|
162
|
+
render(
|
|
163
|
+
<SelectInputInset
|
|
164
|
+
id="testId"
|
|
165
|
+
onChange={mockedHandleChange}
|
|
166
|
+
label="Required Select"
|
|
167
|
+
options={selectOptions}
|
|
168
|
+
isRequired
|
|
169
|
+
value={selectOptions[0].value}
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const inputElement = screen.getByLabelText('Required Select');
|
|
174
|
+
expect(inputElement).toHaveAttribute('aria-required', 'true');
|
|
175
|
+
expect(inputElement).toHaveAttribute('required');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('it renders an asterisk in the label by default', () => {
|
|
179
|
+
const mockedHandleChange = jest.fn();
|
|
180
|
+
|
|
181
|
+
render(
|
|
182
|
+
<SelectInputInset
|
|
183
|
+
id="testId"
|
|
184
|
+
onChange={mockedHandleChange}
|
|
185
|
+
label="Select Label"
|
|
186
|
+
options={selectOptions}
|
|
187
|
+
isRequired
|
|
188
|
+
value={selectOptions[0].value}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
expect(screen.getByText('*')).toBeInTheDocument();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('Is Disabled', () => {
|
|
197
|
+
test('it disables the input', () => {
|
|
198
|
+
const mockedHandleChange = jest.fn();
|
|
199
|
+
|
|
200
|
+
render(
|
|
201
|
+
<SelectInputInset
|
|
202
|
+
id="testId"
|
|
203
|
+
onChange={mockedHandleChange}
|
|
204
|
+
label="disabled test"
|
|
205
|
+
options={selectOptions}
|
|
206
|
+
isDisabled
|
|
207
|
+
value={null}
|
|
208
|
+
/>
|
|
209
|
+
);
|
|
210
|
+
const select = screen.getByLabelText('disabled test');
|
|
211
|
+
expect(select).toBeDisabled();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('Is Invalid, with a helpful message', () => {
|
|
216
|
+
test('it renders the helpful message', () => {
|
|
217
|
+
const mockedHandleChange = jest.fn();
|
|
218
|
+
|
|
219
|
+
render(
|
|
220
|
+
<SelectInputInset
|
|
221
|
+
id="testId"
|
|
222
|
+
onChange={mockedHandleChange}
|
|
223
|
+
label="Select Label"
|
|
224
|
+
options={selectOptions}
|
|
225
|
+
error="Helpful message"
|
|
226
|
+
value={null}
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
expect(screen.getByText('Helpful message')).toBeInTheDocument();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
describe('Sizes', () => {
|
|
236
|
+
const mockedHandleChange = jest.fn();
|
|
237
|
+
const sizes = ['md', 'lg'] as ('md' | 'lg')[];
|
|
238
|
+
|
|
239
|
+
const breakpoints: BreakpointSize[] = ['tablet', 'desktop', 'hd'];
|
|
240
|
+
|
|
241
|
+
sizes.forEach((size) => {
|
|
242
|
+
test(`it has a ${size} class applied to it`, () => {
|
|
243
|
+
render(
|
|
244
|
+
<SelectInputInset
|
|
245
|
+
id="testId"
|
|
246
|
+
onChange={mockedHandleChange}
|
|
247
|
+
options={selectOptions}
|
|
248
|
+
value={selectOptions[0].value}
|
|
249
|
+
size={size}
|
|
250
|
+
label="size test"
|
|
251
|
+
/>
|
|
252
|
+
);
|
|
253
|
+
const select = screen.getByLabelText('size test');
|
|
254
|
+
const selectParent = select.closest('div');
|
|
255
|
+
expect(selectParent?.getAttribute('class')).toContain(size);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
breakpoints.forEach((breakpoint) => {
|
|
259
|
+
test(`it applies responsive classes for breakpoint: ${breakpoint} and size: ${size}`, () => {
|
|
260
|
+
render(
|
|
261
|
+
<SelectInputInset
|
|
262
|
+
id="testId"
|
|
263
|
+
onChange={mockedHandleChange}
|
|
264
|
+
options={selectOptions}
|
|
265
|
+
value={selectOptions[0].value}
|
|
266
|
+
size={{ [breakpoint]: size }}
|
|
267
|
+
label="size test"
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
const select = screen.getByLabelText('size test');
|
|
271
|
+
const selectParent = select.closest('div');
|
|
272
|
+
|
|
273
|
+
expect(selectParent?.getAttribute('class')).toContain(
|
|
274
|
+
`size-${size}-${breakpoint}`
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test('It applies responsive classes when multiple are applied', () => {
|
|
281
|
+
render(
|
|
282
|
+
<SelectInputInset
|
|
283
|
+
id="testId"
|
|
284
|
+
onChange={mockedHandleChange}
|
|
285
|
+
options={selectOptions}
|
|
286
|
+
value={selectOptions[0].value}
|
|
287
|
+
size={{
|
|
288
|
+
base: 'md',
|
|
289
|
+
tablet: 'md',
|
|
290
|
+
desktop: 'lg',
|
|
291
|
+
hd: 'lg',
|
|
292
|
+
}}
|
|
293
|
+
label="size test"
|
|
294
|
+
/>
|
|
295
|
+
);
|
|
296
|
+
const select = screen.getByLabelText('size test');
|
|
297
|
+
const selectParent = select.closest('div');
|
|
298
|
+
|
|
299
|
+
expect(selectParent?.getAttribute('class')).toContain('size-md');
|
|
300
|
+
expect(selectParent?.getAttribute('class')).toContain('size-md-tablet');
|
|
301
|
+
expect(selectParent?.getAttribute('class')).toContain('size-lg-desktop');
|
|
302
|
+
expect(selectParent?.getAttribute('class')).toContain('size-lg-hd');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
ChangeEvent,
|
|
3
|
+
forwardRef,
|
|
4
|
+
MouseEvent,
|
|
5
|
+
KeyboardEvent,
|
|
6
|
+
FocusEvent,
|
|
7
|
+
ForwardRefExoticComponent,
|
|
8
|
+
ReactNode,
|
|
9
|
+
HTMLProps,
|
|
10
|
+
} from 'react';
|
|
11
|
+
import classNames from 'classnames';
|
|
12
|
+
import { ResponsiveProp } from '../../types';
|
|
13
|
+
import { generateResponsiveClasses } from '../../lib/generateResponsiveClasses';
|
|
14
|
+
|
|
15
|
+
import { Box, BoxProps } from '../Box/Box';
|
|
16
|
+
import { HelpText } from '../HelpText/HelpText';
|
|
17
|
+
import { Icon } from '../Icon/Icon';
|
|
18
|
+
import { getAutoCompleteValue } from '../../lib/getAutoCompleteValue';
|
|
19
|
+
import styles from './SelectInputInset.module.scss';
|
|
20
|
+
import { InputValidationMessage } from '../InputValidationMessage/InputValidationMessage';
|
|
21
|
+
|
|
22
|
+
export type SelectInputInsetSize = 'md' | 'lg';
|
|
23
|
+
export interface SelectInputInsetProps {
|
|
24
|
+
/**
|
|
25
|
+
* The input's id attribute. Used to programmatically tie the input with its label.
|
|
26
|
+
*/
|
|
27
|
+
id: string;
|
|
28
|
+
/**
|
|
29
|
+
* Custom content to be displayed above the input. If the label is hidden, will be used to set aria-label attribute.
|
|
30
|
+
*/
|
|
31
|
+
label: string;
|
|
32
|
+
/**
|
|
33
|
+
* List of options for the select input.
|
|
34
|
+
*/
|
|
35
|
+
options: { value: string | number; label: string | number }[];
|
|
36
|
+
/**
|
|
37
|
+
* Callback function to call on change event.
|
|
38
|
+
*/
|
|
39
|
+
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
40
|
+
/**
|
|
41
|
+
* Value of selected option. Should match the value key in the option object.
|
|
42
|
+
*/
|
|
43
|
+
value: string | number | null;
|
|
44
|
+
/**
|
|
45
|
+
* Automatically focus the input when the page is loaded.
|
|
46
|
+
*/
|
|
47
|
+
autoFocus?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Custom class to be added to standard input classes.
|
|
50
|
+
*/
|
|
51
|
+
className?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Mark the input field as invalid and display a validation message.
|
|
54
|
+
* Pass a string or node to render a validation message below the input.
|
|
55
|
+
*/
|
|
56
|
+
error?: ReactNode;
|
|
57
|
+
/**
|
|
58
|
+
* Additional clarifying text to help describe the input
|
|
59
|
+
*/
|
|
60
|
+
helpText?: ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Props passed directly to the input element of the component
|
|
63
|
+
*/
|
|
64
|
+
inputProps?: BoxProps & HTMLProps<HTMLInputElement>;
|
|
65
|
+
/**
|
|
66
|
+
* The input's disabled attribute
|
|
67
|
+
*/
|
|
68
|
+
isDisabled?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The required and aria-required attributes on the input
|
|
71
|
+
*/
|
|
72
|
+
isRequired?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The input's 'name' attribute.
|
|
75
|
+
*/
|
|
76
|
+
name?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Callback function to call on blur event.
|
|
79
|
+
*/
|
|
80
|
+
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Callback function to call when input us cleared. When this is passed,
|
|
83
|
+
* the input will display an icon on the right side, for triggering this callback.
|
|
84
|
+
*/
|
|
85
|
+
onClear?: (
|
|
86
|
+
event: MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLButtonElement>
|
|
87
|
+
) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Callback function to call on focus event.
|
|
90
|
+
*/
|
|
91
|
+
onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
|
|
92
|
+
/**
|
|
93
|
+
* The input placeholder attribute.
|
|
94
|
+
*/
|
|
95
|
+
placeholder?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Visual indicator that the field is required, that gets appended to the label
|
|
98
|
+
*/
|
|
99
|
+
requiredIndicator?: ReactNode;
|
|
100
|
+
/**
|
|
101
|
+
* The size of the text input.
|
|
102
|
+
*/
|
|
103
|
+
size?: SelectInputInsetSize | ResponsiveProp<SelectInputInsetSize>;
|
|
104
|
+
/**
|
|
105
|
+
* Additional props to be spread to rendered element
|
|
106
|
+
*/
|
|
107
|
+
[x: string]: any; // eslint-disable-line
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const SelectInputInset: ForwardRefExoticComponent<SelectInputInsetProps> =
|
|
111
|
+
forwardRef<HTMLDivElement, SelectInputInsetProps>(
|
|
112
|
+
(
|
|
113
|
+
{
|
|
114
|
+
id,
|
|
115
|
+
label,
|
|
116
|
+
onChange,
|
|
117
|
+
value,
|
|
118
|
+
autoComplete = false,
|
|
119
|
+
autoFocus = false,
|
|
120
|
+
error = false,
|
|
121
|
+
helpText,
|
|
122
|
+
inputProps = {},
|
|
123
|
+
isDisabled = false,
|
|
124
|
+
isRequired = false,
|
|
125
|
+
name = '',
|
|
126
|
+
onBlur = undefined,
|
|
127
|
+
onClear = undefined,
|
|
128
|
+
onFocus = undefined,
|
|
129
|
+
options,
|
|
130
|
+
placeholder = 'Select...',
|
|
131
|
+
requiredIndicator = ' *',
|
|
132
|
+
size = 'md',
|
|
133
|
+
},
|
|
134
|
+
ref
|
|
135
|
+
) => {
|
|
136
|
+
const placeholderOption = { value: '', label: placeholder };
|
|
137
|
+
const optionsWithPlaceholder = [{ ...placeholderOption }, ...options];
|
|
138
|
+
|
|
139
|
+
const responsiveClasses = generateResponsiveClasses('size', size);
|
|
140
|
+
|
|
141
|
+
const inputWrapperClasses = classNames(
|
|
142
|
+
'hyphen-components__variables__form-control',
|
|
143
|
+
styles['text-input-wrapper'],
|
|
144
|
+
...responsiveClasses.map((c) => styles[c]),
|
|
145
|
+
{
|
|
146
|
+
[styles.error]: error,
|
|
147
|
+
[styles.disabled]: isDisabled,
|
|
148
|
+
[styles['is-clearable']]: onClear,
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const clearBtnClasses = classNames(styles['clear-button'], styles.md);
|
|
153
|
+
|
|
154
|
+
const renderClearIcon = (): ReactNode => {
|
|
155
|
+
const handleKeyPress = (
|
|
156
|
+
event: KeyboardEvent<HTMLButtonElement>
|
|
157
|
+
): void => {
|
|
158
|
+
if (event.keyCode === 13 && onClear) onClear(event);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<button
|
|
163
|
+
type="button"
|
|
164
|
+
onClick={onClear}
|
|
165
|
+
onKeyUp={handleKeyPress}
|
|
166
|
+
className={clearBtnClasses}
|
|
167
|
+
data-testid="text-input-clear-button"
|
|
168
|
+
aria-label="clear input"
|
|
169
|
+
>
|
|
170
|
+
<Icon name="remove" className="display-block" />
|
|
171
|
+
</button>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const computedInputProps: SelectInputInsetProps['inputProps'] = {
|
|
176
|
+
...inputProps, // These are spread first so that we don't have top level props overwritten by the user.
|
|
177
|
+
'aria-required': isRequired,
|
|
178
|
+
'aria-invalid': !!error,
|
|
179
|
+
'aria-label': label,
|
|
180
|
+
'aria-labelledby': label ? `${id}Label` : undefined,
|
|
181
|
+
autoComplete: getAutoCompleteValue(autoComplete),
|
|
182
|
+
autoFocus,
|
|
183
|
+
disabled: isDisabled,
|
|
184
|
+
id,
|
|
185
|
+
name,
|
|
186
|
+
onBlur,
|
|
187
|
+
onChange,
|
|
188
|
+
onFocus,
|
|
189
|
+
required: isRequired,
|
|
190
|
+
value: value ?? '',
|
|
191
|
+
className: classNames(inputProps.className),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<div ref={ref}>
|
|
196
|
+
<Box
|
|
197
|
+
direction="row"
|
|
198
|
+
flex="auto"
|
|
199
|
+
position="relative"
|
|
200
|
+
className={inputWrapperClasses}
|
|
201
|
+
>
|
|
202
|
+
<Box as="select" {...computedInputProps}>
|
|
203
|
+
{optionsWithPlaceholder.map((option) => (
|
|
204
|
+
<Box
|
|
205
|
+
as="option"
|
|
206
|
+
key={option.value}
|
|
207
|
+
value={option.value}
|
|
208
|
+
disabled={option.value === ''}
|
|
209
|
+
hidden={option.value === ''}
|
|
210
|
+
color={option.value === '' ? 'secondary' : 'base'}
|
|
211
|
+
>
|
|
212
|
+
{option.label}
|
|
213
|
+
</Box>
|
|
214
|
+
))}
|
|
215
|
+
</Box>
|
|
216
|
+
{!!onClear && !!value && renderClearIcon()}
|
|
217
|
+
<label
|
|
218
|
+
htmlFor={id}
|
|
219
|
+
className={styles['select-input-label']}
|
|
220
|
+
id={`${id}Label`}
|
|
221
|
+
>
|
|
222
|
+
{label}
|
|
223
|
+
{isRequired && requiredIndicator && (
|
|
224
|
+
<span>{requiredIndicator}</span>
|
|
225
|
+
)}
|
|
226
|
+
</label>
|
|
227
|
+
</Box>
|
|
228
|
+
{helpText && <HelpText>{helpText}</HelpText>}
|
|
229
|
+
{error && error !== true && (
|
|
230
|
+
<InputValidationMessage>{error}</InputValidationMessage>
|
|
231
|
+
)}
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Canvas, Meta, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import { SelectInputNative } from './SelectInputNative';
|
|
3
|
+
import * as Stories from './SelectInputNative.stories';
|
|
4
|
+
|
|
5
|
+
<Meta of={Stories} />
|
|
6
|
+
|
|
7
|
+
# SelectInputNative
|
|
8
|
+
|
|
9
|
+
Allows users to pick a value from a predefined list of options. Ideally, it should be used when there are 5 or more options, otherwise you should consider using a radio group instead.
|
|
10
|
+
|
|
11
|
+
_NOTE:_ This is an alternative to the `SelectInput` component, but leveraging the native platform dropdown instead of a custom one. This is useful,
|
|
12
|
+
when a custom UI is not needed for a select, or the native UI is preferred (this is recommended for most cases except multi-selects).
|
|
13
|
+
|
|
14
|
+
## Props
|
|
15
|
+
|
|
16
|
+
<ArgTypes of={SelectInputNative} />
|
|
17
|
+
|
|
18
|
+
## Default
|
|
19
|
+
|
|
20
|
+
All that is required to render a basic version of the SelectInputNative is a unique `id`, a `label`, a list of options passed to the `options` prop, a `value`, and an onchange event handler passed to the `onChange` prop.
|
|
21
|
+
|
|
22
|
+
<Canvas of={Stories.Default} />
|
|
23
|
+
|
|
24
|
+
## Pre-Selected
|
|
25
|
+
|
|
26
|
+
Pre-select an option by passing its value to the `value` prop.
|
|
27
|
+
|
|
28
|
+
<Canvas of={Stories.PreSelected} />
|
|
29
|
+
|
|
30
|
+
## Help Text
|
|
31
|
+
|
|
32
|
+
Use the `helpText` prop to add clarifying text beneath the input label.
|
|
33
|
+
|
|
34
|
+
<Canvas of={Stories.HelpText} />
|
|
35
|
+
|
|
36
|
+
## Placeholder
|
|
37
|
+
|
|
38
|
+
Use the `placeholder` prop to add a custom placeholder. Note that this component automatically renders the first option
|
|
39
|
+
to use as a placeholder with a value of `''`. This first option is however disabled can't be selected after a user has picked
|
|
40
|
+
one of the real options.
|
|
41
|
+
|
|
42
|
+
<Canvas of={Stories.Placeholder} />
|
|
43
|
+
|
|
44
|
+
## Hidden Label
|
|
45
|
+
|
|
46
|
+
Use the `hideLabel` prop to not render the label.
|
|
47
|
+
|
|
48
|
+
<Canvas of={Stories.HiddenLabel} />
|
|
49
|
+
|
|
50
|
+
## Autofocus
|
|
51
|
+
|
|
52
|
+
Use the `autoFocus` prop to autofocus a SelectInput.
|
|
53
|
+
|
|
54
|
+
<Canvas of={Stories.Autofocus} />
|
|
55
|
+
|
|
56
|
+
## Required
|
|
57
|
+
|
|
58
|
+
Use the `isRequired` prop to set the `required` and `aria-required` on the underlying input element.
|
|
59
|
+
|
|
60
|
+
<Canvas of={Stories.Required} />
|
|
61
|
+
|
|
62
|
+
You can remove or customize the required indicator using the `requiredIndicator` prop.
|
|
63
|
+
|
|
64
|
+
<Canvas of={Stories.CustomRequiredIndicator} />
|
|
65
|
+
|
|
66
|
+
## Disabled
|
|
67
|
+
|
|
68
|
+
Use the `isDisabled` prop to mark the input as disabled.
|
|
69
|
+
|
|
70
|
+
<Canvas of={Stories.Disabled} />
|
|
71
|
+
|
|
72
|
+
## Error
|
|
73
|
+
|
|
74
|
+
Use the `error` prop to mark the input as invalid. `error` accepts a `boolean`, `string`, or `node`. If either a `string` or `node` is passed, a validation message is displayed below it.
|
|
75
|
+
|
|
76
|
+
<Canvas of={Stories.Error} />
|
|
77
|
+
|
|
78
|
+
## Sizes
|
|
79
|
+
|
|
80
|
+
Set the size of the input to `sm`, `md` or `lg`. `md` is the default size.
|
|
81
|
+
The `size` prop is also a `ResponsiveProp`, so it can be sized differently at each [breakpoint](?path=/docs/design-tokens-design-tokens--page#breakpoints) by passing an object.
|
|
82
|
+
|
|
83
|
+
<Canvas of={Stories.Sizes} />
|
|
84
|
+
|
|
85
|
+
## Component Design Tokens
|
|
86
|
+
|
|
87
|
+
This component shares component design tokens with all form controls. For a complete list of tokens, see the [Theming Form Controls documentation](/docs/theming-form-controls--custom-theme-form).
|