@nationaldesignstudio/react 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/component-registry.md +1310 -127
  2. package/dist/components/atoms/background/background.d.ts +13 -27
  3. package/dist/components/atoms/button/button.d.ts +64 -72
  4. package/dist/components/atoms/button/button.figma.d.ts +1 -0
  5. package/dist/components/atoms/button/icon-button.d.ts +62 -110
  6. package/dist/components/atoms/input/input-group.d.ts +278 -0
  7. package/dist/components/atoms/input/input.d.ts +121 -0
  8. package/dist/components/atoms/popover/popover.d.ts +195 -0
  9. package/dist/components/atoms/select/select.d.ts +131 -0
  10. package/dist/components/atoms/tooltip/tooltip.d.ts +161 -0
  11. package/dist/components/organisms/card/card.d.ts +3 -3
  12. package/dist/components/sections/hero/hero.d.ts +2 -2
  13. package/dist/components/sections/prose/prose.d.ts +3 -3
  14. package/dist/components/sections/river/river.d.ts +1 -1
  15. package/dist/components/sections/tout/tout.d.ts +4 -4
  16. package/dist/components/shared/floating-arrow.d.ts +34 -0
  17. package/dist/index.d.ts +12 -0
  18. package/dist/index.js +13935 -7622
  19. package/dist/index.js.map +1 -1
  20. package/dist/lib/form-control.d.ts +106 -0
  21. package/dist/tokens.css +4725 -19065
  22. package/package.json +2 -1
  23. package/src/components/atoms/accordion/accordion.stories.tsx +1 -1
  24. package/src/components/atoms/accordion/accordion.tsx +2 -2
  25. package/src/components/atoms/background/background.tsx +71 -109
  26. package/src/components/atoms/button/button.figma.tsx +37 -0
  27. package/src/components/atoms/button/button.stories.tsx +253 -115
  28. package/src/components/atoms/button/button.test.tsx +289 -5
  29. package/src/components/atoms/button/button.tsx +40 -101
  30. package/src/components/atoms/button/button.visual.test.tsx +28 -32
  31. package/src/components/atoms/button/icon-button.stories.tsx +44 -101
  32. package/src/components/atoms/button/icon-button.test.tsx +26 -94
  33. package/src/components/atoms/button/icon-button.tsx +81 -224
  34. package/src/components/atoms/input/index.ts +17 -0
  35. package/src/components/atoms/input/input-group.stories.tsx +646 -0
  36. package/src/components/atoms/input/input-group.test.tsx +362 -0
  37. package/src/components/atoms/input/input-group.tsx +409 -0
  38. package/src/components/atoms/input/input.stories.tsx +228 -0
  39. package/src/components/atoms/input/input.test.tsx +167 -0
  40. package/src/components/atoms/input/input.tsx +104 -0
  41. package/src/components/atoms/pager-control/pager-control.stories.tsx +6 -8
  42. package/src/components/atoms/pager-control/pager-control.tsx +12 -12
  43. package/src/components/atoms/popover/index.ts +30 -0
  44. package/src/components/atoms/popover/popover.stories.tsx +531 -0
  45. package/src/components/atoms/popover/popover.test.tsx +486 -0
  46. package/src/components/atoms/popover/popover.tsx +488 -0
  47. package/src/components/atoms/select/index.ts +18 -0
  48. package/src/components/atoms/select/select.stories.tsx +455 -0
  49. package/src/components/atoms/select/select.tsx +324 -0
  50. package/src/components/atoms/tooltip/index.ts +24 -0
  51. package/src/components/atoms/tooltip/tooltip.stories.tsx +348 -0
  52. package/src/components/atoms/tooltip/tooltip.test.tsx +363 -0
  53. package/src/components/atoms/tooltip/tooltip.tsx +347 -0
  54. package/src/components/dev-tools/dev-toolbar/dev-toolbar.stories.tsx +8 -17
  55. package/src/components/dev-tools/dev-toolbar/dev-toolbar.tsx +3 -3
  56. package/src/components/foundation/typography/typography.stories.tsx +401 -0
  57. package/src/components/organisms/card/card.stories.tsx +19 -19
  58. package/src/components/organisms/card/card.test.tsx +1 -1
  59. package/src/components/organisms/card/card.tsx +3 -3
  60. package/src/components/organisms/card/card.visual.test.tsx +11 -11
  61. package/src/components/organisms/navbar/navbar.tsx +2 -2
  62. package/src/components/organisms/navbar/navbar.visual.test.tsx +2 -2
  63. package/src/components/organisms/us-gov-banner/us-gov-banner.tsx +2 -2
  64. package/src/components/sections/banner/banner.stories.tsx +1 -5
  65. package/src/components/sections/banner/banner.test.tsx +2 -2
  66. package/src/components/sections/banner/banner.tsx +6 -6
  67. package/src/components/sections/card-grid/card-grid.tsx +5 -5
  68. package/src/components/sections/faq-section/faq-section.tsx +2 -2
  69. package/src/components/sections/hero/hero.stories.tsx +7 -7
  70. package/src/components/sections/hero/hero.test.tsx +5 -5
  71. package/src/components/sections/hero/hero.tsx +10 -11
  72. package/src/components/sections/prose/prose.test.tsx +2 -2
  73. package/src/components/sections/prose/prose.tsx +6 -7
  74. package/src/components/sections/river/river.stories.tsx +8 -8
  75. package/src/components/sections/river/river.test.tsx +4 -4
  76. package/src/components/sections/river/river.tsx +8 -16
  77. package/src/components/sections/tout/tout.stories.tsx +7 -31
  78. package/src/components/sections/tout/tout.test.tsx +1 -1
  79. package/src/components/sections/tout/tout.tsx +11 -11
  80. package/src/components/sections/two-column-section/two-column-section.tsx +7 -9
  81. package/src/components/shared/floating-arrow.tsx +78 -0
  82. package/src/components/shared/index.ts +5 -0
  83. package/src/index.ts +98 -0
  84. package/src/lib/form-control.ts +71 -0
  85. package/src/stories/grid-system.stories.tsx +309 -0
  86. package/src/stories/{Introduction.mdx → introduction.mdx} +29 -15
  87. package/src/stories/{ThemeProvider.stories.tsx → theme-provider.stories.tsx} +8 -22
  88. package/src/stories/{TokenShowcase.stories.tsx → token-showcase.stories.tsx} +1 -20
  89. package/src/stories/token-showcase.tsx +777 -0
  90. package/src/styles.css +3 -0
  91. package/src/tests/token-resolution.test.tsx +298 -0
  92. package/src/theme/hooks.ts +1 -1
  93. package/src/theme/index.ts +1 -1
  94. package/src/theme/theme-provider.test.tsx +270 -0
  95. package/src/theme/{ThemeProvider.tsx → theme-provider.tsx} +18 -2
  96. package/src/stories/GridSystem.stories.tsx +0 -84
  97. package/src/stories/TokenShowcase.tsx +0 -1429
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nationaldesignstudio/react",
3
- "version": "0.2.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "*.css"
@@ -51,6 +51,7 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@chromatic-com/storybook": "catalog:",
54
+ "@figma/code-connect": "^1.3.12",
54
55
  "@nds-design-system/tailwind-token-generator": "workspace:*",
