@nypl/design-system-react-components 0.23.4 → 0.25.1
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/CHANGELOG.md +98 -1
- package/README.md +46 -11
- package/dist/components/Accordion/Accordion.d.ts +14 -14
- package/dist/components/Autosuggest/Autosuggest.stories.d.ts +1 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +11 -14
- package/dist/components/Breadcrumbs/BreadcrumbsTypes.d.ts +6 -0
- package/dist/components/Button/Button.d.ts +6 -13
- package/dist/components/Button/ButtonTypes.d.ts +5 -3
- package/dist/components/Card/Card.d.ts +59 -10
- package/dist/components/Card/CardTypes.d.ts +19 -0
- package/dist/components/CardEdition/CardEdition.d.ts +21 -0
- package/dist/components/{StyleGuide/Colors.stories.d.ts → CardEdition/CardEdition.stories.d.ts} +5 -2
- package/dist/components/Checkbox/Checkbox.d.ts +21 -16
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +43 -0
- package/dist/components/CheckboxGroup/CheckboxGroupLayoutTypes.d.ts +4 -0
- package/dist/components/DatePicker/DatePicker.d.ts +79 -0
- package/dist/components/DatePicker/DatePickerTypes.d.ts +5 -0
- package/dist/components/Form/Form.d.ts +16 -8
- package/dist/components/Form/FormTypes.d.ts +2 -0
- package/dist/components/Grid/GridTypes.d.ts +9 -0
- package/dist/components/Grid/SimpleGrid.d.ts +14 -0
- package/dist/components/Heading/Heading.d.ts +9 -11
- package/dist/components/Heading/{HeadingDisplaySizes.d.ts → HeadingTypes.d.ts} +8 -0
- package/dist/components/HelperErrorText/HelperErrorText.stories.d.ts +2 -1
- package/dist/components/Hero/Hero.d.ts +19 -14
- package/dist/components/Hero/HeroTypes.d.ts +10 -5
- package/dist/components/Icons/Icon.d.ts +13 -16
- package/dist/components/Icons/IconSvgs.d.ts +4 -0
- package/dist/components/Icons/IconTypes.d.ts +78 -60
- package/dist/components/Image/Image.stories.d.ts +2 -1
- package/dist/components/Label/Label.d.ts +10 -26
- package/dist/components/Link/Link.d.ts +8 -12
- package/dist/components/List/List.stories.d.ts +1 -0
- package/dist/components/Radio/Radio.d.ts +30 -24
- package/dist/components/RadioGroup/RadioGroup.d.ts +40 -0
- package/dist/components/RadioGroup/RadioGroupLayoutTypes.d.ts +4 -0
- package/dist/components/SearchBar/SearchBar.d.ts +45 -27
- package/dist/components/Select/Select.d.ts +34 -35
- package/dist/components/Select/SelectTypes.d.ts +4 -0
- package/dist/components/SkeletonLoader/SkeletonLoader.d.ts +1 -1
- package/dist/components/SkeletonLoader/SkeletonLoaderTypes.d.ts +2 -2
- package/dist/components/StatusBadge/StatusBadge.d.ts +8 -6
- package/dist/components/StatusBadge/StatusBadgeTypes.d.ts +5 -0
- package/dist/components/Tabs/Tabs.d.ts +25 -0
- package/dist/components/Template/Template.d.ts +91 -0
- package/dist/components/Text/Text.d.ts +16 -0
- package/dist/components/Text/TextTypes.d.ts +6 -0
- package/dist/components/TextInput/TextInput.d.ts +37 -30
- package/dist/components/TextInput/TextInputTypes.d.ts +5 -0
- package/dist/design-system-react-components.cjs.development.js +4102 -917
- package/dist/design-system-react-components.cjs.development.js.map +1 -1
- package/dist/design-system-react-components.cjs.production.min.js +1 -1
- package/dist/design-system-react-components.cjs.production.min.js.map +1 -1
- package/dist/design-system-react-components.esm.js +4023 -920
- package/dist/design-system-react-components.esm.js.map +1 -1
- package/dist/index.d.ts +23 -5
- package/dist/resources.scss +133 -24
- package/dist/styles.css +1 -1
- package/dist/theme/components/accordion.d.ts +25 -0
- package/dist/theme/components/breadcrumb.d.ts +90 -0
- package/dist/theme/components/button.d.ts +109 -0
- package/dist/theme/components/checkbox.d.ts +91 -0
- package/dist/theme/components/customCheckboxGroup.d.ts +18 -0
- package/dist/theme/components/customRadioGroup.d.ts +18 -0
- package/dist/theme/components/global.d.ts +55 -0
- package/dist/theme/components/globalMixins.d.ts +15 -0
- package/dist/theme/components/heading.d.ts +110 -0
- package/dist/theme/components/hero.d.ts +492 -0
- package/dist/theme/components/icon.d.ts +13 -0
- package/dist/theme/components/label.d.ts +16 -0
- package/dist/theme/components/link.d.ts +45 -0
- package/dist/theme/components/radio.d.ts +95 -0
- package/dist/theme/components/searchBar.d.ts +20 -0
- package/dist/theme/components/select.d.ts +58 -0
- package/dist/theme/components/statusBadge.d.ts +25 -0
- package/dist/theme/components/tabs.d.ts +85 -0
- package/dist/theme/components/template.d.ts +105 -0
- package/dist/theme/components/text.d.ts +20 -0
- package/dist/theme/components/textInput.d.ts +105 -0
- package/dist/theme/foundations/breakpoints.d.ts +23 -0
- package/dist/theme/foundations/colors.d.ts +3 -0
- package/dist/theme/foundations/global.d.ts +23 -0
- package/dist/theme/foundations/shadows.d.ts +4 -0
- package/dist/theme/foundations/spacing.d.ts +77 -0
- package/dist/theme/foundations/typography.d.ts +8 -0
- package/dist/theme/index.d.ts +20 -0
- package/dist/theme/provider.d.ts +5 -0
- package/dist/theme/types.d.ts +1 -0
- package/dist/utils/utils.d.ts +6 -0
- package/package.json +9 -2
- package/src/components/Accordion/Accordion.stories.mdx +233 -33
- package/src/components/Accordion/Accordion.test.tsx +135 -19
- package/src/components/Accordion/Accordion.tsx +81 -56
- package/src/components/Autosuggest/Autosuggest.stories.mdx +4 -3
- package/src/components/Autosuggest/Autosuggest.stories.tsx +1 -1
- package/src/components/Autosuggest/_Autosuggest.scss +2 -2
- package/src/components/Breadcrumbs/Breadcrumbs.stories.mdx +57 -56
- package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +31 -25
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +71 -73
- package/src/components/Breadcrumbs/BreadcrumbsTypes.tsx +6 -0
- package/src/components/Breadcrumbs/__snapshots__/Breadcrumbs.test.tsx.snap +100 -0
- package/src/components/Button/Button.stories.mdx +125 -138
- package/src/components/Button/Button.test.tsx +65 -11
- package/src/components/Button/Button.tsx +72 -68
- package/src/components/Button/ButtonTypes.tsx +4 -2
- package/src/components/Button/_Button.scss +7 -92
- package/src/components/Button/__snapshots__/Button.test.tsx.snap +58 -3
- package/src/components/Card/Card.stories.mdx +694 -0
- package/src/components/Card/Card.test.tsx +97 -102
- package/src/components/Card/Card.tsx +182 -31
- package/src/components/Card/CardTypes.tsx +21 -0
- package/src/components/Card/_Card.scss +234 -49
- package/src/components/{Card/Card.stories.tsx → CardEdition/CardEdition.stories.tsx} +32 -22
- package/src/components/CardEdition/CardEdition.test.tsx +395 -0
- package/src/components/CardEdition/CardEdition.tsx +60 -0
- package/src/components/CardEdition/_CardEdition.scss +138 -0
- package/src/components/Chakra/Box.stories.mdx +57 -0
- package/src/components/Chakra/Center.stories.mdx +99 -0
- package/src/components/Chakra/Grid.stories.mdx +79 -0
- package/src/components/Chakra/Stack.stories.mdx +93 -0
- package/src/components/Checkbox/Checkbox.stories.mdx +57 -35
- package/src/components/Checkbox/Checkbox.test.tsx +117 -147
- package/src/components/Checkbox/Checkbox.tsx +76 -50
- package/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +325 -0
- package/src/components/CheckboxGroup/CheckboxGroup.stories.mdx +249 -0
- package/src/components/CheckboxGroup/CheckboxGroup.test.tsx +345 -0
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +148 -0
- package/src/components/CheckboxGroup/CheckboxGroupLayoutTypes.tsx +4 -0
- package/src/components/CheckboxGroup/__snapshots__/CheckboxGroup.test.tsx.snap +1360 -0
- package/src/components/DatePicker/DatePicker.stories.mdx +284 -0
- package/src/components/DatePicker/DatePicker.test.tsx +657 -0
- package/src/components/DatePicker/DatePicker.tsx +396 -0
- package/src/components/DatePicker/DatePickerTypes.tsx +5 -0
- package/src/components/DatePicker/_DatePicker.scss +76 -0
- package/src/components/Form/Form.stories.mdx +130 -27
- package/src/components/Form/Form.test.tsx +78 -36
- package/src/components/Form/Form.tsx +53 -19
- package/src/components/Form/FormTypes.tsx +3 -0
- package/src/components/Form/__snapshots__/Form.test.tsx.snap +38 -0
- package/src/components/Grid/GridTypes.tsx +9 -0
- package/src/components/Grid/SimpleGrid.stories.mdx +275 -0
- package/src/components/Grid/SimpleGrid.test.tsx +66 -0
- package/src/components/Grid/SimpleGrid.tsx +37 -0
- package/src/components/Grid/__snapshots__/SimpleGrid.test.tsx.snap +8 -0
- package/src/components/Heading/Heading.stories.mdx +63 -33
- package/src/components/Heading/Heading.test.tsx +24 -16
- package/src/components/Heading/Heading.tsx +54 -38
- package/src/components/Heading/{HeadingDisplaySizes.tsx → HeadingTypes.tsx} +9 -0
- package/src/components/HelperErrorText/HelperErrorText.stories.tsx +2 -1
- package/src/components/HelperErrorText/_HelperErrorText.scss +1 -1
- package/src/components/Hero/Hero.stories.mdx +195 -85
- package/src/components/Hero/Hero.test.tsx +544 -113
- package/src/components/Hero/Hero.tsx +80 -93
- package/src/components/Hero/HeroTypes.tsx +17 -5
- package/src/components/Hero/__snapshots__/Hero.test.tsx.snap +307 -0
- package/src/components/HorizontalRule/HorizontalRule.stories.mdx +6 -1
- package/src/components/HorizontalRule/_HorizontalRule.scss +1 -1
- package/src/components/Icons/Icon.stories.mdx +89 -74
- package/src/components/Icons/Icon.test.tsx +30 -22
- package/src/components/Icons/Icon.tsx +63 -61
- package/src/components/Icons/IconSvgs.tsx +8 -0
- package/src/components/Icons/IconTypes.tsx +80 -60
- package/src/components/Image/Image.stories.tsx +2 -1
- package/src/components/Input/_Input.scss +2 -2
- package/src/components/Label/Label.stories.mdx +77 -0
- package/src/components/Label/Label.test.tsx +43 -12
- package/src/components/Label/Label.tsx +28 -45
- package/src/components/Label/__snapshots__/Label.test.tsx.snap +41 -0
- package/src/components/Link/Link.stories.mdx +47 -41
- package/src/components/Link/Link.test.tsx +33 -44
- package/src/components/Link/Link.tsx +114 -100
- package/src/components/List/List.stories.mdx +7 -3
- package/src/components/List/List.stories.tsx +14 -9
- package/src/components/List/List.test.tsx +12 -8
- package/src/components/List/List.tsx +9 -7
- package/src/components/List/_List.scss +3 -3
- package/src/components/Modal/Modal.stories.mdx +7 -3
- package/src/components/Modal/_Modal.scss +1 -1
- package/src/components/Notification/Notification.stories.mdx +99 -65
- package/src/components/Notification/Notification.test.tsx +3 -16
- package/src/components/Notification/Notification.tsx +12 -12
- package/src/components/Notification/_Notification.scss +5 -4
- package/src/components/Notification/__snapshots__/Notification.test.tsx.snap +1 -1
- package/src/components/Pagination/Pagination.stories.mdx +7 -1
- package/src/components/Pagination/Pagination.test.tsx +16 -10
- package/src/components/Radio/Radio.stories.mdx +57 -46
- package/src/components/Radio/Radio.test.tsx +92 -138
- package/src/components/Radio/Radio.tsx +70 -69
- package/src/components/Radio/__snapshots__/Radio.test.tsx.snap +250 -0
- package/src/components/RadioGroup/RadioGroup.stories.mdx +247 -0
- package/src/components/RadioGroup/RadioGroup.test.tsx +327 -0
- package/src/components/RadioGroup/RadioGroup.tsx +154 -0
- package/src/components/RadioGroup/RadioGroupLayoutTypes.tsx +4 -0
- package/src/components/RadioGroup/__snapshots__/RadioGroup.test.tsx.snap +1101 -0
- package/src/components/SearchBar/SearchBar.Test.tsx +151 -16
- package/src/components/SearchBar/SearchBar.stories.mdx +196 -224
- package/src/components/SearchBar/SearchBar.tsx +151 -46
- package/src/components/Select/Select.stories.mdx +193 -168
- package/src/components/Select/Select.test.tsx +129 -324
- package/src/components/Select/Select.tsx +120 -160
- package/src/components/Select/SelectTypes.tsx +4 -0
- package/src/components/SkeletonLoader/SkeletonLoader.stories.mdx +18 -29
- package/src/components/SkeletonLoader/SkeletonLoader.test.tsx +7 -7
- package/src/components/SkeletonLoader/SkeletonLoader.tsx +4 -2
- package/src/components/SkeletonLoader/SkeletonLoaderTypes.tsx +2 -2
- package/src/components/SkeletonLoader/_SkeletonLoader.scss +3 -3
- package/src/components/StatusBadge/StatusBadge.stories.mdx +91 -0
- package/src/components/StatusBadge/StatusBadge.test.tsx +35 -7
- package/src/components/StatusBadge/StatusBadge.tsx +24 -25
- package/src/components/StatusBadge/StatusBadgeTypes.tsx +5 -0
- package/src/components/StatusBadge/__snapshots__/StatusBadge.test.tsx.snap +28 -0
- package/src/components/StyleGuide/Bidirectionality.stories.mdx +112 -90
- package/src/components/StyleGuide/Buttons.stories.mdx +98 -100
- package/src/components/StyleGuide/Colors.stories.mdx +336 -0
- package/src/components/StyleGuide/Forms.stories.mdx +85 -0
- package/src/components/StyleGuide/Iconography.stories.mdx +86 -93
- package/src/components/StyleGuide/Spacing.stories.mdx +0 -1
- package/src/components/StyleGuide/Typography.stories.mdx +164 -166
- package/src/components/StyleGuide/UIDocCard.tsx +4 -4
- package/src/components/Tabs/Tabs.stories.mdx +221 -0
- package/src/components/Tabs/Tabs.test.tsx +264 -0
- package/src/components/Tabs/Tabs.tsx +220 -0
- package/src/components/Template/Template.stories.mdx +574 -0
- package/src/components/Template/Template.test.tsx +124 -0
- package/src/components/Template/Template.tsx +226 -0
- package/src/components/Text/Text.stories.mdx +70 -0
- package/src/components/Text/Text.test.tsx +63 -0
- package/src/components/Text/Text.tsx +55 -0
- package/src/components/Text/TextTypes.tsx +6 -0
- package/src/components/Text/__snapshots__/Text.test.tsx.snap +33 -0
- package/src/components/TextInput/TextInput.stories.mdx +90 -90
- package/src/components/TextInput/TextInput.test.tsx +103 -83
- package/src/components/TextInput/TextInput.tsx +108 -91
- package/src/components/TextInput/TextInputTypes.tsx +6 -0
- package/src/components/VideoPlayer/VideoPlayer.stories.mdx +2 -1
- package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
- package/src/components/VideoPlayer/_VideoPlayer.scss +1 -1
- package/src/docs/Chakra.stories.mdx +341 -0
- package/src/docs/Intro.stories.mdx +31 -24
- package/src/index.ts +70 -5
- package/src/styles/01-colors/_colors-brand.scss +6 -4
- package/src/styles/01-colors/_colors-utility.scss +14 -15
- package/src/styles/03-space/_space-inline.scss +47 -7
- package/src/styles/03-space/_space-inset.scss +33 -5
- package/src/styles/03-space/_space-stack.scss +48 -8
- package/src/styles/base/_02-breakpoints.scss +5 -4
- package/src/styles/base/_04-base.scss +2 -1
- package/src/styles/base/_place-holder.scss +1 -1
- package/src/styles/base/_typography.scss +1 -29
- package/src/styles.scss +22 -25
- package/src/theme/components/accordion.ts +30 -0
- package/src/theme/components/breadcrumb.ts +77 -0
- package/src/theme/components/button.ts +125 -0
- package/src/theme/components/checkbox.ts +107 -0
- package/src/theme/components/customCheckboxGroup.ts +12 -0
- package/src/theme/components/customRadioGroup.ts +12 -0
- package/src/theme/components/global.ts +71 -0
- package/src/theme/components/globalMixins.ts +16 -0
- package/src/theme/components/heading.ts +72 -0
- package/src/theme/components/hero.ts +239 -0
- package/src/theme/components/icon.ts +79 -0
- package/src/theme/components/label.ts +17 -0
- package/src/theme/components/link.ts +47 -0
- package/src/theme/components/radio.ts +106 -0
- package/src/theme/components/searchBar.ts +21 -0
- package/src/theme/components/select.ts +50 -0
- package/src/theme/components/statusBadge.ts +27 -0
- package/src/theme/components/tabs.ts +79 -0
- package/src/theme/components/template.ts +114 -0
- package/src/theme/components/text.ts +31 -0
- package/src/theme/components/textInput.ts +61 -0
- package/src/theme/foundations/breakpoints.ts +24 -0
- package/src/theme/foundations/colors.ts +208 -0
- package/src/theme/foundations/global.ts +26 -0
- package/src/theme/foundations/shadows.ts +5 -0
- package/src/theme/foundations/spacing.ts +85 -0
- package/src/theme/foundations/typography.ts +35 -0
- package/src/theme/index.ts +88 -0
- package/src/theme/provider.tsx +9 -0
- package/src/theme/types.ts +1 -0
- package/src/utils/componentCategories.ts +56 -21
- package/src/utils/utils.ts +13 -0
- package/dist/components/Accordion/Accordion.stories.d.ts +0 -5
- package/dist/components/Card/Card.stories.d.ts +0 -27
- package/dist/components/Label/Label.stories.d.ts +0 -12
- package/dist/components/StatusBadge/StatusBadge.stories.d.ts +0 -8
- package/dist/components/Template/Template.stories.d.ts +0 -29
- package/src/components/Accordion/Accordion.stories.tsx +0 -65
- package/src/components/Accordion/_Accordion.scss +0 -81
- package/src/components/Breadcrumbs/_Breadcrumbs.scss +0 -97
- package/src/components/Checkbox/_Checkbox.scss +0 -97
- package/src/components/Form/_Form.scss +0 -28
- package/src/components/Heading/_Heading.scss +0 -163
- package/src/components/Hero/_Hero.scss +0 -256
- package/src/components/Icons/_Icons.scss +0 -116
- package/src/components/Label/Label.stories.tsx +0 -30
- package/src/components/Label/_Label.scss +0 -22
- package/src/components/Link/_Link.scss +0 -73
- package/src/components/Radio/_Radio.scss +0 -84
- package/src/components/SearchBar/_SearchBar.scss +0 -16
- package/src/components/Select/_Select.scss +0 -82
- package/src/components/StatusBadge/StatusBadge.stories.tsx +0 -33
- package/src/components/StatusBadge/_StatusBadge.scss +0 -23
- package/src/components/StyleGuide/Colors.stories.tsx +0 -288
- package/src/components/Template/Template.stories.tsx +0 -85
- package/src/components/Template/_Template.scss +0 -63
- package/src/components/TextInput/_TextInput.scss +0 -59
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { axe } from "jest-axe";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
|
|
6
|
+
import { Tabs, TabList, Tab, TabPanels, TabPanel } from "./Tabs";
|
|
7
|
+
|
|
8
|
+
export const animalCrossing = [
|
|
9
|
+
{
|
|
10
|
+
label: "Tom Nook",
|
|
11
|
+
content: (
|
|
12
|
+
<p>
|
|
13
|
+
Tom Nook, <b>known in Japan as Tanukichi</b>, is a fictional character
|
|
14
|
+
in the Animal Crossing series who operates the village store.
|
|
15
|
+
</p>
|
|
16
|
+
),
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: "Isabelle",
|
|
20
|
+
content:
|
|
21
|
+
"Isabelle, known as Shizue in Japan, is a fictional character " +
|
|
22
|
+
"from the Animal Crossing series of video games. She is a kindly Shih " +
|
|
23
|
+
"Tzu that debuted in the 2012 release Animal Crossing: New Leaf, where " +
|
|
24
|
+
"she serves as the secretary to the player character.",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "K.K. Slider",
|
|
28
|
+
content:
|
|
29
|
+
"<p>Totakeke, more commonly known as <b>K.K. Slider or K.K.</b>, is a " +
|
|
30
|
+
"fictional character within the Animal Crossing franchise. One of the " +
|
|
31
|
+
"franchise's most popular characters, he debuted in the title Animal " +
|
|
32
|
+
"Crossing, and has appeared in every installment since.</p>",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
describe("Tabs Accessibility", () => {
|
|
37
|
+
it("passes axe accessibility test with the data prop", async () => {
|
|
38
|
+
const { container } = render(<Tabs contentData={animalCrossing} />);
|
|
39
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("passes axe accessibility test with children components", async () => {
|
|
43
|
+
const { container } = render(
|
|
44
|
+
<Tabs>
|
|
45
|
+
<TabList>
|
|
46
|
+
<Tab>Tom Nook</Tab>
|
|
47
|
+
<Tab>Isabelle</Tab>
|
|
48
|
+
<Tab>K.K. Slider</Tab>
|
|
49
|
+
</TabList>
|
|
50
|
+
<TabPanels>
|
|
51
|
+
<TabPanel>
|
|
52
|
+
Tom Nook, known in Japan as Tanukichi, is a fictional character in
|
|
53
|
+
the Animal Crossing series who operates the village store.
|
|
54
|
+
</TabPanel>
|
|
55
|
+
<TabPanel>
|
|
56
|
+
Isabelle, known as Shizue in Japan, is a fictional character from
|
|
57
|
+
the Animal Crossing series of video games. She is a kindly Shih Tzu
|
|
58
|
+
that debuted in the 2012 release Animal Crossing: New Leaf, where
|
|
59
|
+
she serves as the secretary to the player character.
|
|
60
|
+
</TabPanel>
|
|
61
|
+
<TabPanel>
|
|
62
|
+
Totakeke, more commonly known as K.K. Slider or K.K., is a fictional
|
|
63
|
+
character within the Animal Crossing franchise. One of the
|
|
64
|
+
franchise's most popular characters, he debuted in the title Animal
|
|
65
|
+
Crossing, and has appeared in every installment since.
|
|
66
|
+
</TabPanel>
|
|
67
|
+
</TabPanels>
|
|
68
|
+
</Tabs>
|
|
69
|
+
);
|
|
70
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("Tabs", () => {
|
|
75
|
+
const getTabByName = (name) => screen.getByRole("tab", { name });
|
|
76
|
+
|
|
77
|
+
it("renders all tabs but only one panel at a time with children", () => {
|
|
78
|
+
render(
|
|
79
|
+
<Tabs>
|
|
80
|
+
<TabList>
|
|
81
|
+
<Tab>Tom Nook</Tab>
|
|
82
|
+
<Tab>Isabelle</Tab>
|
|
83
|
+
<Tab>K.K. Slider</Tab>
|
|
84
|
+
</TabList>
|
|
85
|
+
<TabPanels>
|
|
86
|
+
<TabPanel>
|
|
87
|
+
Tom Nook, known in Japan as Tanukichi, is a fictional character in
|
|
88
|
+
the Animal Crossing series who operates the village store.
|
|
89
|
+
</TabPanel>
|
|
90
|
+
<TabPanel>
|
|
91
|
+
Isabelle, known as Shizue in Japan, is a fictional character from
|
|
92
|
+
the Animal Crossing series of video games. She is a kindly Shih Tzu
|
|
93
|
+
that debuted in the 2012 release Animal Crossing: New Leaf, where
|
|
94
|
+
she serves as the secretary to the player character.
|
|
95
|
+
</TabPanel>
|
|
96
|
+
<TabPanel>
|
|
97
|
+
Totakeke, more commonly known as K.K. Slider or K.K., is a fictional
|
|
98
|
+
character within the Animal Crossing franchise. One of the
|
|
99
|
+
franchise's most popular characters, he debuted in the title Animal
|
|
100
|
+
Crossing, and has appeared in every installment since.
|
|
101
|
+
</TabPanel>
|
|
102
|
+
</TabPanels>
|
|
103
|
+
</Tabs>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(getTabByName("Tom Nook")).toBeInTheDocument();
|
|
107
|
+
expect(getTabByName("Isabelle")).toBeInTheDocument();
|
|
108
|
+
expect(getTabByName("K.K. Slider")).toBeInTheDocument();
|
|
109
|
+
expect(
|
|
110
|
+
screen.getByText(/Tom Nook, known in Japan as Tanukichi/i)
|
|
111
|
+
).toBeInTheDocument();
|
|
112
|
+
expect(
|
|
113
|
+
screen.queryByText(/Isabelle, known as Shizue in Japan,/i)
|
|
114
|
+
).not.toBeInTheDocument();
|
|
115
|
+
expect(
|
|
116
|
+
screen.queryByText(
|
|
117
|
+
/Totakeke, more commonly known as K.K. Slider or K.K./i
|
|
118
|
+
)
|
|
119
|
+
).not.toBeInTheDocument();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("renders all tabs but only one visible panel at a time with data prop", () => {
|
|
123
|
+
render(<Tabs contentData={animalCrossing} />);
|
|
124
|
+
expect(getTabByName("Tom Nook")).toBeInTheDocument();
|
|
125
|
+
expect(getTabByName("Isabelle")).toBeInTheDocument();
|
|
126
|
+
expect(getTabByName("K.K. Slider")).toBeInTheDocument();
|
|
127
|
+
expect(
|
|
128
|
+
screen.getByText(/known in Japan as Tanukichi/i)
|
|
129
|
+
).toBeInTheDocument();
|
|
130
|
+
expect(
|
|
131
|
+
screen.queryByText(/Isabelle, known as Shizue in Japan,/i)
|
|
132
|
+
).not.toBeVisible();
|
|
133
|
+
expect(
|
|
134
|
+
screen.queryByText(/Totakeke, more commonly known as/i)
|
|
135
|
+
).not.toBeVisible();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("switches between tabs", () => {
|
|
139
|
+
render(<Tabs contentData={animalCrossing} />);
|
|
140
|
+
const isabelleTab = getTabByName("Isabelle");
|
|
141
|
+
const kkSliderTab = getTabByName("K.K. Slider");
|
|
142
|
+
|
|
143
|
+
expect(
|
|
144
|
+
screen.getByText(/known in Japan as Tanukichi/i)
|
|
145
|
+
).toBeInTheDocument();
|
|
146
|
+
expect(
|
|
147
|
+
screen.queryByText(/Isabelle, known as Shizue in Japan,/i)
|
|
148
|
+
).not.toBeVisible();
|
|
149
|
+
expect(
|
|
150
|
+
screen.queryByText(/Totakeke, more commonly known as/i)
|
|
151
|
+
).not.toBeVisible();
|
|
152
|
+
|
|
153
|
+
userEvent.click(isabelleTab);
|
|
154
|
+
expect(isabelleTab).toHaveAttribute("aria-selected", "true");
|
|
155
|
+
|
|
156
|
+
expect(
|
|
157
|
+
screen.queryByText(/known in Japan as Tanukichi/i)
|
|
158
|
+
).not.toBeInTheDocument();
|
|
159
|
+
expect(
|
|
160
|
+
screen.queryByText(/Isabelle, known as Shizue in Japan,/i)
|
|
161
|
+
).toBeInTheDocument();
|
|
162
|
+
expect(
|
|
163
|
+
screen.queryByText(/Totakeke, more commonly known/i)
|
|
164
|
+
).not.toBeVisible();
|
|
165
|
+
|
|
166
|
+
userEvent.click(kkSliderTab);
|
|
167
|
+
expect(kkSliderTab).toHaveAttribute("aria-selected", "true");
|
|
168
|
+
|
|
169
|
+
expect(
|
|
170
|
+
screen.queryByText(/known in Japan as Tanukichi/i)
|
|
171
|
+
).not.toBeInTheDocument();
|
|
172
|
+
expect(
|
|
173
|
+
screen.queryByText(/Isabelle, known as Shizue in Japan,/i)
|
|
174
|
+
).not.toBeVisible();
|
|
175
|
+
expect(
|
|
176
|
+
screen.queryByText(/Totakeke, more commonly known/i)
|
|
177
|
+
).toBeInTheDocument();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("renders the specified initial index value", () => {
|
|
181
|
+
render(<Tabs contentData={animalCrossing} defaultIndex={2} />);
|
|
182
|
+
let tomTab = getTabByName("Tom Nook");
|
|
183
|
+
let isabelleTab = getTabByName("Isabelle");
|
|
184
|
+
let kkSliderTab = getTabByName("K.K. Slider");
|
|
185
|
+
|
|
186
|
+
expect(tomTab).toHaveAttribute("aria-selected", "false");
|
|
187
|
+
expect(isabelleTab).toHaveAttribute("aria-selected", "false");
|
|
188
|
+
expect(kkSliderTab).toHaveAttribute("aria-selected", "true");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("invokes the callback function", () => {
|
|
192
|
+
let selectedIndex = 0;
|
|
193
|
+
const onChange = (index) => (selectedIndex = index);
|
|
194
|
+
|
|
195
|
+
render(<Tabs contentData={animalCrossing} onChange={onChange} />);
|
|
196
|
+
|
|
197
|
+
const tomTab = getTabByName("Tom Nook");
|
|
198
|
+
const isabelleTab = getTabByName("Isabelle");
|
|
199
|
+
const kkSliderTab = getTabByName("K.K. Slider");
|
|
200
|
+
|
|
201
|
+
userEvent.click(kkSliderTab);
|
|
202
|
+
expect(selectedIndex).toEqual(2);
|
|
203
|
+
|
|
204
|
+
userEvent.click(tomTab);
|
|
205
|
+
expect(selectedIndex).toEqual(0);
|
|
206
|
+
|
|
207
|
+
userEvent.click(isabelleTab);
|
|
208
|
+
expect(selectedIndex).toEqual(1);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should throw warning when both the 'data' probp and children are passed", () => {
|
|
212
|
+
const warn = jest.spyOn(console, "warn");
|
|
213
|
+
render(
|
|
214
|
+
<Tabs contentData={animalCrossing}>
|
|
215
|
+
<TabList>
|
|
216
|
+
<Tab>Tom Nook</Tab>
|
|
217
|
+
<Tab>Isabelle</Tab>
|
|
218
|
+
<Tab>K.K. Slider</Tab>
|
|
219
|
+
</TabList>
|
|
220
|
+
<TabPanels>
|
|
221
|
+
<TabPanel>
|
|
222
|
+
Tom Nook, known in Japan as Tanukichi, is a fictional character in
|
|
223
|
+
the Animal Crossing series who operates the village store.
|
|
224
|
+
</TabPanel>
|
|
225
|
+
<TabPanel>
|
|
226
|
+
Isabelle, known as Shizue in Japan, is a fictional character from
|
|
227
|
+
the Animal Crossing series of video games. She is a kindly Shih Tzu
|
|
228
|
+
that debuted in the 2012 release Animal Crossing: New Leaf, where
|
|
229
|
+
she serves as the secretary to the player character.
|
|
230
|
+
</TabPanel>
|
|
231
|
+
<TabPanel>
|
|
232
|
+
Totakeke, more commonly known as K.K. Slider or K.K., is a fictional
|
|
233
|
+
character within the Animal Crossing franchise. One of the
|
|
234
|
+
franchise's most popular characters, he debuted in the title Animal
|
|
235
|
+
Crossing, and has appeared in every installment since.
|
|
236
|
+
</TabPanel>
|
|
237
|
+
</TabPanels>
|
|
238
|
+
</Tabs>
|
|
239
|
+
);
|
|
240
|
+
expect(warn).toHaveBeenCalledWith(
|
|
241
|
+
"Only pass children or data in the `data` props but not both."
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should throw warning when more than six object tabs are passed", () => {
|
|
246
|
+
const warn = jest.spyOn(console, "warn");
|
|
247
|
+
render(
|
|
248
|
+
<Tabs
|
|
249
|
+
contentData={[
|
|
250
|
+
...animalCrossing,
|
|
251
|
+
...[
|
|
252
|
+
{ label: "Another character 1", content: "Text" },
|
|
253
|
+
{ label: "Another character 2", content: "Text" },
|
|
254
|
+
{ label: "Another character 3", content: "Text" },
|
|
255
|
+
{ label: "Another character 4", content: "Text" },
|
|
256
|
+
],
|
|
257
|
+
]}
|
|
258
|
+
/>
|
|
259
|
+
);
|
|
260
|
+
expect(warn).toHaveBeenCalledWith(
|
|
261
|
+
"We recommend to use no more than six tabs. If more than six tabs are needed, consider other navigational patterns."
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
Tabs as ChakraTabs,
|
|
5
|
+
TabList,
|
|
6
|
+
Tab,
|
|
7
|
+
TabPanels,
|
|
8
|
+
TabPanel,
|
|
9
|
+
useMultiStyleConfig,
|
|
10
|
+
} from "@chakra-ui/react";
|
|
11
|
+
|
|
12
|
+
import generateUUID from "../../helpers/generateUUID";
|
|
13
|
+
import { IconNames, IconRotationTypes, IconSizes } from "../Icons/IconTypes";
|
|
14
|
+
import Icon from "../Icons/Icon";
|
|
15
|
+
import { ButtonTypes } from "../Button/ButtonTypes";
|
|
16
|
+
import Button from "../Button/Button";
|
|
17
|
+
|
|
18
|
+
// The general shape of the data object for each Tab.
|
|
19
|
+
export interface TabsContentDataProps {
|
|
20
|
+
label: string;
|
|
21
|
+
content: string | React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TabsProps {
|
|
25
|
+
/** Array of data to display */
|
|
26
|
+
contentData?: TabsContentDataProps[];
|
|
27
|
+
/** The index of the tab to display for controlled situations. */
|
|
28
|
+
defaultIndex?: number;
|
|
29
|
+
/** ID that other components can cross reference for accessibility purposes */
|
|
30
|
+
id?: string;
|
|
31
|
+
/** The callback function invoked on every tab change event. */
|
|
32
|
+
onChange?: (index: number) => any;
|
|
33
|
+
/** Render a hash in the url for each tab. Only available when data is
|
|
34
|
+
* passed through the `data` props. */
|
|
35
|
+
useHash?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* An internal function used to update the hash in the URL.
|
|
40
|
+
* This function is only used when `useHash` is `true`.
|
|
41
|
+
*/
|
|
42
|
+
const onClickHash = (tabHash) => {
|
|
43
|
+
window.location.hash = tabHash;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* This returns an object with `Tab` and `TabPanel` components to render in
|
|
48
|
+
* `TabList` and `TabPanels` components respectively.
|
|
49
|
+
*/
|
|
50
|
+
const getElementsFromContentData = (data, useHash) => {
|
|
51
|
+
const tabs = [];
|
|
52
|
+
const panels = [];
|
|
53
|
+
|
|
54
|
+
if (!data?.length) {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (data?.length > 6) {
|
|
59
|
+
console.warn(
|
|
60
|
+
"We recommend to use no more than six tabs. If more than six tabs are " +
|
|
61
|
+
"needed, consider other navigational patterns."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
data.map((tab, index) => {
|
|
66
|
+
let tempPanel;
|
|
67
|
+
// For URL hash enabled tabs, we need to add a custom `onClick` to handle the URL hash.
|
|
68
|
+
const tempTab = (
|
|
69
|
+
<Tab
|
|
70
|
+
fontSize={["0", null, "1"]}
|
|
71
|
+
key={index}
|
|
72
|
+
onClick={useHash ? () => onClickHash(`tab${index + 1}`) : null}
|
|
73
|
+
>
|
|
74
|
+
{tab.label}
|
|
75
|
+
</Tab>
|
|
76
|
+
);
|
|
77
|
+
if (typeof tab.content === "string") {
|
|
78
|
+
tempPanel = (
|
|
79
|
+
<TabPanel
|
|
80
|
+
key={index}
|
|
81
|
+
dangerouslySetInnerHTML={{ __html: tab.content }}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
tempPanel = <TabPanel key={index}>{tab.content}</TabPanel>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
tabs.push(tempTab);
|
|
89
|
+
panels.push(tempPanel);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return { tabs, panels };
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* This returns an object with `TabList` and `TabPanels` components to help format
|
|
97
|
+
* the DOM when building up the `Tabs` component using child component.
|
|
98
|
+
*/
|
|
99
|
+
const getElementsFromChildren = (children) => {
|
|
100
|
+
const tabs = [];
|
|
101
|
+
const panels = [];
|
|
102
|
+
|
|
103
|
+
if (!children?.length) {
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
children.map((child) => {
|
|
108
|
+
if (child.type === TabList || child.props.mdxType === "TabList") {
|
|
109
|
+
tabs.push(child);
|
|
110
|
+
|
|
111
|
+
const childTabs = React.Children.count(child.props.children);
|
|
112
|
+
if (childTabs > 6) {
|
|
113
|
+
console.warn(
|
|
114
|
+
"We recommend to use no more than six tabs. If more than six tabs are " +
|
|
115
|
+
"needed, consider other navigational patterns."
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (child.type === TabPanels || child.props.mdxType === "TabPanels") {
|
|
121
|
+
panels.push(child);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return { tabs, panels };
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Renders Chakra's `Tab` component with specific variants, props,
|
|
130
|
+
* and controlled styling.
|
|
131
|
+
*/
|
|
132
|
+
function Tabs(props: React.PropsWithChildren<TabsProps>) {
|
|
133
|
+
const {
|
|
134
|
+
children,
|
|
135
|
+
contentData,
|
|
136
|
+
defaultIndex = 0,
|
|
137
|
+
id = generateUUID(),
|
|
138
|
+
onChange,
|
|
139
|
+
useHash = false,
|
|
140
|
+
} = props;
|
|
141
|
+
const styles = useMultiStyleConfig("Tabs", {});
|
|
142
|
+
const { tabs, panels } = contentData
|
|
143
|
+
? getElementsFromContentData(contentData, useHash)
|
|
144
|
+
: getElementsFromChildren(children);
|
|
145
|
+
|
|
146
|
+
if (children && contentData?.length) {
|
|
147
|
+
console.warn(
|
|
148
|
+
"Only pass children or data in the `data` props but not both."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<ChakraTabs
|
|
154
|
+
id={id}
|
|
155
|
+
// The following lazy loads each panel whenever it is needed.
|
|
156
|
+
isLazy
|
|
157
|
+
onChange={onChange}
|
|
158
|
+
defaultIndex={defaultIndex}
|
|
159
|
+
variant="enclosed"
|
|
160
|
+
>
|
|
161
|
+
{contentData ? (
|
|
162
|
+
<>
|
|
163
|
+
<Box
|
|
164
|
+
__css={styles.tablistWrapper}
|
|
165
|
+
sx={{
|
|
166
|
+
"&::-webkit-scrollbar": {
|
|
167
|
+
display: "none",
|
|
168
|
+
},
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
<Button
|
|
172
|
+
buttonType={ButtonTypes.Primary}
|
|
173
|
+
attributes={{
|
|
174
|
+
"aria-label": "Previous",
|
|
175
|
+
...styles.buttonArrows,
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
<Icon
|
|
179
|
+
name={IconNames.Arrow}
|
|
180
|
+
iconRotation={IconRotationTypes.Rotate90}
|
|
181
|
+
size={IconSizes.Small}
|
|
182
|
+
/>
|
|
183
|
+
</Button>
|
|
184
|
+
<TabList>{tabs}</TabList>
|
|
185
|
+
<Button
|
|
186
|
+
buttonType={ButtonTypes.Primary}
|
|
187
|
+
attributes={{
|
|
188
|
+
"aria-label": "Next",
|
|
189
|
+
...styles.buttonArrows,
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
<Icon
|
|
193
|
+
name={IconNames.Arrow}
|
|
194
|
+
iconRotation={IconRotationTypes.Rotate270}
|
|
195
|
+
size={IconSizes.Small}
|
|
196
|
+
/>
|
|
197
|
+
</Button>
|
|
198
|
+
</Box>
|
|
199
|
+
<TabPanels>{panels}</TabPanels>
|
|
200
|
+
</>
|
|
201
|
+
) : (
|
|
202
|
+
<>
|
|
203
|
+
<Box
|
|
204
|
+
__css={styles.tablistWrapper}
|
|
205
|
+
sx={{
|
|
206
|
+
"&::-webkit-scrollbar": {
|
|
207
|
+
display: "none",
|
|
208
|
+
},
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
{tabs}
|
|
212
|
+
</Box>
|
|
213
|
+
{panels}
|
|
214
|
+
</>
|
|
215
|
+
)}
|
|
216
|
+
</ChakraTabs>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export { Tabs, TabList, Tab, TabPanels, TabPanel };
|