@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.
Files changed (307) hide show
  1. package/CHANGELOG.md +98 -1
  2. package/README.md +46 -11
  3. package/dist/components/Accordion/Accordion.d.ts +14 -14
  4. package/dist/components/Autosuggest/Autosuggest.stories.d.ts +1 -0
  5. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +11 -14
  6. package/dist/components/Breadcrumbs/BreadcrumbsTypes.d.ts +6 -0
  7. package/dist/components/Button/Button.d.ts +6 -13
  8. package/dist/components/Button/ButtonTypes.d.ts +5 -3
  9. package/dist/components/Card/Card.d.ts +59 -10
  10. package/dist/components/Card/CardTypes.d.ts +19 -0
  11. package/dist/components/CardEdition/CardEdition.d.ts +21 -0
  12. package/dist/components/{StyleGuide/Colors.stories.d.ts → CardEdition/CardEdition.stories.d.ts} +5 -2
  13. package/dist/components/Checkbox/Checkbox.d.ts +21 -16
  14. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +43 -0
  15. package/dist/components/CheckboxGroup/CheckboxGroupLayoutTypes.d.ts +4 -0
  16. package/dist/components/DatePicker/DatePicker.d.ts +79 -0
  17. package/dist/components/DatePicker/DatePickerTypes.d.ts +5 -0
  18. package/dist/components/Form/Form.d.ts +16 -8
  19. package/dist/components/Form/FormTypes.d.ts +2 -0
  20. package/dist/components/Grid/GridTypes.d.ts +9 -0
  21. package/dist/components/Grid/SimpleGrid.d.ts +14 -0
  22. package/dist/components/Heading/Heading.d.ts +9 -11
  23. package/dist/components/Heading/{HeadingDisplaySizes.d.ts → HeadingTypes.d.ts} +8 -0
  24. package/dist/components/HelperErrorText/HelperErrorText.stories.d.ts +2 -1
  25. package/dist/components/Hero/Hero.d.ts +19 -14
  26. package/dist/components/Hero/HeroTypes.d.ts +10 -5
  27. package/dist/components/Icons/Icon.d.ts +13 -16
  28. package/dist/components/Icons/IconSvgs.d.ts +4 -0
  29. package/dist/components/Icons/IconTypes.d.ts +78 -60
  30. package/dist/components/Image/Image.stories.d.ts +2 -1
  31. package/dist/components/Label/Label.d.ts +10 -26
  32. package/dist/components/Link/Link.d.ts +8 -12
  33. package/dist/components/List/List.stories.d.ts +1 -0
  34. package/dist/components/Radio/Radio.d.ts +30 -24
  35. package/dist/components/RadioGroup/RadioGroup.d.ts +40 -0
  36. package/dist/components/RadioGroup/RadioGroupLayoutTypes.d.ts +4 -0
  37. package/dist/components/SearchBar/SearchBar.d.ts +45 -27
  38. package/dist/components/Select/Select.d.ts +34 -35
  39. package/dist/components/Select/SelectTypes.d.ts +4 -0
  40. package/dist/components/SkeletonLoader/SkeletonLoader.d.ts +1 -1
  41. package/dist/components/SkeletonLoader/SkeletonLoaderTypes.d.ts +2 -2
  42. package/dist/components/StatusBadge/StatusBadge.d.ts +8 -6
  43. package/dist/components/StatusBadge/StatusBadgeTypes.d.ts +5 -0
  44. package/dist/components/Tabs/Tabs.d.ts +25 -0
  45. package/dist/components/Template/Template.d.ts +91 -0
  46. package/dist/components/Text/Text.d.ts +16 -0
  47. package/dist/components/Text/TextTypes.d.ts +6 -0
  48. package/dist/components/TextInput/TextInput.d.ts +37 -30
  49. package/dist/components/TextInput/TextInputTypes.d.ts +5 -0
  50. package/dist/design-system-react-components.cjs.development.js +4102 -917
  51. package/dist/design-system-react-components.cjs.development.js.map +1 -1
  52. package/dist/design-system-react-components.cjs.production.min.js +1 -1
  53. package/dist/design-system-react-components.cjs.production.min.js.map +1 -1
  54. package/dist/design-system-react-components.esm.js +4023 -920
  55. package/dist/design-system-react-components.esm.js.map +1 -1
  56. package/dist/index.d.ts +23 -5
  57. package/dist/resources.scss +133 -24
  58. package/dist/styles.css +1 -1
  59. package/dist/theme/components/accordion.d.ts +25 -0
  60. package/dist/theme/components/breadcrumb.d.ts +90 -0
  61. package/dist/theme/components/button.d.ts +109 -0
  62. package/dist/theme/components/checkbox.d.ts +91 -0
  63. package/dist/theme/components/customCheckboxGroup.d.ts +18 -0
  64. package/dist/theme/components/customRadioGroup.d.ts +18 -0
  65. package/dist/theme/components/global.d.ts +55 -0
  66. package/dist/theme/components/globalMixins.d.ts +15 -0
  67. package/dist/theme/components/heading.d.ts +110 -0
  68. package/dist/theme/components/hero.d.ts +492 -0
  69. package/dist/theme/components/icon.d.ts +13 -0
  70. package/dist/theme/components/label.d.ts +16 -0
  71. package/dist/theme/components/link.d.ts +45 -0
  72. package/dist/theme/components/radio.d.ts +95 -0
  73. package/dist/theme/components/searchBar.d.ts +20 -0
  74. package/dist/theme/components/select.d.ts +58 -0
  75. package/dist/theme/components/statusBadge.d.ts +25 -0
  76. package/dist/theme/components/tabs.d.ts +85 -0
  77. package/dist/theme/components/template.d.ts +105 -0
  78. package/dist/theme/components/text.d.ts +20 -0
  79. package/dist/theme/components/textInput.d.ts +105 -0
  80. package/dist/theme/foundations/breakpoints.d.ts +23 -0
  81. package/dist/theme/foundations/colors.d.ts +3 -0
  82. package/dist/theme/foundations/global.d.ts +23 -0
  83. package/dist/theme/foundations/shadows.d.ts +4 -0
  84. package/dist/theme/foundations/spacing.d.ts +77 -0
  85. package/dist/theme/foundations/typography.d.ts +8 -0
  86. package/dist/theme/index.d.ts +20 -0
  87. package/dist/theme/provider.d.ts +5 -0
  88. package/dist/theme/types.d.ts +1 -0
  89. package/dist/utils/utils.d.ts +6 -0
  90. package/package.json +9 -2
  91. package/src/components/Accordion/Accordion.stories.mdx +233 -33
  92. package/src/components/Accordion/Accordion.test.tsx +135 -19
  93. package/src/components/Accordion/Accordion.tsx +81 -56
  94. package/src/components/Autosuggest/Autosuggest.stories.mdx +4 -3
  95. package/src/components/Autosuggest/Autosuggest.stories.tsx +1 -1
  96. package/src/components/Autosuggest/_Autosuggest.scss +2 -2
  97. package/src/components/Breadcrumbs/Breadcrumbs.stories.mdx +57 -56
  98. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +31 -25
  99. package/src/components/Breadcrumbs/Breadcrumbs.tsx +71 -73
  100. package/src/components/Breadcrumbs/BreadcrumbsTypes.tsx +6 -0
  101. package/src/components/Breadcrumbs/__snapshots__/Breadcrumbs.test.tsx.snap +100 -0
  102. package/src/components/Button/Button.stories.mdx +125 -138
  103. package/src/components/Button/Button.test.tsx +65 -11
  104. package/src/components/Button/Button.tsx +72 -68
  105. package/src/components/Button/ButtonTypes.tsx +4 -2
  106. package/src/components/Button/_Button.scss +7 -92
  107. package/src/components/Button/__snapshots__/Button.test.tsx.snap +58 -3
  108. package/src/components/Card/Card.stories.mdx +694 -0
  109. package/src/components/Card/Card.test.tsx +97 -102
  110. package/src/components/Card/Card.tsx +182 -31
  111. package/src/components/Card/CardTypes.tsx +21 -0
  112. package/src/components/Card/_Card.scss +234 -49
  113. package/src/components/{Card/Card.stories.tsx → CardEdition/CardEdition.stories.tsx} +32 -22
  114. package/src/components/CardEdition/CardEdition.test.tsx +395 -0
  115. package/src/components/CardEdition/CardEdition.tsx +60 -0
  116. package/src/components/CardEdition/_CardEdition.scss +138 -0
  117. package/src/components/Chakra/Box.stories.mdx +57 -0
  118. package/src/components/Chakra/Center.stories.mdx +99 -0
  119. package/src/components/Chakra/Grid.stories.mdx +79 -0
  120. package/src/components/Chakra/Stack.stories.mdx +93 -0
  121. package/src/components/Checkbox/Checkbox.stories.mdx +57 -35
  122. package/src/components/Checkbox/Checkbox.test.tsx +117 -147
  123. package/src/components/Checkbox/Checkbox.tsx +76 -50
  124. package/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +325 -0
  125. package/src/components/CheckboxGroup/CheckboxGroup.stories.mdx +249 -0
  126. package/src/components/CheckboxGroup/CheckboxGroup.test.tsx +345 -0
  127. package/src/components/CheckboxGroup/CheckboxGroup.tsx +148 -0
  128. package/src/components/CheckboxGroup/CheckboxGroupLayoutTypes.tsx +4 -0
  129. package/src/components/CheckboxGroup/__snapshots__/CheckboxGroup.test.tsx.snap +1360 -0
  130. package/src/components/DatePicker/DatePicker.stories.mdx +284 -0
  131. package/src/components/DatePicker/DatePicker.test.tsx +657 -0
  132. package/src/components/DatePicker/DatePicker.tsx +396 -0
  133. package/src/components/DatePicker/DatePickerTypes.tsx +5 -0
  134. package/src/components/DatePicker/_DatePicker.scss +76 -0
  135. package/src/components/Form/Form.stories.mdx +130 -27
  136. package/src/components/Form/Form.test.tsx +78 -36
  137. package/src/components/Form/Form.tsx +53 -19
  138. package/src/components/Form/FormTypes.tsx +3 -0
  139. package/src/components/Form/__snapshots__/Form.test.tsx.snap +38 -0
  140. package/src/components/Grid/GridTypes.tsx +9 -0
  141. package/src/components/Grid/SimpleGrid.stories.mdx +275 -0
  142. package/src/components/Grid/SimpleGrid.test.tsx +66 -0
  143. package/src/components/Grid/SimpleGrid.tsx +37 -0
  144. package/src/components/Grid/__snapshots__/SimpleGrid.test.tsx.snap +8 -0
  145. package/src/components/Heading/Heading.stories.mdx +63 -33
  146. package/src/components/Heading/Heading.test.tsx +24 -16
  147. package/src/components/Heading/Heading.tsx +54 -38
  148. package/src/components/Heading/{HeadingDisplaySizes.tsx → HeadingTypes.tsx} +9 -0
  149. package/src/components/HelperErrorText/HelperErrorText.stories.tsx +2 -1
  150. package/src/components/HelperErrorText/_HelperErrorText.scss +1 -1
  151. package/src/components/Hero/Hero.stories.mdx +195 -85
  152. package/src/components/Hero/Hero.test.tsx +544 -113
  153. package/src/components/Hero/Hero.tsx +80 -93
  154. package/src/components/Hero/HeroTypes.tsx +17 -5
  155. package/src/components/Hero/__snapshots__/Hero.test.tsx.snap +307 -0
  156. package/src/components/HorizontalRule/HorizontalRule.stories.mdx +6 -1
  157. package/src/components/HorizontalRule/_HorizontalRule.scss +1 -1
  158. package/src/components/Icons/Icon.stories.mdx +89 -74
  159. package/src/components/Icons/Icon.test.tsx +30 -22
  160. package/src/components/Icons/Icon.tsx +63 -61
  161. package/src/components/Icons/IconSvgs.tsx +8 -0
  162. package/src/components/Icons/IconTypes.tsx +80 -60
  163. package/src/components/Image/Image.stories.tsx +2 -1
  164. package/src/components/Input/_Input.scss +2 -2
  165. package/src/components/Label/Label.stories.mdx +77 -0
  166. package/src/components/Label/Label.test.tsx +43 -12
  167. package/src/components/Label/Label.tsx +28 -45
  168. package/src/components/Label/__snapshots__/Label.test.tsx.snap +41 -0
  169. package/src/components/Link/Link.stories.mdx +47 -41
  170. package/src/components/Link/Link.test.tsx +33 -44
  171. package/src/components/Link/Link.tsx +114 -100
  172. package/src/components/List/List.stories.mdx +7 -3
  173. package/src/components/List/List.stories.tsx +14 -9
  174. package/src/components/List/List.test.tsx +12 -8
  175. package/src/components/List/List.tsx +9 -7
  176. package/src/components/List/_List.scss +3 -3
  177. package/src/components/Modal/Modal.stories.mdx +7 -3
  178. package/src/components/Modal/_Modal.scss +1 -1
  179. package/src/components/Notification/Notification.stories.mdx +99 -65
  180. package/src/components/Notification/Notification.test.tsx +3 -16
  181. package/src/components/Notification/Notification.tsx +12 -12
  182. package/src/components/Notification/_Notification.scss +5 -4
  183. package/src/components/Notification/__snapshots__/Notification.test.tsx.snap +1 -1
  184. package/src/components/Pagination/Pagination.stories.mdx +7 -1
  185. package/src/components/Pagination/Pagination.test.tsx +16 -10
  186. package/src/components/Radio/Radio.stories.mdx +57 -46
  187. package/src/components/Radio/Radio.test.tsx +92 -138
  188. package/src/components/Radio/Radio.tsx +70 -69
  189. package/src/components/Radio/__snapshots__/Radio.test.tsx.snap +250 -0
  190. package/src/components/RadioGroup/RadioGroup.stories.mdx +247 -0
  191. package/src/components/RadioGroup/RadioGroup.test.tsx +327 -0
  192. package/src/components/RadioGroup/RadioGroup.tsx +154 -0
  193. package/src/components/RadioGroup/RadioGroupLayoutTypes.tsx +4 -0
  194. package/src/components/RadioGroup/__snapshots__/RadioGroup.test.tsx.snap +1101 -0
  195. package/src/components/SearchBar/SearchBar.Test.tsx +151 -16
  196. package/src/components/SearchBar/SearchBar.stories.mdx +196 -224
  197. package/src/components/SearchBar/SearchBar.tsx +151 -46
  198. package/src/components/Select/Select.stories.mdx +193 -168
  199. package/src/components/Select/Select.test.tsx +129 -324
  200. package/src/components/Select/Select.tsx +120 -160
  201. package/src/components/Select/SelectTypes.tsx +4 -0
  202. package/src/components/SkeletonLoader/SkeletonLoader.stories.mdx +18 -29
  203. package/src/components/SkeletonLoader/SkeletonLoader.test.tsx +7 -7
  204. package/src/components/SkeletonLoader/SkeletonLoader.tsx +4 -2
  205. package/src/components/SkeletonLoader/SkeletonLoaderTypes.tsx +2 -2
  206. package/src/components/SkeletonLoader/_SkeletonLoader.scss +3 -3
  207. package/src/components/StatusBadge/StatusBadge.stories.mdx +91 -0
  208. package/src/components/StatusBadge/StatusBadge.test.tsx +35 -7
  209. package/src/components/StatusBadge/StatusBadge.tsx +24 -25
  210. package/src/components/StatusBadge/StatusBadgeTypes.tsx +5 -0
  211. package/src/components/StatusBadge/__snapshots__/StatusBadge.test.tsx.snap +28 -0
  212. package/src/components/StyleGuide/Bidirectionality.stories.mdx +112 -90
  213. package/src/components/StyleGuide/Buttons.stories.mdx +98 -100
  214. package/src/components/StyleGuide/Colors.stories.mdx +336 -0
  215. package/src/components/StyleGuide/Forms.stories.mdx +85 -0
  216. package/src/components/StyleGuide/Iconography.stories.mdx +86 -93
  217. package/src/components/StyleGuide/Spacing.stories.mdx +0 -1
  218. package/src/components/StyleGuide/Typography.stories.mdx +164 -166
  219. package/src/components/StyleGuide/UIDocCard.tsx +4 -4
  220. package/src/components/Tabs/Tabs.stories.mdx +221 -0
  221. package/src/components/Tabs/Tabs.test.tsx +264 -0
  222. package/src/components/Tabs/Tabs.tsx +220 -0
  223. package/src/components/Template/Template.stories.mdx +574 -0
  224. package/src/components/Template/Template.test.tsx +124 -0
  225. package/src/components/Template/Template.tsx +226 -0
  226. package/src/components/Text/Text.stories.mdx +70 -0
  227. package/src/components/Text/Text.test.tsx +63 -0
  228. package/src/components/Text/Text.tsx +55 -0
  229. package/src/components/Text/TextTypes.tsx +6 -0
  230. package/src/components/Text/__snapshots__/Text.test.tsx.snap +33 -0
  231. package/src/components/TextInput/TextInput.stories.mdx +90 -90
  232. package/src/components/TextInput/TextInput.test.tsx +103 -83
  233. package/src/components/TextInput/TextInput.tsx +108 -91
  234. package/src/components/TextInput/TextInputTypes.tsx +6 -0
  235. package/src/components/VideoPlayer/VideoPlayer.stories.mdx +2 -1
  236. package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
  237. package/src/components/VideoPlayer/_VideoPlayer.scss +1 -1
  238. package/src/docs/Chakra.stories.mdx +341 -0
  239. package/src/docs/Intro.stories.mdx +31 -24
  240. package/src/index.ts +70 -5
  241. package/src/styles/01-colors/_colors-brand.scss +6 -4
  242. package/src/styles/01-colors/_colors-utility.scss +14 -15
  243. package/src/styles/03-space/_space-inline.scss +47 -7
  244. package/src/styles/03-space/_space-inset.scss +33 -5
  245. package/src/styles/03-space/_space-stack.scss +48 -8
  246. package/src/styles/base/_02-breakpoints.scss +5 -4
  247. package/src/styles/base/_04-base.scss +2 -1
  248. package/src/styles/base/_place-holder.scss +1 -1
  249. package/src/styles/base/_typography.scss +1 -29
  250. package/src/styles.scss +22 -25
  251. package/src/theme/components/accordion.ts +30 -0
  252. package/src/theme/components/breadcrumb.ts +77 -0
  253. package/src/theme/components/button.ts +125 -0
  254. package/src/theme/components/checkbox.ts +107 -0
  255. package/src/theme/components/customCheckboxGroup.ts +12 -0
  256. package/src/theme/components/customRadioGroup.ts +12 -0
  257. package/src/theme/components/global.ts +71 -0
  258. package/src/theme/components/globalMixins.ts +16 -0
  259. package/src/theme/components/heading.ts +72 -0
  260. package/src/theme/components/hero.ts +239 -0
  261. package/src/theme/components/icon.ts +79 -0
  262. package/src/theme/components/label.ts +17 -0
  263. package/src/theme/components/link.ts +47 -0
  264. package/src/theme/components/radio.ts +106 -0
  265. package/src/theme/components/searchBar.ts +21 -0
  266. package/src/theme/components/select.ts +50 -0
  267. package/src/theme/components/statusBadge.ts +27 -0
  268. package/src/theme/components/tabs.ts +79 -0
  269. package/src/theme/components/template.ts +114 -0
  270. package/src/theme/components/text.ts +31 -0
  271. package/src/theme/components/textInput.ts +61 -0
  272. package/src/theme/foundations/breakpoints.ts +24 -0
  273. package/src/theme/foundations/colors.ts +208 -0
  274. package/src/theme/foundations/global.ts +26 -0
  275. package/src/theme/foundations/shadows.ts +5 -0
  276. package/src/theme/foundations/spacing.ts +85 -0
  277. package/src/theme/foundations/typography.ts +35 -0
  278. package/src/theme/index.ts +88 -0
  279. package/src/theme/provider.tsx +9 -0
  280. package/src/theme/types.ts +1 -0
  281. package/src/utils/componentCategories.ts +56 -21
  282. package/src/utils/utils.ts +13 -0
  283. package/dist/components/Accordion/Accordion.stories.d.ts +0 -5
  284. package/dist/components/Card/Card.stories.d.ts +0 -27
  285. package/dist/components/Label/Label.stories.d.ts +0 -12
  286. package/dist/components/StatusBadge/StatusBadge.stories.d.ts +0 -8
  287. package/dist/components/Template/Template.stories.d.ts +0 -29
  288. package/src/components/Accordion/Accordion.stories.tsx +0 -65
  289. package/src/components/Accordion/_Accordion.scss +0 -81
  290. package/src/components/Breadcrumbs/_Breadcrumbs.scss +0 -97
  291. package/src/components/Checkbox/_Checkbox.scss +0 -97
  292. package/src/components/Form/_Form.scss +0 -28
  293. package/src/components/Heading/_Heading.scss +0 -163
  294. package/src/components/Hero/_Hero.scss +0 -256
  295. package/src/components/Icons/_Icons.scss +0 -116
  296. package/src/components/Label/Label.stories.tsx +0 -30
  297. package/src/components/Label/_Label.scss +0 -22
  298. package/src/components/Link/_Link.scss +0 -73
  299. package/src/components/Radio/_Radio.scss +0 -84
  300. package/src/components/SearchBar/_SearchBar.scss +0 -16
  301. package/src/components/Select/_Select.scss +0 -82
  302. package/src/components/StatusBadge/StatusBadge.stories.tsx +0 -33
  303. package/src/components/StatusBadge/_StatusBadge.scss +0 -23
  304. package/src/components/StyleGuide/Colors.stories.tsx +0 -288
  305. package/src/components/Template/Template.stories.tsx +0 -85
  306. package/src/components/Template/_Template.scss +0 -63
  307. 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 };