@nypl/design-system-react-components 0.25.9 → 0.25.10

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 (78) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/components/DatePicker/DatePicker.d.ts +1 -1
  3. package/dist/components/Fieldset/Fieldset.d.ts +1 -3
  4. package/dist/components/Form/Form.d.ts +13 -12
  5. package/dist/components/Form/FormTypes.d.ts +2 -2
  6. package/dist/components/HorizontalRule/HorizontalRule.d.ts +1 -1
  7. package/dist/components/RadioGroup/RadioGroup.d.ts +3 -3
  8. package/dist/components/SearchBar/SearchBar.d.ts +5 -5
  9. package/dist/components/Table/Table.d.ts +9 -3
  10. package/dist/components/Template/Template.d.ts +23 -4
  11. package/dist/design-system-react-components.cjs.development.js +197 -89
  12. package/dist/design-system-react-components.cjs.development.js.map +1 -1
  13. package/dist/design-system-react-components.cjs.production.min.js +1 -1
  14. package/dist/design-system-react-components.cjs.production.min.js.map +1 -1
  15. package/dist/design-system-react-components.esm.js +186 -91
  16. package/dist/design-system-react-components.esm.js.map +1 -1
  17. package/dist/index.d.ts +4 -4
  18. package/dist/resources.scss +0 -2
  19. package/dist/theme/components/breadcrumb.d.ts +1 -1
  20. package/dist/theme/components/customTable.d.ts +12 -3
  21. package/package.json +40 -36
  22. package/src/components/Accordion/Accordion.stories.mdx +1 -1
  23. package/src/components/Accordion/Accordion.test.tsx +45 -1
  24. package/src/components/Accordion/Accordion.tsx +20 -8
  25. package/src/components/Accordion/__snapshots__/Accordion.test.tsx.snap +243 -0
  26. package/src/components/Breadcrumbs/Breadcrumbs.stories.mdx +13 -2
  27. package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +15 -0
  28. package/src/components/Breadcrumbs/Breadcrumbs.tsx +9 -3
  29. package/src/components/Breadcrumbs/__snapshots__/Breadcrumbs.test.tsx.snap +5 -5
  30. package/src/components/Card/Card.stories.mdx +1 -1
  31. package/src/components/Card/Card.tsx +4 -1
  32. package/src/components/Chakra/Flex.stories.mdx +113 -0
  33. package/src/components/DatePicker/DatePicker.stories.mdx +1 -1
  34. package/src/components/DatePicker/DatePicker.test.tsx +6 -6
  35. package/src/components/DatePicker/DatePicker.tsx +3 -4
  36. package/src/components/Fieldset/Fieldset.stories.mdx +1 -1
  37. package/src/components/Fieldset/Fieldset.tsx +2 -4
  38. package/src/components/Form/Form.stories.mdx +34 -16
  39. package/src/components/Form/Form.test.tsx +92 -3
  40. package/src/components/Form/Form.tsx +25 -21
  41. package/src/components/Form/FormTypes.tsx +2 -2
  42. package/src/components/Form/__snapshots__/Form.test.tsx.snap +0 -1
  43. package/src/components/Hero/Hero.stories.mdx +1 -1
  44. package/src/components/HorizontalRule/HorizontalRule.stories.mdx +3 -2
  45. package/src/components/HorizontalRule/HorizontalRule.tsx +2 -2
  46. package/src/components/HorizontalRule/__snapshots__/HorizontalRule.test.tsx.snap +4 -4
  47. package/src/components/List/List.stories.mdx +1 -1
  48. package/src/components/List/List.tsx +1 -1
  49. package/src/components/Pagination/Pagination.stories.mdx +1 -1
  50. package/src/components/Pagination/Pagination.tsx +2 -2
  51. package/src/components/Radio/__snapshots__/Radio.test.tsx.snap +5 -5
  52. package/src/components/RadioGroup/RadioGroup.stories.mdx +1 -1
  53. package/src/components/RadioGroup/RadioGroup.test.tsx +13 -11
  54. package/src/components/RadioGroup/RadioGroup.tsx +88 -89
  55. package/src/components/RadioGroup/__snapshots__/RadioGroup.test.tsx.snap +18 -18
  56. package/src/components/SearchBar/SearchBar.Test.tsx +106 -28
  57. package/src/components/SearchBar/SearchBar.stories.mdx +7 -4
  58. package/src/components/SearchBar/SearchBar.tsx +19 -20
  59. package/src/components/Select/Select.test.tsx +89 -0
  60. package/src/components/Select/Select.tsx +7 -1
  61. package/src/components/Select/__snapshots__/Select.test.tsx.snap +545 -0
  62. package/src/components/Slider/__snapshots__/Slider.test.tsx.snap +7 -0
  63. package/src/components/Table/Table.stories.mdx +118 -19
  64. package/src/components/Table/Table.test.tsx +80 -3
  65. package/src/components/Table/Table.tsx +26 -16
  66. package/src/components/Table/__snapshots__/Table.test.tsx.snap +1179 -0
  67. package/src/components/Tabs/Tabs.stories.mdx +1 -1
  68. package/src/components/Tabs/Tabs.test.tsx +21 -5
  69. package/src/components/Tabs/Tabs.tsx +33 -18
  70. package/src/components/Tabs/__snapshots__/Tabs.test.tsx.snap +195 -0
  71. package/src/components/Template/Template.stories.mdx +79 -4
  72. package/src/components/Template/Template.test.tsx +65 -3
  73. package/src/components/Template/Template.tsx +58 -8
  74. package/src/components/Template/__snapshots__/Template.test.tsx.snap +93 -0
  75. package/src/index.ts +8 -2
  76. package/src/theme/components/breadcrumb.ts +1 -1
  77. package/src/theme/components/customTable.ts +16 -3
  78. package/src/utils/componentCategories.ts +1 -0
