@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,199 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { DatePicker } from './DatePicker';
|
|
3
|
+
import type { Meta } from '@storybook/react';
|
|
4
|
+
import { Box } from '../Box/Box';
|
|
5
|
+
import { Heading } from '../Heading/Heading';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof DatePicker> = {
|
|
8
|
+
title: 'Components/DatePicker',
|
|
9
|
+
component: DatePicker,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
|
|
14
|
+
export const BasicExample = () => {
|
|
15
|
+
const [selectedDate, setSelectedDate] = useState<Date>(new Date(2019, 11, 3));
|
|
16
|
+
return (
|
|
17
|
+
<Box gap="md">
|
|
18
|
+
<DatePicker
|
|
19
|
+
onChange={(date) => setSelectedDate(date as Date)}
|
|
20
|
+
selected={selectedDate}
|
|
21
|
+
/>
|
|
22
|
+
<p>Selected Date: {selectedDate.toISOString()}</p>
|
|
23
|
+
</Box>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const DateRange = () => {
|
|
28
|
+
const [startDate, setStartDate] = useState<Date>(new Date(2019, 11, 3));
|
|
29
|
+
const [endDate, setEndDate] = useState<Date>(new Date(2019, 11, 28));
|
|
30
|
+
const setDate = ([startDate, endDate]: [Date, Date]) => {
|
|
31
|
+
setStartDate(startDate);
|
|
32
|
+
setEndDate(endDate);
|
|
33
|
+
};
|
|
34
|
+
return (
|
|
35
|
+
<Box gap="md">
|
|
36
|
+
<DatePicker
|
|
37
|
+
onChange={(date) => setDate(date as [Date, Date])}
|
|
38
|
+
selected={startDate}
|
|
39
|
+
startDate={startDate}
|
|
40
|
+
endDate={endDate}
|
|
41
|
+
selectsRange
|
|
42
|
+
/>
|
|
43
|
+
<p>
|
|
44
|
+
{`Selected Date Range: ${startDate && startDate.toISOString()} - ${
|
|
45
|
+
endDate && endDate.toISOString()
|
|
46
|
+
}`}
|
|
47
|
+
</p>
|
|
48
|
+
</Box>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const MinAndMaxDates = () => {
|
|
53
|
+
const [startDate, setStartDate] = useState<Date>(new Date(2019, 11, 18));
|
|
54
|
+
const min = new Date(2019, 11, 18);
|
|
55
|
+
min.setDate(min.getDate() - 5);
|
|
56
|
+
const max = new Date(2019, 11, 18);
|
|
57
|
+
max.setDate(max.getDate() + 5);
|
|
58
|
+
return (
|
|
59
|
+
<Box gap="md">
|
|
60
|
+
<DatePicker
|
|
61
|
+
selected={startDate}
|
|
62
|
+
onChange={(date) => setStartDate(date as Date)}
|
|
63
|
+
minDate={min}
|
|
64
|
+
maxDate={max}
|
|
65
|
+
/>
|
|
66
|
+
<p>Selected Date: {startDate.toISOString()}</p>
|
|
67
|
+
</Box>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const MonthPicker = () => {
|
|
72
|
+
const [startDateOne, setStartDateOne] = useState<Date>(new Date(2019, 10));
|
|
73
|
+
const [startDateTwo, setStartDateTwo] = useState<Date>(new Date(2019, 10));
|
|
74
|
+
const [startDateThree, setStartDateThree] = useState<Date>(
|
|
75
|
+
new Date(2019, 10)
|
|
76
|
+
);
|
|
77
|
+
return (
|
|
78
|
+
<Box display="flex" direction="row" gap="md">
|
|
79
|
+
<Box
|
|
80
|
+
gap="md"
|
|
81
|
+
display="flex"
|
|
82
|
+
direction="column"
|
|
83
|
+
alignItems="center"
|
|
84
|
+
width="33"
|
|
85
|
+
>
|
|
86
|
+
<Heading size="md">Default</Heading>
|
|
87
|
+
<DatePicker
|
|
88
|
+
selected={startDateOne}
|
|
89
|
+
onChange={(date) => setStartDateOne(date as Date)}
|
|
90
|
+
showMonthYearPicker
|
|
91
|
+
/>
|
|
92
|
+
<p>{startDateOne.toISOString()}</p>
|
|
93
|
+
</Box>
|
|
94
|
+
<Box
|
|
95
|
+
gap="md"
|
|
96
|
+
display="flex"
|
|
97
|
+
direction="column"
|
|
98
|
+
alignItems="center"
|
|
99
|
+
width="33"
|
|
100
|
+
>
|
|
101
|
+
<Heading size="md">With full month name</Heading>
|
|
102
|
+
<DatePicker
|
|
103
|
+
selected={startDateTwo}
|
|
104
|
+
onChange={(date) => setStartDateTwo(date as Date)}
|
|
105
|
+
showMonthYearPicker
|
|
106
|
+
showFullMonthYearPicker
|
|
107
|
+
/>
|
|
108
|
+
<p>{startDateTwo.toISOString()}</p>
|
|
109
|
+
</Box>
|
|
110
|
+
<Box
|
|
111
|
+
gap="md"
|
|
112
|
+
display="flex"
|
|
113
|
+
direction="column"
|
|
114
|
+
alignItems="center"
|
|
115
|
+
width="33"
|
|
116
|
+
>
|
|
117
|
+
<Heading size="md">With Two-column layout</Heading>
|
|
118
|
+
<DatePicker
|
|
119
|
+
selected={startDateThree}
|
|
120
|
+
onChange={(date) => setStartDateThree(date as Date)}
|
|
121
|
+
showMonthYearPicker
|
|
122
|
+
showFullMonthYearPicker
|
|
123
|
+
showTwoColumnMonthYearPicker
|
|
124
|
+
/>
|
|
125
|
+
<p>{startDateThree.toISOString()}</p>
|
|
126
|
+
</Box>
|
|
127
|
+
</Box>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const ShowMultipleMonths = () => {
|
|
132
|
+
const [startDate, setStartDate] = useState<Date>(new Date(2019, 11, 3));
|
|
133
|
+
const [endDate, setEndDate] = useState<Date>(new Date(2019, 12, 20));
|
|
134
|
+
const setDate = ([startDate, endDate]: [Date, Date]) => {
|
|
135
|
+
setStartDate(startDate);
|
|
136
|
+
setEndDate(endDate);
|
|
137
|
+
};
|
|
138
|
+
return (
|
|
139
|
+
<Box gap="md">
|
|
140
|
+
<DatePicker
|
|
141
|
+
onChange={(date) => setDate(date as [Date, Date])}
|
|
142
|
+
selected={startDate}
|
|
143
|
+
startDate={startDate}
|
|
144
|
+
endDate={endDate}
|
|
145
|
+
selectsRange
|
|
146
|
+
monthsShown={2}
|
|
147
|
+
/>
|
|
148
|
+
<p>Start Date: {startDate && startDate.toISOString()}</p>
|
|
149
|
+
<p>End Date: {endDate && endDate.toISOString()}</p>
|
|
150
|
+
</Box>
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const WithTimePicker = () => {
|
|
155
|
+
const [startDate, setStartDate] = useState<Date>(new Date('1993/09/28'));
|
|
156
|
+
return (
|
|
157
|
+
<Box gap="md">
|
|
158
|
+
<DatePicker
|
|
159
|
+
selected={startDate}
|
|
160
|
+
onChange={(date) => setStartDate(date as Date)}
|
|
161
|
+
showTimeSelect
|
|
162
|
+
timeIntervals={15}
|
|
163
|
+
timeCaption="Time"
|
|
164
|
+
/>
|
|
165
|
+
<p>Selected Date: {startDate && startDate.toISOString()}</p>
|
|
166
|
+
</Box>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export const OpenByDefaultOnASpecificDate = () => {
|
|
171
|
+
const [startDate, setStartDate] = useState<Date>(new Date('1993/09/28'));
|
|
172
|
+
return (
|
|
173
|
+
<Box gap="md">
|
|
174
|
+
<DatePicker
|
|
175
|
+
onChange={(date) => setStartDate(date as Date)}
|
|
176
|
+
selected={startDate}
|
|
177
|
+
openToDate={new Date('1993/09/28')}
|
|
178
|
+
/>
|
|
179
|
+
<p>Selected Date: {startDate && startDate.toISOString()}</p>
|
|
180
|
+
</Box>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const WithChildren = () => {
|
|
185
|
+
const [selectedDate, setSelectedDate] = useState<Date>(new Date(2019, 11, 3));
|
|
186
|
+
return (
|
|
187
|
+
<Box gap="md">
|
|
188
|
+
<DatePicker
|
|
189
|
+
onChange={(date) => setSelectedDate(date as Date)}
|
|
190
|
+
selected={selectedDate}
|
|
191
|
+
>
|
|
192
|
+
<Box display="block" style={{ textAlign: 'center' }} color="base">
|
|
193
|
+
It will be sunny out today!
|
|
194
|
+
</Box>
|
|
195
|
+
</DatePicker>
|
|
196
|
+
<p>Selected Date: {selectedDate.toISOString()}</p>
|
|
197
|
+
</Box>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
+
import { DatePicker } from './DatePicker';
|
|
4
|
+
|
|
5
|
+
describe('DatePicker', () => {
|
|
6
|
+
describe('Default', () => {
|
|
7
|
+
it('renders a datepicker with default props', () => {
|
|
8
|
+
const mockedOnChange = jest.fn();
|
|
9
|
+
const { container } = render(<DatePicker onChange={mockedOnChange} />);
|
|
10
|
+
const datePicker = container.querySelector('.react-datepicker');
|
|
11
|
+
expect(datePicker).toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('Callbacks', () => {
|
|
16
|
+
it('Fires the expected callback when date is selected', () => {
|
|
17
|
+
const openToDate = new Date('1995, 11, 14');
|
|
18
|
+
const mockedOnChange = jest.fn();
|
|
19
|
+
render(<DatePicker onChange={mockedOnChange} openToDate={openToDate} />);
|
|
20
|
+
const fourteenth = screen.getByText('14');
|
|
21
|
+
expect(fourteenth).toBeInTheDocument();
|
|
22
|
+
fireEvent.click(fourteenth);
|
|
23
|
+
expect(mockedOnChange).toHaveBeenCalledTimes(1);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React, { FC, SyntheticEvent, ReactNode } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import ReactDatePicker, { ReactDatePickerProps } from 'react-datepicker';
|
|
4
|
+
import styles from './DatePicker.module.scss';
|
|
5
|
+
|
|
6
|
+
export interface DatePickerProps extends ReactDatePickerProps<any, any> {
|
|
7
|
+
/**
|
|
8
|
+
* React children (to be rendered below the calendar dates).
|
|
9
|
+
*/
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* Custom classname to be applied to the DatePicker container.
|
|
13
|
+
*/
|
|
14
|
+
className?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Callback that fires when a date is changed/selected.
|
|
17
|
+
*/
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
onChange: (
|
|
20
|
+
date: Date | [Date, Date] | null,
|
|
21
|
+
event?: React.SyntheticEvent<any> | undefined
|
|
22
|
+
) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Callback that fires when a date is clicked.
|
|
25
|
+
*/
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
onSelect?:
|
|
28
|
+
| ((date: Date, event: SyntheticEvent<any, Event> | undefined) => void)
|
|
29
|
+
| undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Custom Class to be applied to a single day element based on a date.
|
|
32
|
+
*/
|
|
33
|
+
dayClassName?: ((date: Date) => string | null) | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Custom Class to be applied to a single week element based on a date.
|
|
36
|
+
*/
|
|
37
|
+
weekClassName?: ((date: Date) => string | null) | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Custom Class to be applied to a single month element based on a date.
|
|
40
|
+
*/
|
|
41
|
+
monthClassName?: ((date: Date) => string | null) | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Custom Class to be applied to a specific time.
|
|
44
|
+
*/
|
|
45
|
+
timeClassName?: ((date: Date) => string | null) | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Custom format for weekday.
|
|
48
|
+
*/
|
|
49
|
+
formatWeekDay?: (formattedDate: string) => string;
|
|
50
|
+
/**
|
|
51
|
+
* Last allowable/shown date
|
|
52
|
+
*/
|
|
53
|
+
maxDate?: Date | null;
|
|
54
|
+
/**
|
|
55
|
+
* First allowable/shown date
|
|
56
|
+
*/
|
|
57
|
+
minDate?: Date | null;
|
|
58
|
+
/**
|
|
59
|
+
* Months to be shown at one time
|
|
60
|
+
*/
|
|
61
|
+
monthsShown?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Date that the calendar will open to by default.
|
|
64
|
+
*/
|
|
65
|
+
openToDate?: Date;
|
|
66
|
+
/**
|
|
67
|
+
* Currently selected date.
|
|
68
|
+
*/
|
|
69
|
+
selected?: Date | null;
|
|
70
|
+
/**
|
|
71
|
+
* Whether or not the picker will return a range of dates.
|
|
72
|
+
*/
|
|
73
|
+
selectsRange?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Start date in a range
|
|
76
|
+
*/
|
|
77
|
+
startDate?: Date | null;
|
|
78
|
+
/**
|
|
79
|
+
* Show month picker in two columns
|
|
80
|
+
*/
|
|
81
|
+
showTwoColumnMonthYearPicker?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* See full month name in the month picker
|
|
84
|
+
*/
|
|
85
|
+
showFullMonthYearPicker?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Use the month picker
|
|
88
|
+
*/
|
|
89
|
+
showMonthYearPicker?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Additional props to be spread to rendered element
|
|
92
|
+
*/
|
|
93
|
+
[x: string]: any; // eslint-disable-line
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const DatePicker: FC<DatePickerProps> = ({
|
|
97
|
+
children = null,
|
|
98
|
+
dayClassName = undefined,
|
|
99
|
+
maxDate = undefined,
|
|
100
|
+
minDate = undefined,
|
|
101
|
+
monthsShown = undefined,
|
|
102
|
+
openToDate = undefined,
|
|
103
|
+
startDate = undefined,
|
|
104
|
+
selected = undefined,
|
|
105
|
+
selectsRange = undefined,
|
|
106
|
+
showTwoColumnMonthYearPicker = false,
|
|
107
|
+
showFullMonthYearPicker = false,
|
|
108
|
+
showMonthYearPicker = false,
|
|
109
|
+
className = undefined,
|
|
110
|
+
formatWeekDay = (formattedDate) => formattedDate[0], // Make days show as 1 character.
|
|
111
|
+
...restProps
|
|
112
|
+
}) => {
|
|
113
|
+
const datePickerClasses = classNames(styles['react-datepicker'], className);
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<ReactDatePicker
|
|
117
|
+
inline
|
|
118
|
+
calendarClassName={datePickerClasses}
|
|
119
|
+
formatWeekDay={formatWeekDay}
|
|
120
|
+
maxDate={maxDate}
|
|
121
|
+
minDate={minDate}
|
|
122
|
+
monthsShown={monthsShown}
|
|
123
|
+
openToDate={openToDate}
|
|
124
|
+
selected={selected}
|
|
125
|
+
startDate={startDate}
|
|
126
|
+
selectsRange={selectsRange}
|
|
127
|
+
showTwoColumnMonthYearPicker={showTwoColumnMonthYearPicker}
|
|
128
|
+
showFullMonthYearPicker={showFullMonthYearPicker}
|
|
129
|
+
showMonthYearPicker={showMonthYearPicker}
|
|
130
|
+
dayClassName={dayClassName}
|
|
131
|
+
{...restProps}
|
|
132
|
+
>
|
|
133
|
+
{children}
|
|
134
|
+
</ReactDatePicker>
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export default DatePicker;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Canvas, Meta, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import { Details } from './Details';
|
|
3
|
+
import { DetailsSummary } from './DetailsSummary';
|
|
4
|
+
import * as Stories from './Details.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={Stories} />
|
|
7
|
+
|
|
8
|
+
# Details
|
|
9
|
+
|
|
10
|
+
The `<details>` tag specifies additional details that the user can open and close on demand. This custom component
|
|
11
|
+
provides a React implementation of this semantic HTML with controlled state.
|
|
12
|
+
|
|
13
|
+
It includes a child component for the details summary `<Details.Summary />`. The details themselves can be included as children
|
|
14
|
+
inside `<Details>` typically following the `<Details.Summary>`.
|
|
15
|
+
|
|
16
|
+
NOTE: for a custom implementation of this component see the [accordion](/?path=/story/components-accordion-overview--default-story)
|
|
17
|
+
|
|
18
|
+
<Canvas of={Stories.BasicUsage} />
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
<ArgTypes of={Details} />
|
|
23
|
+
|
|
24
|
+
## Sub-Components
|
|
25
|
+
|
|
26
|
+
### `<Details.Summary>`
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
<ArgTypes of={DetailsSummary} />
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.details-reset {
|
|
2
|
+
> summary {
|
|
3
|
+
cursor: pointer;
|
|
4
|
+
list-style: none;
|
|
5
|
+
|
|
6
|
+
&::-webkit-details-marker {
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
&::before {
|
|
11
|
+
display: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&:focus {
|
|
15
|
+
outline: 0;
|
|
16
|
+
box-shadow: 0 0 0 2px var(--color-base-primary-light);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//Show focus styles on keyboard focus.
|
|
20
|
+
&:focus-visible {
|
|
21
|
+
outline: 0;
|
|
22
|
+
box-shadow: 0 0 0 2px var(--color-base-primary-light);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Hide focus styles if they are not needed, for example,
|
|
26
|
+
// when an element receives focus via the mouse.
|
|
27
|
+
&:focus:not(:focus-visible) {
|
|
28
|
+
outline: 0;
|
|
29
|
+
box-shadow: none;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Details } from './Details';
|
|
2
|
+
import type { Meta } from '@storybook/react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Box } from '../Box/Box';
|
|
5
|
+
import { useOpenClose } from '../../hooks/useOpenClose/useOpenClose';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Details> = {
|
|
8
|
+
title: 'Components/Details',
|
|
9
|
+
component: Details,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
|
|
14
|
+
export const BasicUsage = () => {
|
|
15
|
+
const { isOpen, handleToggle } = useOpenClose();
|
|
16
|
+
return (
|
|
17
|
+
<Details isOpen={isOpen}>
|
|
18
|
+
<Details.Summary
|
|
19
|
+
isDetailsOpen={isOpen}
|
|
20
|
+
onToggle={handleToggle}
|
|
21
|
+
display="inline"
|
|
22
|
+
>
|
|
23
|
+
What is Hyphen's Mission?
|
|
24
|
+
</Details.Summary>
|
|
25
|
+
<Box padding="md 0" gap="sm">
|
|
26
|
+
<Box fontSize="lg" as="h4">
|
|
27
|
+
Empowering Teams with Streamlined DevOps
|
|
28
|
+
</Box>
|
|
29
|
+
<Box as="p">
|
|
30
|
+
Our mission is to streamline DevOps for software teams. By automating
|
|
31
|
+
access management and integrating essential tools, we empower teams to
|
|
32
|
+
focus on innovation and deliver seamless software solutions
|
|
33
|
+
efficiently.
|
|
34
|
+
</Box>
|
|
35
|
+
</Box>
|
|
36
|
+
</Details>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { Details } from './Details';
|
|
4
|
+
|
|
5
|
+
describe('Details', () => {
|
|
6
|
+
describe('Default', () => {
|
|
7
|
+
test('It renders a default details HTML element and summary', () => {
|
|
8
|
+
render(
|
|
9
|
+
<Details isOpen={false}>
|
|
10
|
+
<Details.Summary isDetailsOpen={false}>summary</Details.Summary>
|
|
11
|
+
</Details>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const details = screen.getByRole('group');
|
|
15
|
+
expect(details).toBeInTheDocument();
|
|
16
|
+
const summary = screen.getByText('summary');
|
|
17
|
+
expect(summary).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('With open details initially', () => {
|
|
22
|
+
test('It renders a default details HTML element and summary', () => {
|
|
23
|
+
render(
|
|
24
|
+
<Details isOpen>
|
|
25
|
+
<Details.Summary isDetailsOpen>summary</Details.Summary>
|
|
26
|
+
<div>details</div>
|
|
27
|
+
</Details>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const details = screen.getByRole('group');
|
|
31
|
+
expect(details).toBeInTheDocument();
|
|
32
|
+
const summary = screen.getByText('summary');
|
|
33
|
+
expect(summary).toBeInTheDocument();
|
|
34
|
+
const innerDetails = screen.getByText('details');
|
|
35
|
+
expect(innerDetails).toBeVisible();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('Aria', () => {
|
|
40
|
+
test('It renders the summary with the correct "button" role', () => {
|
|
41
|
+
render(
|
|
42
|
+
<Details isOpen={false}>
|
|
43
|
+
<Details.Summary isDetailsOpen={false}>summary</Details.Summary>
|
|
44
|
+
</Details>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const summary = screen.getByRole('button');
|
|
48
|
+
expect(summary).toBeInTheDocument();
|
|
49
|
+
expect(summary).toHaveTextContent('summary');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('It notes whether the underlying element is expanded', () => {
|
|
53
|
+
const { rerender } = render(
|
|
54
|
+
<Details isOpen={false}>
|
|
55
|
+
<Details.Summary isDetailsOpen={false}>summary</Details.Summary>
|
|
56
|
+
</Details>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const summary = screen.getByText('summary');
|
|
60
|
+
expect(summary).toBeInTheDocument();
|
|
61
|
+
expect(summary).toHaveAttribute('aria-expanded', 'false');
|
|
62
|
+
|
|
63
|
+
rerender(
|
|
64
|
+
<Details isOpen>
|
|
65
|
+
<Details.Summary isDetailsOpen>summary2</Details.Summary>
|
|
66
|
+
</Details>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const summaryTwo = screen.getByText('summary2');
|
|
70
|
+
expect(summaryTwo).toBeInTheDocument();
|
|
71
|
+
expect(summaryTwo).toHaveAttribute('aria-expanded', 'true');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('The summary is tabbable', () => {
|
|
75
|
+
render(
|
|
76
|
+
<Details isOpen={false}>
|
|
77
|
+
<Details.Summary isDetailsOpen={false}>summary</Details.Summary>
|
|
78
|
+
</Details>
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const summary = screen.getByRole('button');
|
|
82
|
+
expect(summary).toBeInTheDocument();
|
|
83
|
+
expect(summary).toHaveAttribute('tabIndex', '0');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('Events', () => {
|
|
88
|
+
test('it fires an onToggle when summary is clicked', () => {
|
|
89
|
+
const mockedOnToggle = jest.fn(() => null);
|
|
90
|
+
|
|
91
|
+
render(
|
|
92
|
+
<Details isOpen={false}>
|
|
93
|
+
<Details.Summary isDetailsOpen={false} onToggle={mockedOnToggle}>
|
|
94
|
+
summary
|
|
95
|
+
</Details.Summary>
|
|
96
|
+
</Details>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const summary = screen.getByRole('button');
|
|
100
|
+
fireEvent.click(summary);
|
|
101
|
+
expect(mockedOnToggle).toHaveBeenCalledTimes(1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('onToggle event fires with ENTER key', () => {
|
|
105
|
+
const mockedOnToggle = jest.fn(() => null);
|
|
106
|
+
|
|
107
|
+
render(
|
|
108
|
+
<Details isOpen={false}>
|
|
109
|
+
<Details.Summary isDetailsOpen={false} onToggle={mockedOnToggle}>
|
|
110
|
+
summary
|
|
111
|
+
</Details.Summary>
|
|
112
|
+
</Details>
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const summary = screen.getByRole('button');
|
|
116
|
+
fireEvent.keyDown(summary, { keyCode: 13 });
|
|
117
|
+
fireEvent.keyDown(summary, { keyCode: 32 });
|
|
118
|
+
fireEvent.keyDown(summary, { keyCode: 25 });
|
|
119
|
+
expect(mockedOnToggle).toHaveBeenCalledTimes(2);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('Does not attempt to fire onToggle if function not passed', () => {
|
|
123
|
+
const mockedOnToggle = jest.fn(() => null);
|
|
124
|
+
|
|
125
|
+
render(
|
|
126
|
+
<Details isOpen={false}>
|
|
127
|
+
<Details.Summary isDetailsOpen={false}>summary</Details.Summary>
|
|
128
|
+
</Details>
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const summary = screen.getByRole('button');
|
|
132
|
+
fireEvent.keyDown(summary, { keyCode: 13 });
|
|
133
|
+
fireEvent.keyDown(summary, { keyCode: 32 });
|
|
134
|
+
fireEvent.click(summary);
|
|
135
|
+
expect(mockedOnToggle).toHaveBeenCalledTimes(0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('Fires onClick if passed', () => {
|
|
139
|
+
const mockedOnToggle = jest.fn(() => null);
|
|
140
|
+
|
|
141
|
+
render(
|
|
142
|
+
<Details isOpen={false}>
|
|
143
|
+
<Details.Summary isDetailsOpen={false} onClick={mockedOnToggle}>
|
|
144
|
+
summary
|
|
145
|
+
</Details.Summary>
|
|
146
|
+
</Details>
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const summary = screen.getByRole('button');
|
|
150
|
+
fireEvent.click(summary);
|
|
151
|
+
expect(mockedOnToggle).toHaveBeenCalledTimes(1);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test('Fires onKeyDown if passed', () => {
|
|
155
|
+
const mockedOnToggle = jest.fn(() => null);
|
|
156
|
+
|
|
157
|
+
render(
|
|
158
|
+
<Details isOpen={false}>
|
|
159
|
+
<Details.Summary isDetailsOpen={false} onKeyDown={mockedOnToggle}>
|
|
160
|
+
summary
|
|
161
|
+
</Details.Summary>
|
|
162
|
+
</Details>
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const summary = screen.getByRole('button');
|
|
166
|
+
fireEvent.keyDown(summary, { keyCode: 13 });
|
|
167
|
+
|
|
168
|
+
expect(mockedOnToggle).toHaveBeenCalledTimes(1);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('Spread props', () => {
|
|
173
|
+
it('takes a className and applies it to root node', () => {
|
|
174
|
+
render(
|
|
175
|
+
<Details isOpen={false} className="m-bottom-md">
|
|
176
|
+
<Details.Summary isDetailsOpen={false} className="m-top-lg">
|
|
177
|
+
summary
|
|
178
|
+
</Details.Summary>
|
|
179
|
+
</Details>
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const details = screen.getByRole('group');
|
|
183
|
+
expect(details).toHaveClass('m-bottom-md');
|
|
184
|
+
|
|
185
|
+
const summary = screen.getByRole('button');
|
|
186
|
+
expect(summary).toHaveClass('m-top-lg');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|