@nypl/design-system-react-components 0.25.12 → 0.25.13

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 (194) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/dist/components/Accordion/Accordion.d.ts +5 -3
  3. package/dist/components/Accordion/AccordionTypes.d.ts +5 -0
  4. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +3 -3
  5. package/dist/components/Breadcrumbs/BreadcrumbsTypes.d.ts +1 -1
  6. package/dist/components/Card/Card.d.ts +11 -20
  7. package/dist/components/Checkbox/Checkbox.d.ts +1 -1
  8. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +4 -2
  9. package/dist/components/Heading/Heading.d.ts +4 -4
  10. package/dist/components/Heading/HeadingTypes.d.ts +1 -1
  11. package/dist/components/Hero/Hero.d.ts +7 -4
  12. package/dist/components/Icons/IconTypes.d.ts +1 -0
  13. package/dist/components/Image/Image.d.ts +25 -7
  14. package/dist/components/Image/ImageTypes.d.ts +4 -4
  15. package/dist/components/Logo/LogoTypes.d.ts +2 -2
  16. package/dist/components/Notification/Notification.d.ts +4 -4
  17. package/dist/components/Radio/Radio.d.ts +1 -1
  18. package/dist/components/RadioGroup/RadioGroup.d.ts +4 -2
  19. package/dist/components/Select/Select.d.ts +2 -2
  20. package/dist/components/SkeletonLoader/SkeletonLoader.d.ts +4 -3
  21. package/dist/components/SkeletonLoader/SkeletonLoaderTypes.d.ts +0 -4
  22. package/dist/components/StructuredContent/StructuredContent.d.ts +9 -22
  23. package/dist/components/Tabs/Tabs.d.ts +3 -3
  24. package/dist/components/Template/Template.d.ts +13 -5
  25. package/dist/components/Text/Text.d.ts +3 -3
  26. package/dist/components/Text/TextTypes.d.ts +1 -1
  27. package/dist/components/TextInput/TextInput.d.ts +2 -2
  28. package/dist/components/Toggle/Toggle.d.ts +6 -7
  29. package/dist/components/Toggle/{ToggleSizes.d.ts → ToggleTypes.d.ts} +1 -1
  30. package/dist/design-system-react-components.cjs.development.js +505 -422
  31. package/dist/design-system-react-components.cjs.development.js.map +1 -1
  32. package/dist/design-system-react-components.cjs.production.min.js +1 -1
  33. package/dist/design-system-react-components.cjs.production.min.js.map +1 -1
  34. package/dist/design-system-react-components.esm.js +514 -435
  35. package/dist/design-system-react-components.esm.js.map +1 -1
  36. package/dist/helpers/enums.d.ts +4 -0
  37. package/dist/index.d.ts +7 -8
  38. package/dist/theme/components/accordion.d.ts +7 -12
  39. package/dist/theme/components/breadcrumb.d.ts +3 -0
  40. package/dist/theme/components/card.d.ts +4 -4
  41. package/dist/theme/components/checkbox.d.ts +1 -0
  42. package/dist/theme/components/checkboxGroup.d.ts +3 -1
  43. package/dist/theme/components/global.d.ts +2 -1
  44. package/dist/theme/components/hero.d.ts +1 -1
  45. package/dist/theme/components/image.d.ts +1 -1
  46. package/dist/theme/components/notification.d.ts +4 -4
  47. package/dist/theme/components/pagination.d.ts +2 -5
  48. package/dist/theme/components/radio.d.ts +1 -0
  49. package/dist/theme/components/radioGroup.d.ts +3 -1
  50. package/dist/theme/components/select.d.ts +3 -0
  51. package/dist/theme/components/toggle.d.ts +13 -1
  52. package/package.json +1 -1
  53. package/src/components/AccessibilityGuide/SkipNavigation.stories.mdx +34 -0
  54. package/src/components/Accordion/Accordion.stories.mdx +150 -66
  55. package/src/components/Accordion/Accordion.test.tsx +44 -17
  56. package/src/components/Accordion/Accordion.tsx +50 -20
  57. package/src/components/Accordion/AccordionTypes.tsx +5 -0
  58. package/src/components/Accordion/__snapshots__/Accordion.test.tsx.snap +244 -2
  59. package/src/components/Breadcrumbs/Breadcrumbs.stories.mdx +17 -15
  60. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +6 -6
  61. package/src/components/Breadcrumbs/Breadcrumbs.tsx +6 -6
  62. package/src/components/Breadcrumbs/BreadcrumbsTypes.tsx +1 -1
  63. package/src/components/Card/Card.stories.mdx +236 -165
  64. package/src/components/Card/Card.test.tsx +36 -18
  65. package/src/components/Card/Card.tsx +84 -59
  66. package/src/components/Card/__snapshots__/Card.test.tsx.snap +25 -65
  67. package/src/components/Chakra/Center.stories.mdx +2 -2
  68. package/src/components/Checkbox/Checkbox.stories.mdx +13 -1
  69. package/src/components/Checkbox/Checkbox.test.tsx +58 -2
  70. package/src/components/Checkbox/Checkbox.tsx +6 -1
  71. package/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +76 -0
  72. package/src/components/CheckboxGroup/CheckboxGroup.stories.mdx +73 -9
  73. package/src/components/CheckboxGroup/CheckboxGroup.test.tsx +79 -9
  74. package/src/components/CheckboxGroup/CheckboxGroup.tsx +10 -7
  75. package/src/components/CheckboxGroup/__snapshots__/CheckboxGroup.test.tsx.snap +169 -0
  76. package/src/components/ComponentWrapper/ComponentWrapper.tsx +1 -1
  77. package/src/components/DatePicker/DatePicker.test.tsx +5 -2
  78. package/src/components/DatePicker/DatePicker.tsx +5 -2
  79. package/src/components/Form/Form.stories.mdx +47 -9
  80. package/src/components/Form/Form.test.tsx +1 -1
  81. package/src/components/Form/Form.tsx +3 -1
  82. package/src/components/Grid/SimpleGrid.stories.mdx +53 -35
  83. package/src/components/Grid/SimpleGrid.test.tsx +15 -9
  84. package/src/components/Heading/Heading.stories.mdx +21 -23
  85. package/src/components/Heading/Heading.test.tsx +7 -7
  86. package/src/components/Heading/Heading.tsx +10 -14
  87. package/src/components/Heading/HeadingTypes.tsx +1 -1
  88. package/src/components/Heading/__snapshots__/Heading.test.tsx.snap +1 -1
  89. package/src/components/Hero/Hero.stories.mdx +27 -27
  90. package/src/components/Hero/Hero.test.tsx +113 -58
  91. package/src/components/Hero/Hero.tsx +43 -20
  92. package/src/components/HorizontalRule/HorizontalRule.test.tsx +6 -4
  93. package/src/components/HorizontalRule/HorizontalRule.tsx +3 -2
  94. package/src/components/Icons/Icon.stories.mdx +50 -18
  95. package/src/components/Icons/Icon.test.tsx +13 -2
  96. package/src/components/Icons/Icon.tsx +11 -6
  97. package/src/components/Icons/IconTypes.tsx +1 -0
  98. package/src/components/Image/Image.stories.mdx +133 -68
  99. package/src/components/Image/Image.test.tsx +32 -48
  100. package/src/components/Image/Image.tsx +46 -26
  101. package/src/components/Image/ImageTypes.ts +4 -4
  102. package/src/components/Image/__snapshots__/Image.test.tsx.snap +60 -13
  103. package/src/components/Link/Link.tsx +8 -1
  104. package/src/components/List/List.stories.mdx +1 -1
  105. package/src/components/List/List.test.tsx +7 -4
  106. package/src/components/List/List.tsx +7 -4
  107. package/src/components/Logo/Logo.stories.mdx +13 -13
  108. package/src/components/Logo/Logo.test.tsx +12 -2
  109. package/src/components/Logo/Logo.tsx +10 -5
  110. package/src/components/Logo/LogoTypes.tsx +1 -1
  111. package/src/components/Notification/Notification.stories.mdx +5 -5
  112. package/src/components/Notification/Notification.tsx +10 -10
  113. package/src/components/Pagination/Pagination.stories.mdx +4 -3
  114. package/src/components/Pagination/Pagination.test.tsx +30 -2
  115. package/src/components/Pagination/Pagination.tsx +6 -3
  116. package/src/components/ProgressIndicator/ProgressIndicator.stories.mdx +1 -1
  117. package/src/components/ProgressIndicator/ProgressIndicator.test.tsx +6 -2
  118. package/src/components/ProgressIndicator/ProgressIndicator.tsx +3 -1
  119. package/src/components/Radio/Radio.stories.mdx +13 -1
  120. package/src/components/Radio/Radio.test.tsx +56 -2
  121. package/src/components/Radio/Radio.tsx +6 -1
  122. package/src/components/Radio/__snapshots__/Radio.test.tsx.snap +61 -0
  123. package/src/components/RadioGroup/RadioGroup.stories.mdx +73 -9
  124. package/src/components/RadioGroup/RadioGroup.test.tsx +72 -7
  125. package/src/components/RadioGroup/RadioGroup.tsx +10 -7
  126. package/src/components/RadioGroup/__snapshots__/RadioGroup.test.tsx.snap +140 -0
  127. package/src/components/SearchBar/SearchBar.stories.mdx +1 -1
  128. package/src/components/SearchBar/SearchBar.tsx +3 -3
  129. package/src/components/Select/Select.stories.mdx +26 -16
  130. package/src/components/Select/Select.test.tsx +1 -36
  131. package/src/components/Select/Select.tsx +4 -16
  132. package/src/components/SkeletonLoader/SkeletonLoader.stories.mdx +12 -14
  133. package/src/components/SkeletonLoader/SkeletonLoader.test.tsx +6 -8
  134. package/src/components/SkeletonLoader/SkeletonLoader.tsx +5 -7
  135. package/src/components/SkeletonLoader/SkeletonLoaderTypes.tsx +0 -5
  136. package/src/components/Slider/Slider.stories.mdx +41 -8
  137. package/src/components/Slider/Slider.tsx +4 -4
  138. package/src/components/StatusBadge/StatusBadge.test.tsx +3 -1
  139. package/src/components/StatusBadge/StatusBadge.tsx +1 -1
  140. package/src/components/StructuredContent/StructuredContent.stories.mdx +103 -54
  141. package/src/components/StructuredContent/StructuredContent.test.tsx +129 -102
  142. package/src/components/StructuredContent/StructuredContent.tsx +43 -53
  143. package/src/components/StyleGuide/ColorCard.tsx +3 -3
  144. package/src/components/StyleGuide/Typography.stories.mdx +17 -12
  145. package/src/components/Table/Table.test.tsx +1 -1
  146. package/src/components/Table/Table.tsx +3 -1
  147. package/src/components/Tabs/Tabs.stories.mdx +8 -8
  148. package/src/components/Tabs/Tabs.test.tsx +13 -11
  149. package/src/components/Tabs/Tabs.tsx +18 -15
  150. package/src/components/Template/Template.stories.mdx +62 -25
  151. package/src/components/Template/Template.test.tsx +35 -5
  152. package/src/components/Template/Template.tsx +26 -13
  153. package/src/components/Template/__snapshots__/Template.test.tsx.snap +4 -2
  154. package/src/components/Text/Text.stories.mdx +13 -15
  155. package/src/components/Text/Text.test.tsx +6 -15
  156. package/src/components/Text/Text.tsx +7 -12
  157. package/src/components/Text/TextTypes.tsx +1 -1
  158. package/src/components/TextInput/TextInput.stories.mdx +9 -9
  159. package/src/components/TextInput/TextInput.test.tsx +28 -27
  160. package/src/components/TextInput/TextInput.tsx +4 -4
  161. package/src/components/Toggle/Toggle.stories.mdx +12 -22
  162. package/src/components/Toggle/Toggle.test.tsx +15 -2
  163. package/src/components/Toggle/Toggle.tsx +8 -9
  164. package/src/components/Toggle/{ToggleSizes.tsx → ToggleTypes.tsx} +1 -1
  165. package/src/components/Toggle/__snapshots__/Toggle.test.tsx.snap +64 -0
  166. package/src/components/VideoPlayer/VideoPlayer.test.tsx +18 -6
  167. package/src/components/VideoPlayer/VideoPlayer.tsx +14 -7
  168. package/src/docs/{Intro.stories.mdx → Welcome.stories.mdx} +5 -9
  169. package/src/{components/Card/CardTypes.tsx → helpers/enums.ts} +2 -2
  170. package/src/hooks/tests/useNYPLTheme.test.tsx +1 -1
  171. package/src/hooks/useCarouselStyles.stories.mdx +10 -0
  172. package/src/hooks/useNYPLTheme.ts +1 -1
  173. package/src/index.ts +7 -14
  174. package/src/theme/components/accordion.ts +7 -12
  175. package/src/theme/components/breadcrumb.ts +3 -0
  176. package/src/theme/components/card.ts +29 -20
  177. package/src/theme/components/checkboxGroup.ts +3 -1
  178. package/src/theme/components/global.ts +4 -3
  179. package/src/theme/components/hero.ts +1 -1
  180. package/src/theme/components/icon.ts +5 -2
  181. package/src/theme/components/image.ts +1 -1
  182. package/src/theme/components/list.ts +1 -1
  183. package/src/theme/components/notification.ts +5 -5
  184. package/src/theme/components/pagination.ts +2 -5
  185. package/src/theme/components/progressIndicator.ts +3 -3
  186. package/src/theme/components/radioGroup.ts +3 -1
  187. package/src/theme/components/select.ts +6 -0
  188. package/src/theme/components/toggle.ts +26 -3
  189. package/src/utils/componentCategories.ts +27 -19
  190. package/dist/components/Card/CardTypes.d.ts +0 -4
  191. package/dist/components/CheckboxGroup/CheckboxGroupLayoutTypes.d.ts +0 -4
  192. package/dist/components/RadioGroup/RadioGroupLayoutTypes.d.ts +0 -4
  193. package/src/components/CheckboxGroup/CheckboxGroupLayoutTypes.tsx +0 -4
  194. package/src/components/RadioGroup/RadioGroupLayoutTypes.tsx +0 -4