55
56
  "@nds-design-system/tokens": "workspace:*",
56
57
  "@nds-design-system/tools": "workspace:*",
@@ -19,7 +19,7 @@ const meta: Meta<typeof Accordion> = {
19
19
  },
20
20
  decorators: [
21
21
  (Story) => (
22
- <div className="p-spacing-56 max-w-[746px]">
22
+ <div className="p-56 max-w-[746px]">
23
23
  <Story />
24
24
  </div>
25
25
  ),
@@ -38,7 +38,7 @@ const accordionItemVariants = tv({
38
38
  const accordionTriggerVariants = tv({
39
39
  base: [
40
40
  // Uses primitive spacing tokens
41
- "flex w-full items-center justify-between py-spacing-24 text-left",
41
+ "flex w-full items-center justify-between py-24 text-left",
42
42
  "typography-body-large transition-colors cursor-pointer",
43
43
  ],
44
44
  variants: {
@@ -54,7 +54,7 @@ const accordionTriggerVariants = tv({
54
54
 
55
55
  const accordionPanelVariants = tv({
56
56
  // Uses primitive spacing tokens
57
- base: "typography-body-large pb-spacing-24",
57
+ base: "typography-body-large pb-24",
58
58
  variants: {
59
59
  colorScheme: {
60
60
  dark: "text-gray-100",
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { useRender } from "@base-ui-components/react/use-render";
3
4
  import * as React from "react";
4
5
  import { tv } from "tailwind-variants";
5
6
 
@@ -49,7 +50,8 @@ const backgroundImageVariants = tv({
49
50
  });
50
51
 
51
52
  export interface BackgroundImageProps
52
- extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src"> {
53
+ extends useRender.ComponentProps<"img">,
54
+ Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "render"> {
53
55
  /**
54
56
  * URL for the background image
55
57
  */
@@ -58,23 +60,6 @@ export interface BackgroundImageProps
58
60
  * Object position (default: "center")
59
61
  */
60
62
  position?: string;
61
- /**
62
- * Custom render prop for element composition.
63
- * Accepts a React element or render function.
64
- * @example
65
- * ```tsx
66
- * // Element pattern
67
- * <BackgroundImage render={<img className="custom" />} src="/bg.jpg" />
68
- *
69
- * // Callback pattern
70
- * <BackgroundImage render={(props) => <img {...props} />} src="/bg.jpg" />
71
- * ```
72
- */
73
- render?:
74
- | React.ReactElement
75
- | ((
76
- props: React.ImgHTMLAttributes<HTMLImageElement>,
77
- ) => React.ReactElement);
78
63
  }
79
64
 
80
65
  /**
@@ -82,45 +67,32 @@ export interface BackgroundImageProps
82
67
  * Supports native lazy loading, srcset, and better accessibility.
83
68
  * Supports render prop for element composition.
84
69
  */
85
- const BackgroundImage = React.forwardRef<
86
- HTMLImageElement,
87
- BackgroundImageProps
88
- >(
89
- (
90
- { className, src, position = "center", alt = "", style, render, ...props },
91
- ref,
92
- ) => {
93
- const imgClassName = backgroundImageVariants({ class: className });
94
- const imgStyle = { objectPosition: position, ...style };
95
- const imgProps = {
70
+ function BackgroundImage(props: BackgroundImageProps) {
71
+ const {
72
+ className,
73
+ src,
74
+ position = "center",
75
+ alt = "",
76
+ style,
77
+ render,
78
+ ...otherProps
79
+ } = props;
80
+
81
+ const imgClassName = backgroundImageVariants({ class: className });
82
+ const imgStyle = { objectPosition: position, ...style };
83
+
84
+ return useRender({
85
+ render,
86
+ props: {
96
87
  src,
97
88
  alt,
98
89
  className: imgClassName,
99
90
  style: imgStyle,
100
- ...props,
101
- };
102
-
103
- // Handle render prop (element or function)
104
- if (render) {
105
- if (typeof render === "function") {
106
- return render({
107
- ref,
108
- ...imgProps,
109
- } as React.ImgHTMLAttributes<HTMLImageElement>);
110
- }
111
- // Clone the render element with merged props
112
- return React.cloneElement(render, {
113
- ref,
114
- ...imgProps,
115
- ...(render.props as Record<string, unknown>),
116
- });
117
- }
118
-
119
- // Default: render as img
120
- // biome-ignore lint/a11y/useAltText: alt is provided via imgProps spread
121
- return <img ref={ref} {...imgProps} />;
122
- },
123
- );
91
+ ...otherProps,
92
+ },
93
+ defaultTagName: "img",
94
+ });
95
+ }
124
96
  BackgroundImage.displayName = "Background.Image";
125
97
 
126
98
  // =============================================================================
@@ -132,7 +104,11 @@ const backgroundVideoVariants = tv({
132
104
  });
133
105
 
134
106
  export interface BackgroundVideoProps
135
- extends Omit<React.VideoHTMLAttributes<HTMLVideoElement>, "children"> {
107
+ extends useRender.ComponentProps<"video">,
108
+ Omit<
109
+ React.VideoHTMLAttributes<HTMLVideoElement>,
110
+ "children" | "render" | "src"
111
+ > {
136
112
  /**
137
113
  * URL for the video source
138
114
  */
@@ -145,77 +121,63 @@ export interface BackgroundVideoProps
145
121
  * Poster image URL shown before video loads
146
122
  */
147
123
  poster?: string;
148
- /**
149
- * Custom render prop for element composition.
150
- * @example
151
- * ```tsx
152
- * <BackgroundVideo render={<video className="custom" />} src="/bg.mp4" />
153
- * ```
154
- */
155
- render?:
156
- | React.ReactElement
157
- | ((
158
- props: React.VideoHTMLAttributes<HTMLVideoElement>,
159
- ) => React.ReactElement);
160
124
  }
161
125
 
162
126
  /**
163
127
  * Background video layer using HTML5 video element.
164
128
  * Supports render prop for element composition.
165
129
  */
166
- const BackgroundVideo = React.forwardRef<
167
- HTMLVideoElement,
168
- BackgroundVideoProps
169
- >(
170
- (
171
- {
172
- className,
173
- src,
174
- type,
175
- poster,
176
- autoPlay = true,
177
- loop = true,
178
- muted = true,
179
- playsInline = true,
180
- render,
181
- ...props
182
- },
183
- ref,
184
- ) => {
185
- const videoClassName = backgroundVideoVariants({ class: className });
186
- const videoProps = {
130
+ function BackgroundVideo(props: BackgroundVideoProps) {
131
+ const {
132
+ className,
133
+ src,
134
+ type,
135
+ poster,
136
+ autoPlay = true,
137
+ loop = true,
138
+ muted = true,
139
+ playsInline = true,
140
+ render,
141
+ children,
142
+ ...otherProps
143
+ } = props;
144
+
145
+ const videoClassName = backgroundVideoVariants({ class: className });
146
+
147
+ // useRender must be called unconditionally
148
+ const rendered = useRender({
149
+ render,
150
+ props: {
187
151
  autoPlay,
188
152
  loop,
189
153
  muted,
190
154
  playsInline,
191
155
  poster,
192
156
  className: videoClassName,
193
- ...props,
194
- };
195
-
196
- // Handle render prop (element or function)
197
- if (render) {
198
- if (typeof render === "function") {
199
- return render({
200
- ref,
201
- ...videoProps,
202
- } as React.VideoHTMLAttributes<HTMLVideoElement>);
203
- }
204
- // Clone the render element with merged props
205
- return React.cloneElement(render, {
206
- ...videoProps,
207
- ...(render.props as Record<string, unknown>),
208
- });
209
- }
210
-
211
- // Default: render as video with source
157
+ ...otherProps,
158
+ },
159
+ defaultTagName: "video",
160
+ });
161
+
162
+ // If no render prop, return video with source child
163
+ if (!render) {
212
164
  return (
213
- <video ref={ref} {...videoProps}>
165
+ <video
166
+ autoPlay={autoPlay}
167
+ loop={loop}
168
+ muted={muted}
169
+ playsInline={playsInline}
170
+ poster={poster}
171
+ className={videoClassName}
172
+ {...otherProps}
173
+ >
214
174
  <source src={src} type={type} />
215
175
  </video>
216
176
  );
217
- },
218
- );
177
+ }
178
+
179
+ return rendered;
180
+ }
219
181
  BackgroundVideo.displayName = "Background.Video";
220
182
 
221
183
  // =============================================================================
@@ -0,0 +1,37 @@
1
+ import figma from "@figma/code-connect";
2
+ import { Button } from "./button";
3
+
4
+ figma.connect(
5
+ Button,
6
+ "https://www.figma.com/design/nvGqlGFXelQ5XdjEM5RCdK/Americas-Design-System?node-id=27103-21020",
7
+ {
8
+ props: {
9
+ variant: figma.enum("Variant", {
10
+ Primary: "primary",
11
+ Default: "default",
12
+ Secondary: "secondary",
13
+ Destructive: "destructive",
14
+ Outline: "outline",
15
+ Ghost: "ghost",
16
+ Link: "link",
17
+ }),
18
+ size: figma.enum("Size", {
19
+ sm: "sm",
20
+ default: "default",
21
+ lg: "lg",
22
+ }),
23
+ disabled: figma.enum("State", {
24
+ Disabled: true,
25
+ }),
26
+ },
27
+ example: (props) => (
28
+ <Button
29
+ variant={props.variant}
30
+ size={props.size}
31
+ disabled={props.disabled}
32
+ >
33
+ Button
34
+ </Button>
35
+ ),
36
+ },
37
+ );