@@ -5,6 +5,7 @@ import renderer from "react-test-renderer";
5
5
 
6
6
  import {
7
7
  Template,
8
+ TemplateAboveHeader,
8
9
  TemplateHeader,
9
10
  TemplateBreakout,
10
11
  TemplateContent,
@@ -16,6 +17,7 @@ import {
16
17
  } from "./Template";
17
18
  import Placeholder from "../Placeholder/Placeholder";
18
19
 
20
+ const aboveHeader = <Placeholder variant="short">Above Header</Placeholder>;
19
21
  const header = <Placeholder variant="short">NYPL Header</Placeholder>;
20
22
  const breakout = (
21
23
  <>
@@ -38,6 +40,7 @@ describe("TemplateAppContainer accessibility", () => {
38
40
  it("passes axe accessibility test", async () => {
39
41
  const { container } = render(
40
42
  <TemplateAppContainer
43
+ aboveHeader={aboveHeader}
41
44
  header={header}
42
45
  breakout={breakout}
43
46
  sidebar={sidebar}
@@ -55,6 +58,7 @@ describe("Template components accessibility", () => {
55
58
  it("passes axe accessibility test", async () => {
56
59
  const { container } = render(
57
60
  <Template>
61
+ <TemplateAboveHeader>{aboveHeader}</TemplateAboveHeader>
58
62
  <TemplateHeader>
59
63
  {header}
60
64
  <TemplateBreakout>{breakout}</TemplateBreakout>
@@ -75,6 +79,7 @@ describe("TemplateAppContainer component", () => {
75
79
  it("renders each section", () => {
76
80
  render(
77
81
  <TemplateAppContainer
82
+ aboveHeader={aboveHeader}
78
83
  header={header}
79
84
  breakout={breakout}
80
85
  sidebar={sidebar}
@@ -84,7 +89,7 @@ describe("TemplateAppContainer component", () => {
84
89
  footer={footer}
85
90
  />
86
91
  );
87
-
92
+ expect(screen.getByText("Above Header")).toBeInTheDocument();
88
93
  expect(screen.getByText("NYPL Header")).toBeInTheDocument();
89
94
  expect(screen.getByText("Breadcrumbs")).toBeInTheDocument();
90
95
  expect(screen.getByText("Hero")).toBeInTheDocument();
@@ -95,6 +100,45 @@ describe("TemplateAppContainer component", () => {
95
100
  expect(screen.getByText("Footer")).toBeInTheDocument();
96
101
  });
97
102
 
103
+ it("renders only one header in a custom header component", () => {
104
+ const customHeader = <header>Custom header</header>;
105
+ render(
106
+ <TemplateAppContainer
107
+ header={customHeader}
108
+ renderHeaderElement={false}
109
+ breakout={breakout}
110
+ sidebar={sidebar}
111
+ contentTop={contentTop}
112
+ contentSidebar={contentSidebar}
113
+ contentPrimary={contentPrimary}
114
+ footer={footer}
115
+ />
116
+ );
117
+
118
+ // The `<header>` HTML element has the same meaning as `role="banner"`.
119
+ expect(screen.getAllByRole("banner")).toHaveLength(1);
120
+ });
121
+
122
+ it("consoles a warning when a header element was passed without setting `renderHeaderElement` to false", () => {
123
+ const warn = jest.spyOn(console, "warn");
124
+ const customHeader = <header>Custom header</header>;
125
+ render(
126
+ <TemplateAppContainer
127
+ header={customHeader}
128
+ breakout={breakout}
129
+ sidebar={sidebar}
130
+ contentTop={contentTop}
131
+ contentSidebar={contentSidebar}
132
+ contentPrimary={contentPrimary}
133
+ footer={footer}
134
+ />
135
+ );
136
+ expect(warn).toHaveBeenCalledWith(
137
+ "`TemplateHeader`: An HTML `header` element was passed in. Set " +
138
+ "`renderHeaderElement` to `false` to avoid nested HTML `header` elements."
139
+ );
140
+ });
141
+
98
142
  it("renders only one footer in a custom footer component", () => {
99
143
  const customFooter = <footer>Custom Footer</footer>;
100
144
  render(
@@ -138,6 +182,7 @@ describe("Template components", () => {
138
182
  it("renders each section", () => {
139
183
  render(
140
184
  <Template>
185
+ <TemplateAboveHeader>{aboveHeader}</TemplateAboveHeader>
141
186
  <TemplateHeader>
142
187
  {header}
143
188
  <TemplateBreakout>{breakout}</TemplateBreakout>
@@ -151,6 +196,7 @@ describe("Template components", () => {
151
196
  </Template>
152
197
  );
153
198
 
199
+ expect(screen.getByText("Above Header")).toBeInTheDocument();
154
200
  expect(screen.getByText("NYPL Header")).toBeInTheDocument();
155
201
  expect(screen.getByText("Breadcrumbs")).toBeInTheDocument();
156
202
  expect(screen.getByText("Hero")).toBeInTheDocument();
@@ -162,9 +208,10 @@ describe("Template components", () => {
162
208
  });
163
209
 
164
210
  it("Renders the UI snapshot correctly", () => {
165
- const basic = renderer
211
+ const templateComponents = renderer
166
212
  .create(
167
213
  <Template>
214
+ <TemplateAboveHeader>{aboveHeader}</TemplateAboveHeader>
168
215
  <TemplateHeader>
169
216
  {header}
170
217
  <TemplateBreakout>{breakout}</TemplateBreakout>
@@ -178,7 +225,22 @@ describe("Template components", () => {
178
225
  </Template>
179
226
  )
180
227
  .toJSON();
228
+ const singleComponent = renderer
229
+ .create(
230
+ <TemplateAppContainer
231
+ aboveHeader={aboveHeader}
232
+ header={header}
233
+ breakout={breakout}
234
+ sidebar={sidebar}
235
+ contentTop={contentTop}
236
+ contentSidebar={contentSidebar}
237
+ contentPrimary={contentPrimary}
238
+ footer={footer}
239
+ />
240
+ )
241
+ .toJSON();
181
242
 
182
- expect(basic).toMatchSnapshot();
243
+ expect(templateComponents).toMatchSnapshot();
244
+ expect(singleComponent).toMatchSnapshot();
183
245
  });
184
246
  });
@@ -2,6 +2,10 @@ import * as React from "react";
2
2
  import { Box, useStyleConfig } from "@chakra-ui/react";
3
3
 
4
4
  export interface TemplateProps {}
5
+ export interface TemplateHeaderProps {
6
+ /** Flag to render an HTML header element. True by default. */
7
+ renderHeaderElement?: boolean;
8
+ }
5
9
  export interface TemplateFooterProps {
6
10
  /** Flag to render an HTML footer element. True by default. */
7
11
  renderFooterElement?: boolean;
@@ -14,7 +18,11 @@ export interface TemplateSidebarProps {
14
18
  export interface TemplateContentProps extends TemplateSidebarProps {}
15
19
  export interface TemplateAppContainerProps
16
20
  extends TemplateFooterProps,
21
+ TemplateHeaderProps,
17
22
  TemplateSidebarProps {
23
+ /** DOM that will be rendered before the rest of the components in
24
+ * `TemplateAppContainer` and immediately before the `TemplateHeader` component. */
25
+ aboveHeader?: React.ReactElement;
18
26
  /** DOM that will be rendered in the `TemplateBreakout` component section. */
19
27
  breakout?: React.ReactElement;
20
28
  /** DOM that will be rendered in the `TemplateContentPrimary` component section. */
@@ -42,17 +50,52 @@ const Template = (props: React.PropsWithChildren<TemplateProps>) => {
42
50
  );
43
51
  };
44
52
 
53
+ /**
54
+ * This optional component renders its children from edge-to-edge and should
55
+ * be used for alerts or notifications that are typically site-wide. This must
56
+ * be rendered immediately before the `TemplateHeader` component. This is meant
57
+ * for components that render an `aside` HTML element or HTML element with the
58
+ * `role="complementary"` attribute. These elements should *not* be rendered
59
+ * in the `header` HTML section since that's an accessibility violation.
60
+ */
61
+ const TemplateAboveHeader = (props: React.PropsWithChildren<TemplateProps>) => {
62
+ const styles = useStyleConfig("TemplateBreakout", {});
63
+ return <Box __css={styles}>{props.children}</Box>;
64
+ };
65
+
45
66
  /**
46
67
  * This optional component should be the first child of the `Template`
47
- * component. This is rendered as an HTML `<header>` element.
68
+ * component. This is rendered as an HTML `<header>` element. If an HTML
69
+ * `<header>` element is already passed in a custom component as the children,
70
+ * set `renderFooterElement` to `false`. Otherwise, the parent wrapper will
71
+ * render an HTML `<header>` element.
48
72
  */
49
- const TemplateHeader = (props: React.PropsWithChildren<TemplateProps>) => {
73
+ const TemplateHeader = ({
74
+ children,
75
+ renderHeaderElement = true,
76
+ }: React.PropsWithChildren<TemplateHeaderProps>) => {
50
77
  const styles = useStyleConfig("TemplateHeader", {});
51
- return (
52
- <Box as="header" __css={styles}>
53
- {props.children}
54
- </Box>
55
- );
78
+ let headerElement = <Box __css={styles}>{children}</Box>;
79
+
80
+ // The user wants to render the `header` HTML element.
81
+ if (renderHeaderElement) {
82
+ // But if they passed in a component that renders an HTML `<header>`,
83
+ // then log a warning.
84
+ React.Children.map(children, (child: React.ReactElement) => {
85
+ if (child?.type === "header" || child?.props?.mdxType === "header") {
86
+ console.warn(
87
+ "`TemplateHeader`: An HTML `header` element was passed in. Set " +
88
+ "`renderHeaderElement` to `false` to avoid nested HTML `header` elements."
89
+ );
90
+ }
91
+ });
92
+ headerElement = (
93
+ <Box as="header" __css={styles}>
94
+ {children}
95
+ </Box>
96
+ );
97
+ }
98
+ return headerElement;
56
99
  };
57
100
 
58
101
  /**
@@ -194,6 +237,7 @@ const TemplateAppContainer = (
194
237
  props: React.PropsWithChildren<TemplateAppContainerProps>
195
238
  ) => {
196
239
  const {
240
+ aboveHeader,
197
241
  breakout,
198
242
  contentPrimary,
199
243
  contentSidebar,
@@ -202,7 +246,11 @@ const TemplateAppContainer = (
202
246
  header,
203
247
  sidebar = "none",
204
248
  renderFooterElement = true,
249
+ renderHeaderElement = true,
205
250
  } = props;
251
+ const aboveHeaderElem = aboveHeader && (
252
+ <TemplateAboveHeader>{aboveHeader}</TemplateAboveHeader>
253
+ );
206
254
  const breakoutElem = breakout && (
207
255
  <TemplateBreakout>{breakout}</TemplateBreakout>
208
256
  );
@@ -217,8 +265,9 @@ const TemplateAppContainer = (
217
265
  );
218
266
  return (
219
267
  <Template>
268
+ {aboveHeaderElem}
220
269
  {(header || breakoutElem) && (
221
- <TemplateHeader>
270
+ <TemplateHeader renderHeaderElement={renderHeaderElement}>
222
271
  {header}
223
272
  {breakoutElem}
224
273
  </TemplateHeader>
@@ -246,6 +295,7 @@ const TemplateAppContainer = (
246
295
  export {
247
296
  TemplateAppContainer,
248
297
  Template,
298
+ TemplateAboveHeader,
249
299
  TemplateHeader,
250
300
  TemplateBreakout,
251
301
  TemplateContent,
@@ -4,6 +4,99 @@ exports[`Template components Renders the UI snapshot correctly 1`] = `
4
4
  <div
5
5
  className="nypl-ds css-0"
6
6
  >
7
+ <div
8
+ className="css-0"
9
+ >
10
+ <div
11
+ className="placeholder placeholder-short"
12
+ >
13
+ Above Header
14
+ </div>
15
+ </div>
16
+ <header
17
+ className="css-0"
18
+ >
19
+ <div
20
+ className="placeholder placeholder-short"
21
+ >
22
+ NYPL Header
23
+ </div>
24
+ <div
25
+ className="css-0"
26
+ >
27
+ <div
28
+ className="placeholder placeholder-short"
29
+ >
30
+ Breadcrumbs
31
+ </div>
32
+ <div
33
+ className="placeholder placeholder-short"
34
+ >
35
+ Hero
36
+ </div>
37
+ </div>
38
+ </header>
39
+ <main
40
+ className="css-0"
41
+ >
42
+ <div
43
+ className="css-0"
44
+ >
45
+ <div
46
+ className="placeholder placeholder-undefined"
47
+ >
48
+ Content Top
49
+ </div>
50
+ </div>
51
+ <div
52
+ className="css-0"
53
+ >
54
+ <div
55
+ className="placeholder placeholder-undefined"
56
+ >
57
+ Left Sidebar
58
+ </div>
59
+ </div>
60
+ <div
61
+ className="css-0"
62
+ >
63
+ <div
64
+ className="placeholder placeholder-undefined"
65
+ >
66
+ Main Content
67
+ </div>
68
+ <div
69
+ className="placeholder placeholder-short"
70
+ >
71
+ More Content
72
+ </div>
73
+ </div>
74
+ </main>
75
+ <footer
76
+ className="css-0"
77
+ >
78
+ <div
79
+ className="placeholder placeholder-short"
80
+ >
81
+ Footer
82
+ </div>
83
+ </footer>
84
+ </div>
85
+ `;
86
+
87
+ exports[`Template components Renders the UI snapshot correctly 2`] = `
88
+ <div
89
+ className="nypl-ds css-0"
90
+ >
91
+ <div
92
+ className="css-0"
93
+ >
94
+ <div
95
+ className="placeholder placeholder-short"
96
+ >
97
+ Above Header
98
+ </div>
99
+ </div>
7
100
  <header
8
101
  className="css-0"
9
102
  >
package/src/index.ts CHANGED
@@ -7,9 +7,11 @@ export {
7
7
  ButtonGroup,
8
8
  Center,
9
9
  Circle,
10
+ Flex,
10
11
  Grid,
11
12
  GridItem,
12
13
  HStack,
14
+ Spacer,
13
15
  Square,
14
16
  Stack,
15
17
  VStack,
@@ -29,12 +31,15 @@ export { CardLayouts } from "./components/Card/CardTypes";
29
31
  export { default as Checkbox } from "./components/Checkbox/Checkbox";
30
32
  export { default as CheckboxGroup } from "./components/CheckboxGroup/CheckboxGroup";
31
33
  export { CheckboxGroupLayoutTypes } from "./components/CheckboxGroup/CheckboxGroupLayoutTypes";
32
- export { default as DatePicker } from "./components/DatePicker/DatePicker";
34
+ export {
35
+ default as DatePicker,
36
+ FullDateType,
37
+ } from "./components/DatePicker/DatePicker";
33
38
  export { DatePickerTypes } from "./components/DatePicker/DatePickerTypes";
34
39
  export { default as DSProvider } from "./theme/provider";
35
40
  export { default as Fieldset } from "./components/Fieldset/Fieldset";
36
41
  export { default as Form, FormField, FormRow } from "./components/Form/Form";
37
- export { FormSpacing } from "./components/Form/FormTypes";
42
+ export { FormGaps } from "./components/Form/FormTypes";
38
43
  export { GridGaps } from "./components/Grid/GridTypes";
39
44
  export { default as Heading } from "./components/Heading/Heading";
40
45
  export {
@@ -102,6 +107,7 @@ export {
102
107
  export {
103
108
  TemplateAppContainer,
104
109
  Template,
110
+ TemplateAboveHeader,
105
111
  TemplateHeader,
106
112
  TemplateBreakout,
107
113
  TemplateContent,
@@ -67,7 +67,7 @@ const Breadcrumb = {
67
67
  marginInlineStart: "xxs",
68
68
  },
69
69
  },
70
- "li:nth-last-child(2)": {
70
+ "li:nth-last-of-type(2)": {
71
71
  display: "inline-block",
72
72
  span: {
73
73
  display: { base: "none", md: "inline" },
@@ -3,6 +3,15 @@ const baseStyle = ({
3
3
  showRowDividers,
4
4
  useRowHeaders,
5
5
  }) => ({
6
+ // Headers `th` can be rendered as the first cell in every row through the
7
+ // `useRowHeaders`. Whereas the header `th` in the `thead` can be rendered
8
+ // with a custom color, the row header `th` in the `tbody` should always
9
+ // have text color black.
10
+ tbody: {
11
+ th: {
12
+ color: "var(--nypl-colors-ui-black)",
13
+ },
14
+ },
6
15
  th: {
7
16
  border: showRowDividers ? undefined : "none",
8
17
  borderBottom: showRowDividers ? undefined : "0px",
@@ -35,11 +44,15 @@ const baseStyle = ({
35
44
  },
36
45
  caption: {
37
46
  captionSide: "top",
38
- textAlign: "left",
39
- fontSize: "heading.secondary",
40
47
  color: "ui.black",
41
- textTransform: "capitalize",
48
+ fontSize: "heading.secondary",
42
49
  fontWeight: "heading.secondary",
50
+ marginBottom: "s",
51
+ marginLeft: "0",
52
+ marginRight: "0",
53
+ marginTop: "0",
54
+ padding: "0",
55
+ textAlign: "left",
43
56
  },
44
57
  });
45
58
 
@@ -93,6 +93,7 @@ const categories = {
93
93
  title: "Chakra/Layout",
94
94
  components: [
95
95
  "Box",
96
+ "Flex",
96
97
  "Grid",
97
98
  "Center, Circle, Square",
98
99
  "Stack, HStack, VStack",