@@ -76,7 +76,7 @@ describe("Table", () => {
76
76
  const warn = jest.spyOn(console, "warn");
77
77
  render(<Table tableData={[]} />);
78
78
  expect(warn).toHaveBeenCalledWith(
79
- "Table: data should be two dimensional array."
79
+ "NYPL Reservoir Table: Data in the `tableData` prop must be a two dimensional array."
80
80
  );
81
81
  });
82
82
 
@@ -91,7 +91,9 @@ function Table(props: React.PropsWithChildren<TableProps>) {
91
91
  tableData.length <= 0 ||
92
92
  tableData[0].constructor !== Array
93
93
  ) {
94
- console.warn("Table: data should be two dimensional array.");
94
+ console.warn(
95
+ "NYPL Reservoir Table: Data in the `tableData` prop must be a two dimensional array."
96
+ );
95
97
  return null;
96
98
  }
97
99
 
@@ -24,12 +24,12 @@ import DSProvider from "../../theme/provider";
24
24
  }}
25
25
  argTypes={{
26
26
  children: { table: { disable: true } },
27
- contentData: { control: false },
28
27
  defaultIndex: {
29
28
  table: { defaultValue: { summary: 0 } },
30
29
  },
31
30
  id: { control: false },
32
31
  onChange: { control: false },
32
+ tabsData: { control: false },
33
33
  useHash: {
34
34
  table: { defaultValue: { summary: false } },
35
35
  },
@@ -41,7 +41,7 @@ import DSProvider from "../../theme/provider";
41
41
  | Component Version | DS Version |
42
42
  | ----------------- | ---------- |
43
43
  | Added | `0.24.0` |
44
- | Latest | `0.25.11` |
44
+ | Latest | `0.25.13` |
45
45
 
46
46
  <Description of={Tabs} />
47
47
 
@@ -95,7 +95,7 @@ export const animalCrossing = [
95
95
  <Story
96
96
  name="Tabs with Controls"
97
97
  args={{
98
- contentData: animalCrossing,
98
+ tabsData: animalCrossing,
99
99
  defaultIndex: 0,
100
100
  id: "tabs-id",
101
101
  onChange: undefined,
@@ -154,12 +154,12 @@ const animalCrossing = [
154
154
  ];
155
155
 
156
156
  // ...
157
- <Tabs contentData={animalCrossing} />;
157
+ <Tabs tabsData={animalCrossing} />;
158
158
  ```
159
159
 
160
160
  ## Responsive Mobile Carousel
161
161
 
162
- For both, the `contentData` prop approach and the children component approach
162
+ For both, the `tabsData` prop approach and the children component approach
163
163
  (described below in this document), the mobile carousel feature is built. This
164
164
  adds "previous" and "next" arrows in the tab list for users to scroll through
165
165
  all the tabs while the panel stays static.
@@ -183,7 +183,7 @@ export const onChange = (value) => {
183
183
  };
184
184
 
185
185
  // ...
186
- <Tabs contentData={animalCrossing} onChange={onChange} />;
186
+ <Tabs tabsData={animalCrossing} onChange={onChange} />;
187
187
  ```
188
188
 
189
189
  export const onChange = (value) => {
@@ -192,7 +192,7 @@ export const onChange = (value) => {
192
192
 
193
193
  <Canvas>
194
194
  <Story name="With Callback Event Function">
195
- <Tabs contentData={animalCrossing} onChange={onChange} />
195
+ <Tabs tabsData={animalCrossing} onChange={onChange} />
196
196
  </Story>
197
197
  </Canvas>
198
198
 
@@ -203,7 +203,7 @@ To enable this, set the `useHash` prop to true.
203
203
 
204
204
  <Canvas>
205
205
  <Story name="With URL Hash Option">
206
- <Tabs contentData={animalCrossing} useHash={true} />
206
+ <Tabs tabsData={animalCrossing} useHash={true} />
207
207
  </Story>
208
208
  </Canvas>
209
209
 
@@ -36,7 +36,7 @@ export const animalCrossing = [
36
36
 
37
37
  describe("Tabs Accessibility", () => {
38
38
  it("passes axe accessibility test with the data prop", async () => {
39
- const { container } = render(<Tabs contentData={animalCrossing} />);
39
+ const { container } = render(<Tabs tabsData={animalCrossing} />);
40
40
  expect(await axe(container)).toHaveNoViolations();
41
41
  });
42
42
 
@@ -121,7 +121,7 @@ describe("Tabs", () => {
121
121
  });
122
122
 
123
123
  it("renders all tabs but only one visible panel at a time with data prop", () => {
124
- render(<Tabs contentData={animalCrossing} />);
124
+ render(<Tabs tabsData={animalCrossing} />);
125
125
  expect(getTabByName("Tom Nook")).toBeInTheDocument();
126
126
  expect(getTabByName("Isabelle")).toBeInTheDocument();
127
127
  expect(getTabByName("K.K. Slider")).toBeInTheDocument();
@@ -137,7 +137,7 @@ describe("Tabs", () => {
137
137
  });
138
138
 
139
139
  it("switches between tabs", () => {
140
- render(<Tabs contentData={animalCrossing} />);
140
+ render(<Tabs tabsData={animalCrossing} />);
141
141
  const isabelleTab = getTabByName("Isabelle");
142
142
  const kkSliderTab = getTabByName("K.K. Slider");
143
143
 
@@ -179,7 +179,7 @@ describe("Tabs", () => {
179
179
  });
180
180
 
181
181
  it("renders the specified initial index value", () => {
182
- render(<Tabs contentData={animalCrossing} defaultIndex={2} />);
182
+ render(<Tabs tabsData={animalCrossing} defaultIndex={2} />);
183
183
  let tomTab = getTabByName("Tom Nook");
184
184
  let isabelleTab = getTabByName("Isabelle");
185
185
  let kkSliderTab = getTabByName("K.K. Slider");
@@ -193,7 +193,7 @@ describe("Tabs", () => {
193
193
  let selectedIndex = 0;
194
194
  const onChange = (index) => (selectedIndex = index);
195
195
 
196
- render(<Tabs contentData={animalCrossing} onChange={onChange} />);
196
+ render(<Tabs tabsData={animalCrossing} onChange={onChange} />);
197
197
 
198
198
  const tomTab = getTabByName("Tom Nook");
199
199
  const isabelleTab = getTabByName("Isabelle");
@@ -213,14 +213,14 @@ describe("Tabs", () => {
213
213
  const warn = jest.spyOn(console, "warn");
214
214
  render(<Tabs />);
215
215
  expect(warn).toHaveBeenCalledWith(
216
- "Tabs: Pass data in the `data` props or as children."
216
+ "NYPL Reservoir Tabs: Pass data in the `contentData` props or as children."
217
217
  );
218
218
  });
219
219
 
220
220
  it("should throw a warning when both the 'data' prop and children are passed", () => {
221
221
  const warn = jest.spyOn(console, "warn");
222
222
  render(
223
- <Tabs contentData={animalCrossing}>
223
+ <Tabs tabsData={animalCrossing}>
224
224
  <TabList>
225
225
  <Tab>Tom Nook</Tab>
226
226
  <Tab>Isabelle</Tab>
@@ -247,7 +247,8 @@ describe("Tabs", () => {
247
247
  </Tabs>
248
248
  );
249
249
  expect(warn).toHaveBeenCalledWith(
250
- "Tabs: Only pass children or data in the `data` props but not both."
250
+ "NYPL Reservoir Tabs: Only pass children or data in the `contentData` " +
251
+ "prop. Do not pass both."
251
252
  );
252
253
  });
253
254
 
@@ -255,7 +256,7 @@ describe("Tabs", () => {
255
256
  const warn = jest.spyOn(console, "warn");
256
257
  render(
257
258
  <Tabs
258
- contentData={[
259
+ tabsData={[
259
260
  ...animalCrossing,
260
261
  ...[
261
262
  { label: "Another character 1", content: "Text" },
@@ -267,13 +268,14 @@ describe("Tabs", () => {
267
268
  />
268
269
  );
269
270
  expect(warn).toHaveBeenCalledWith(
270
- "Tabs: We recommend to use no more than six tabs. If more than six tabs are needed, consider other navigational patterns."
271
+ "NYPL Reservoir Tabs: it is recommended to use no more than six tabs. If " +
272
+ "more than six tabs are needed, consider other navigational patterns."
271
273
  );
272
274
  });
273
275
 
274
276
  it("renders the UI snapshot correctly", () => {
275
277
  const basic = renderer
276
- .create(<Tabs contentData={animalCrossing} id="basic" />)
278
+ .create(<Tabs tabsData={animalCrossing} id="basic" />)
277
279
  .toJSON();
278
280
  expect(basic).toMatchSnapshot();
279
281
  });
@@ -24,20 +24,20 @@ interface TabPanelProps {
24
24
  panels: React.ReactNode[] | React.ReactNode;
25
25
  }
26
26
  // The general shape of the data object for each Tab.
27
- export interface TabsContentDataProps {
27
+ export interface TabsDataProps {
28
28
  label: string;
29
29
  content: string | React.ReactNode;
30
30
  }
31
31
 
32
32
  export interface TabsProps {
33
- /** Array of data to display */
34
- contentData?: TabsContentDataProps[];
35
33
  /** The index of the tab to display for controlled situations. */
36
34
  defaultIndex?: number;
37
35
  /** ID that other components can cross reference for accessibility purposes */
38
36
  id?: string;
39
37
  /** The callback function invoked on every tab change event. */
40
38
  onChange?: (index: number) => any;
39
+ /** Array of data to display */
40
+ tabsData?: TabsDataProps[];
41
41
  /** Render a hash in the url for each tab. Only available when data is
42
42
  * passed through the `data` props. */
43
43
  useHash?: boolean;
@@ -55,7 +55,7 @@ const onClickHash = (tabHash) => {
55
55
  * This returns an object with `Tab` and `TabPanel` components to rendered in
56
56
  * `TabList` and `TabPanels` components respectively.
57
57
  */
58
- const getElementsFromContentData = (data, useHash): TabPanelProps => {
58
+ const getElementsFromData = (data, useHash): TabPanelProps => {
59
59
  const tabs = [];
60
60
  const panels = [];
61
61
 
@@ -65,8 +65,8 @@ const getElementsFromContentData = (data, useHash): TabPanelProps => {
65
65
 
66
66
  if (data?.length > 6) {
67
67
  console.warn(
68
- "Tabs: We recommend to use no more than six tabs. If more than six tabs " +
69
- "are needed, consider other navigational patterns."
68
+ "NYPL Reservoir Tabs: it is recommended to use no more than six tabs. If " +
69
+ "more than six tabs are needed, consider other navigational patterns."
70
70
  );
71
71
  }
72
72
  data.forEach((tab, index) => {
@@ -121,8 +121,8 @@ const getElementsFromChildren = (children): TabPanelProps => {
121
121
  const childTabs = React.Children.count(child.props.children);
122
122
  if (childTabs > 6) {
123
123
  console.warn(
124
- "Tabs: We recommend to use no more than six tabs. If more than six " +
125
- "tabs are needed, consider other navigational patterns."
124
+ "NYPL Reservoir Tabs: It is recommended to use no more than six tabs. " +
125
+ "If more than six tabs are needed, consider other navigational patterns."
126
126
  );
127
127
  }
128
128
  }
@@ -142,10 +142,10 @@ const getElementsFromChildren = (children): TabPanelProps => {
142
142
  function Tabs(props: React.PropsWithChildren<TabsProps>) {
143
143
  const {
144
144
  children,
145
- contentData,
146
145
  defaultIndex = 0,
147
146
  id = generateUUID(),
148
147
  onChange,
148
+ tabsData,
149
149
  useHash = false,
150
150
  } = props;
151
151
  const styles = useMultiStyleConfig("Tabs", {});
@@ -155,16 +155,18 @@ function Tabs(props: React.PropsWithChildren<TabsProps>) {
155
155
  const mediumTabWidth = 40;
156
156
  const [tabWidth, setTabWidth] = React.useState(initTabWidth);
157
157
  const windowDimensions = useWindowSize();
158
- const { tabs, panels }: any = contentData
159
- ? getElementsFromContentData(contentData, useHash)
158
+ const { tabs, panels }: any = tabsData
159
+ ? getElementsFromData(tabsData, useHash)
160
160
  : getElementsFromChildren(children);
161
161
 
162
162
  if (tabs.length === 0 || panels.length === 0) {
163
- console.warn("Tabs: Pass data in the `data` props or as children.");
163
+ console.warn(
164
+ "NYPL Reservoir Tabs: Pass data in the `contentData` props or as children."
165
+ );
164
166
  }
165
167
 
166
168
  // `tabs` is an array for the children component approach but an object for
167
- // the `contentData` prop approach. We need to get the right props key value
169
+ // the `tabsData` prop approach. We need to get the right props key value
168
170
  // to set the carousel's length.
169
171
  const tabProps = tabs[0] ? tabs[0]?.props : (tabs as any).props;
170
172
  const { prevSlide, nextSlide, carouselStyle, goToStart } = useCarouselStyles(
@@ -221,9 +223,10 @@ function Tabs(props: React.PropsWithChildren<TabsProps>) {
221
223
  </Button>
222
224
  );
223
225
 
224
- if (children && contentData?.length) {
226
+ if (children && tabsData?.length) {
225
227
  console.warn(
226
- "Tabs: Only pass children or data in the `data` props but not both."
228
+ "NYPL Reservoir Tabs: Only pass children or data in the `contentData` " +
229
+ "prop. Do not pass both."
227
230
  );
228
231
  }
229
232
 
@@ -60,7 +60,44 @@ import { getCategory } from "../../utils/componentCategories";
60
60
  | Component Version | DS Version |
61
61
  | ----------------- | ---------- |
62
62
  | Added | `0.3.6` |
63
- | Latest | `0.25.12` |
63
+ | Latest | `0.25.13` |
64
+
65
+ ## Table of Contents
66
+
67
+ - [Accessibility for TemplateAppContainer](#accessibility-for-templateappcontainer)
68
+ - [TemplateAppContainer Component](#templateappcontainer-component)
69
+ - [TemplateAppContainer Props](#templateappcontainer-props)
70
+ - [Template Children Components](#template-children-components)
71
+ - [Template Children Props](#template-children-props)
72
+ - [Full Example with Template Children Components](#full-example-with-template-children-components)
73
+
74
+ ## Accessibility
75
+
76
+ **The `TemplateAppContainer` component is the recommended way to render the entire
77
+ application.** Therefore, this accessibility section is specifically for the
78
+ `TemplateAppContainer` but the same rules apply to the individual "Template"
79
+ components.
80
+
81
+ If you need to render an alert or notification at the top of the page with an
82
+ `aside` HTML element or HTML element with the `role="complementary"` attribute,
83
+ then pass that alert or notification component to the `aboveHeader` prop. These
84
+ elements should _not_ be rendered in the `header` HTML section since that's an
85
+ accessibility violation.
86
+
87
+ The `TemplateAppContainer` component renders a full DOM and one of the children
88
+ is the `main` HTML element with a default "id" of `"mainContent"`. This should
89
+ be used as the anchor element that the skip navigation link points to. As of
90
+ v0.25.13, the consuming application is responsible for adding the skip
91
+ navigation feature to the application. If your application is using the current
92
+ NYPL Header, it already contains the skip navigation feature but make sure it is
93
+ pointing to the correct anchor element.
94
+
95
+ Resources
96
+
97
+ - [W3C Aria Landmarks Example](https://www.w3.org/TR/wai-aria-practices/examples/landmarks/complementary.html)
98
+ - [Digital A11y Role=Complementary](https://www.digitala11y.com/complementary-role/)
99
+ - [WebAim Skip Navigation Link](https://webaim.org/techniques/skipnav/)
100
+ - [A11ymatters Skip Navigation Link](https://www.a11ymatters.com/pattern/skip-link/)
64
101
 
65
102
  ## TemplateAppContainer Component
66
103
 
@@ -74,13 +111,7 @@ Likewise, if you have a custom `Footer` component that _already_ renders an HTML
74
111
  `<footer>` element, set `renderFooterElement` to false so only one `<footer>`
75
112
  element is rendered.
76
113
 
77
- If you need to render an alert or notification at the top of the page with an
78
- `aside` HTML element or HTML element with the `role="complementary"` attribute,
79
- then pass that alert or notification component to the `aboveHeader` prop. These
80
- elements should _not_ be rendered in the `header` HTML section since that's an
81
- accessibility violation.
82
-
83
- <b>This is the recommended way to render an app page template.</b>
114
+ **This is the recommended way to render an app page template.**
84
115
 
85
116
  ```jsx
86
117
  import { TemplateAppContainer } from "@nypl/design-system-react-components";
@@ -107,6 +138,8 @@ import { TemplateAppContainer } from "@nypl/design-system-react-components";
107
138
  />;
108
139
  ```
109
140
 
141
+ ## TemplateAppContainer Props
142
+
110
143
  <Canvas>
111
144
  <Story
112
145
  name="TemplateAppContainer Component"
@@ -124,6 +157,7 @@ import { TemplateAppContainer } from "@nypl/design-system-react-components";
124
157
  <Placeholder variant="short">More Content</Placeholder>
125
158
  </>
126
159
  ),
160
+ contentId: "mainContent",
127
161
  contentSidebar: <Placeholder>Left Sidebar</Placeholder>,
128
162
  contentTop: <Placeholder>Content Top</Placeholder>,
129
163
  footer: <Placeholder variant="short">Footer</Placeholder>,
@@ -203,6 +237,8 @@ import {
203
237
  </Template>
204
238
  ```
205
239
 
240
+ ## Template Children Props
241
+
206
242
  <Canvas>
207
243
  <Story
208
244
  name="Template Children Components"
@@ -212,6 +248,7 @@ import {
212
248
  argTypes={{
213
249
  aboveHeader: { table: { disable: true } },
214
250
  breakout: { table: { disable: true } },
251
+ contentId: { table: { disable: true } },
215
252
  contentPrimary: { table: { disable: true } },
216
253
  contentSidebar: { table: { disable: true } },
217
254
  contentTop: { table: { disable: true } },
@@ -334,7 +371,7 @@ The components consist of:
334
371
  ```
335
372
  <Template>
336
373
  <TemplateHeader>...</TemplateHeader>
337
- <TemplateContent sidebar="left">
374
+ <TemplateContent id="mainContent" sidebar="left">
338
375
  // ...
339
376
  </TemplateContent>
340
377
  <Template>
@@ -513,18 +550,14 @@ This is best viewed in the Storybook "Canvas" and not "Docs" section.
513
550
  ]}
514
551
  />
515
552
  <Hero
553
+ backgroundImageSrc="https://placeimg.com/2400/800/nature/grayscale"
516
554
  heroType={HeroTypes.Campaign}
517
555
  heading={
518
556
  <Heading level={HeadingLevels.One} id="1" text="Hero Campaign" />
519
557
  }
558
+ imageAlt="Image example"
559
+ imageSrc="https://placeimg.com/800/400/animals"
520
560
  subHeaderText={otherSubHeaderText}
521
- backgroundImageSrc="https://placeimg.com/2400/800/nature/grayscale"
522
- image={
523
- <Image
524
- src="https://placeimg.com/800/400/animals"
525
- alt="Image example"
526
- />
527
- }
528
561
  />
529
562
  </TemplateBreakout>
530
563
  </TemplateHeader>
@@ -547,7 +580,7 @@ This is best viewed in the Storybook "Canvas" and not "Docs" section.
547
580
  </TemplateContentTop>
548
581
  <TemplateContentPrimary>
549
582
  <p>This is the main content!</p>
550
- <Accordion contentData={faqContent} />
583
+ <Accordion accordionData={faqContent} />
551
584
  <HorizontalRule />
552
585
  <p>Fill out the form!</p>
553
586
  <Form action="/end/point">
@@ -584,11 +617,13 @@ This is best viewed in the Storybook "Canvas" and not "Docs" section.
584
617
  <TemplateContentSidebar>
585
618
  <p>Sidebar information in a `Card` component.</p>
586
619
  <Card
587
- center
588
- imageSrc="https://placeimg.com/400/200/animals"
589
- imageAlt="Alt text"
590
- imageAspectRatio={ImageRatios.Square}
591
- imageSize={ImageSizes.Small}
620
+ imageProps={{
621
+ alt: "Alt text",
622
+ aspectRatio: ImageRatios.Square,
623
+ size: ImageSizes.Small,
624
+ src: "https://placeimg.com/400/200/animals",
625
+ }}
626
+ isCentered
592
627
  >
593
628
  <CardHeading level={HeadingLevels.Two} id="heading1">
594
629
  Small Animal Image
@@ -606,9 +641,11 @@ This is best viewed in the Storybook "Canvas" and not "Docs" section.
606
641
  <TemplateFooter>
607
642
  <Card
608
643
  id="custom-card"
609
- imageAlt="Alt text"
610
- imageSrc="https://cdn-d8.nypl.org/s3fs-public/2020-05/NYPL_MainFacadeRev2Cam2.png"
611
- imageAspectRatio={ImageRatios.SixteenByNine}
644
+ imageProps={{
645
+ alt: "Alt text",
646
+ aspectRatio: ImageRatios.SixteenByNine,
647
+ src: "https://cdn-d8.nypl.org/s3fs-public/2020-05/NYPL_MainFacadeRev2Cam2.png",
648
+ }}
612
649
  layout="horizontal"
613
650
  backgroundColor="#616161"
614
651
  foregroundColor="#FFF"
@@ -100,6 +100,23 @@ describe("TemplateAppContainer component", () => {
100
100
  expect(screen.getByText("Footer")).toBeInTheDocument();
101
101
  });
102
102
 
103
+ it("renders a #mainContent id in the `main` DOM element", () => {
104
+ const { container } = render(
105
+ <TemplateAppContainer
106
+ aboveHeader={aboveHeader}
107
+ header={header}
108
+ breakout={breakout}
109
+ sidebar={sidebar}
110
+ contentTop={contentTop}
111
+ contentSidebar={contentSidebar}
112
+ contentPrimary={contentPrimary}
113
+ footer={footer}
114
+ />
115
+ );
116
+ expect(container.querySelector("#mainContent")).toBeInTheDocument();
117
+ expect(screen.getByRole("main")).toHaveAttribute("id", "mainContent");
118
+ });
119
+
103
120
  it("renders only one header in a custom header component", () => {
104
121
  const customHeader = <header>Custom header</header>;
105
122
  render(
@@ -134,8 +151,9 @@ describe("TemplateAppContainer component", () => {
134
151
  />
135
152
  );
136
153
  expect(warn).toHaveBeenCalledWith(
137
- "`TemplateHeader`: An HTML `header` element was passed in. Set " +
138
- "`renderHeaderElement` to `false` to avoid nested HTML `header` elements."
154
+ "NYPL Reservoir TemplateHeader: An HTML `header` element was passed " +
155
+ "in. Set `renderHeaderElement` to `false` to avoid nested HTML " +
156
+ "`header` elements."
139
157
  );
140
158
  });
141
159
 
@@ -172,8 +190,9 @@ describe("TemplateAppContainer component", () => {
172
190
  />
173
191
  );
174
192
  expect(warn).toHaveBeenCalledWith(
175
- "`TemplateFooter`: An HTML `footer` element was passed in. Set " +
176
- "`renderFooterElement` to `false` to avoid nested HTML `footer` elements."
193
+ "NYPL Reservoir TemplateFooter: An HTML `footer` element was passed " +
194
+ "in. Set `renderFooterElement` to `false` to avoid nested HTML " +
195
+ "`footer` elements."
177
196
  );
178
197
  });
179
198
  });
@@ -207,7 +226,18 @@ describe("Template components", () => {
207
226
  expect(screen.getByText("Footer")).toBeInTheDocument();
208
227
  });
209
228
 
210
- it("Renders the UI snapshot correctly", () => {
229
+ it("renders a #mainContent id in the TemplateContent component", () => {
230
+ const { container } = render(
231
+ <TemplateContent>
232
+ <TemplateContentPrimary>{contentPrimary}</TemplateContentPrimary>
233
+ </TemplateContent>
234
+ );
235
+
236
+ expect(container.querySelector("#mainContent")).toBeInTheDocument();
237
+ expect(screen.getByRole("main")).toHaveAttribute("id", "mainContent");
238
+ });
239
+
240
+ it("renders the UI snapshot correctly", () => {
211
241
  const templateComponents = renderer
212
242
  .create(
213
243
  <Template>
@@ -15,7 +15,12 @@ export interface TemplateSidebarProps {
15
15
  * right side of the `TemplateContentPrimary` component. */
16
16
  sidebar?: "none" | "left" | "right";
17
17
  }
18
- export interface TemplateContentProps extends TemplateSidebarProps {}
18
+ export interface TemplateContentProps extends TemplateSidebarProps {
19
+ /** ID used for the `main` HTML element. Defaults to "mainContent". Useful
20
+ * anchor for the application skip navigation. */
21
+ id?: string;
22
+ }
23
+
19
24
  export interface TemplateAppContainerProps
20
25
  extends TemplateFooterProps,
21
26
  TemplateHeaderProps,
@@ -25,6 +30,9 @@ export interface TemplateAppContainerProps
25
30
  aboveHeader?: React.ReactElement;
26
31
  /** DOM that will be rendered in the `TemplateBreakout` component section. */
27
32
  breakout?: React.ReactElement;
33
+ /** ID used for the `main` HTML element. Defaults to "mainContent". Useful
34
+ * anchor for the application skip navigation. */
35
+ contentId?: string;
28
36
  /** DOM that will be rendered in the `TemplateContentPrimary` component section. */
29
37
  contentPrimary?: React.ReactElement;
30
38
  /** DOM that will be rendered in the `TemplateContentSidebar` component section. */
@@ -80,8 +88,9 @@ const TemplateHeader = ({
80
88
  React.Children.map(children, (child: React.ReactElement) => {
81
89
  if (child?.type === "header" || child?.props?.mdxType === "header") {
82
90
  console.warn(
83
- "`TemplateHeader`: An HTML `header` element was passed in. Set " +
84
- "`renderHeaderElement` to `false` to avoid nested HTML `header` elements."
91
+ "NYPL Reservoir TemplateHeader: An HTML `header` element was passed " +
92
+ "in. Set `renderHeaderElement` to `false` to avoid nested HTML " +
93
+ "`header` elements."
85
94
  );
86
95
  }
87
96
  });
@@ -106,16 +115,18 @@ const TemplateBreakout = (props: React.PropsWithChildren<TemplateProps>) => {
106
115
 
107
116
  /**
108
117
  * This component is most useful to render content on the page. This renders an
109
- * HTML `<main>` element and takes a `sidebar` prop with optional "left" or
110
- * "right" values. This will set the correct styling needed for the
111
- * `TemplateContentPrimary` and `TemplateContentSidebar` components. Note that
112
- * `TemplateContentPrimary` and `TemplateContentSidebar` must be ordered
113
- * correctly as children elements for the appropriate styles to take effect.
118
+ * HTML `<main>` element with an id of "mainContent". The "mainContent" id should
119
+ * be used as the consuming application's skip navigation link. The `TemplateContent`
120
+ * component also takes a `sidebar` prop with optional "left" or "right" values.
121
+ * This will set the correct *styling* needed for the `TemplateContentPrimary`
122
+ * and `TemplateContentSidebar` components. Note that `TemplateContentPrimary`
123
+ * and `TemplateContentSidebar` must be ordered correctly as children elements
124
+ * for the appropriate styles to take effect.
114
125
  */
115
126
  const TemplateContent = (
116
127
  props: React.PropsWithChildren<TemplateContentProps>
117
128
  ) => {
118
- const { sidebar = "none", children } = props;
129
+ const { children, id = "mainContent", sidebar = "none" } = props;
119
130
  const styles = useStyleConfig("TemplateContent", {
120
131
  variant: sidebar !== "none" ? "sidebar" : null,
121
132
  });
@@ -139,7 +150,7 @@ const TemplateContent = (
139
150
  );
140
151
 
141
152
  return (
142
- <Box as="main" __css={styles}>
153
+ <Box as="main" id={id} __css={styles}>
143
154
  {newChildren}
144
155
  </Box>
145
156
  );
@@ -212,8 +223,9 @@ const TemplateFooter = ({
212
223
  React.Children.map(children, (child: React.ReactElement) => {
213
224
  if (child?.type === "footer" || child?.props?.mdxType === "footer") {
214
225
  console.warn(
215
- "`TemplateFooter`: An HTML `footer` element was passed in. Set " +
216
- "`renderFooterElement` to `false` to avoid nested HTML `footer` elements."
226
+ "NYPL Reservoir TemplateFooter: An HTML `footer` element was passed " +
227
+ "in. Set `renderFooterElement` to `false` to avoid nested HTML " +
228
+ "`footer` elements."
217
229
  );
218
230
  }
219
231
  });
@@ -235,6 +247,7 @@ const TemplateAppContainer = (
235
247
  const {
236
248
  aboveHeader,
237
249
  breakout,
250
+ contentId = "mainContent",
238
251
  contentPrimary,
239
252
  contentSidebar,
240
253
  contentTop,
@@ -270,7 +283,7 @@ const TemplateAppContainer = (
270
283
  )}
271
284
  {/* Note that setting `sidebar` as a prop here affects the
272
285
  TemplateContentSidebar and TemplateContentPrimary components. */}
273
- <TemplateContent sidebar={sidebar}>
286
+ <TemplateContent id={contentId} sidebar={sidebar}>
274
287
  {contentTopElem}
275
288
 
276
289
  {sidebar === "left" && contentSidebarElem}
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`Template components Renders the UI snapshot correctly 1`] = `
3
+ exports[`Template components renders the UI snapshot correctly 1`] = `
4
4
  <div
5
5
  className="css-0"
6
6
  >
@@ -38,6 +38,7 @@ exports[`Template components Renders the UI snapshot correctly 1`] = `
38
38
  </header>
39
39
  <main
40
40
  className="css-0"
41
+ id="mainContent"
41
42
  >
42
43
  <div
43
44
  className="css-0"
@@ -84,7 +85,7 @@ exports[`Template components Renders the UI snapshot correctly 1`] = `
84
85
  </div>
85
86
  `;
86
87
 
87
- exports[`Template components Renders the UI snapshot correctly 2`] = `
88
+ exports[`Template components renders the UI snapshot correctly 2`] = `
88
89
  <div
89
90
  className="css-0"
90
91
  >
@@ -122,6 +123,7 @@ exports[`Template components Renders the UI snapshot correctly 2`] = `
122
123
  </header>
123
124
  <main
124
125
  className="css-0"
126
+ id="mainContent"
125
127
  >
126
128
  <div
127
129
  className="css-0"