@dashforge/tw 0.1.0-beta → 0.2.0-beta

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 (185) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/dist/index.d.ts +1 -82
  3. package/dist/index.esm.js +1563 -2
  4. package/dist/src/components/AspectRatio/AspectRatio.d.ts +36 -0
  5. package/dist/src/components/AspectRatio/AspectRatio.d.ts.map +1 -0
  6. package/dist/src/components/AspectRatio/aspectRatio.types.d.ts +50 -0
  7. package/dist/src/components/AspectRatio/aspectRatio.types.d.ts.map +1 -0
  8. package/dist/src/components/Box/Box.d.ts +36 -0
  9. package/dist/src/components/Box/Box.d.ts.map +1 -0
  10. package/dist/src/components/Box/box.types.d.ts +54 -0
  11. package/dist/src/components/Box/box.types.d.ts.map +1 -0
  12. package/dist/src/components/Box/box.variants.d.ts +402 -0
  13. package/dist/src/components/Box/box.variants.d.ts.map +1 -0
  14. package/dist/src/components/Container/Container.d.ts +35 -0
  15. package/dist/src/components/Container/Container.d.ts.map +1 -0
  16. package/dist/src/components/Container/container.types.d.ts +41 -0
  17. package/dist/src/components/Container/container.types.d.ts.map +1 -0
  18. package/dist/src/components/Container/container.variants.d.ts +93 -0
  19. package/dist/src/components/Container/container.variants.d.ts.map +1 -0
  20. package/dist/src/components/Divider/Divider.d.ts +50 -0
  21. package/dist/src/components/Divider/Divider.d.ts.map +1 -0
  22. package/dist/src/components/Divider/divider.types.d.ts +47 -0
  23. package/dist/src/components/Divider/divider.types.d.ts.map +1 -0
  24. package/dist/src/components/Divider/divider.variants.d.ts +129 -0
  25. package/dist/src/components/Divider/divider.variants.d.ts.map +1 -0
  26. package/dist/src/components/Grid/Grid.d.ts +32 -0
  27. package/dist/src/components/Grid/Grid.d.ts.map +1 -0
  28. package/dist/src/components/Grid/grid.types.d.ts +103 -0
  29. package/dist/src/components/Grid/grid.types.d.ts.map +1 -0
  30. package/dist/src/components/Grid/grid.variants.d.ts +453 -0
  31. package/dist/src/components/Grid/grid.variants.d.ts.map +1 -0
  32. package/dist/src/components/Stack/Stack.d.ts +24 -0
  33. package/dist/src/components/Stack/Stack.d.ts.map +1 -0
  34. package/dist/src/components/Stack/stack.types.d.ts +61 -0
  35. package/dist/src/components/Stack/stack.types.d.ts.map +1 -0
  36. package/dist/src/components/Stack/stack.variants.d.ts +163 -0
  37. package/dist/src/components/Stack/stack.variants.d.ts.map +1 -0
  38. package/dist/src/components/Typography/Typography.d.ts +42 -0
  39. package/dist/src/components/Typography/Typography.d.ts.map +1 -0
  40. package/dist/src/components/Typography/typography.types.d.ts +61 -0
  41. package/dist/src/components/Typography/typography.types.d.ts.map +1 -0
  42. package/dist/src/components/Typography/typography.variants.d.ts +167 -0
  43. package/dist/src/components/Typography/typography.variants.d.ts.map +1 -0
  44. package/dist/src/components/VisuallyHidden/VisuallyHidden.d.ts +42 -0
  45. package/dist/src/components/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  46. package/dist/src/components/VisuallyHidden/visuallyHidden.types.d.ts +42 -0
  47. package/dist/src/components/VisuallyHidden/visuallyHidden.types.d.ts.map +1 -0
  48. package/dist/src/index.d.ts +22 -0
  49. package/dist/src/index.d.ts.map +1 -1
  50. package/package.json +3 -3
  51. package/src/components/AspectRatio/AspectRatio.test.tsx +173 -0
  52. package/src/components/AspectRatio/AspectRatio.tsx +73 -0
  53. package/src/components/AspectRatio/aspectRatio.types.ts +54 -0
  54. package/src/components/Box/Box.test.tsx +349 -0
  55. package/src/components/Box/Box.tsx +83 -0
  56. package/src/components/Box/box.types.ts +61 -0
  57. package/src/components/Box/box.variants.ts +211 -0
  58. package/src/components/Container/Container.test.tsx +209 -0
  59. package/src/components/Container/Container.tsx +74 -0
  60. package/src/components/Container/container.types.ts +45 -0
  61. package/src/components/Container/container.variants.ts +81 -0
  62. package/src/components/Divider/Divider.test.tsx +241 -0
  63. package/src/components/Divider/Divider.tsx +140 -0
  64. package/src/components/Divider/divider.types.ts +52 -0
  65. package/src/components/Divider/divider.variants.ts +115 -0
  66. package/src/components/Grid/Grid.test.tsx +321 -0
  67. package/src/components/Grid/Grid.tsx +148 -0
  68. package/src/components/Grid/grid.types.ts +112 -0
  69. package/src/components/Grid/grid.variants.ts +133 -0
  70. package/src/components/Stack/Stack.test.tsx +309 -0
  71. package/src/components/Stack/Stack.tsx +115 -0
  72. package/src/components/Stack/stack.types.ts +68 -0
  73. package/src/components/Stack/stack.variants.ts +80 -0
  74. package/src/components/Typography/Typography.test.tsx +230 -0
  75. package/src/components/Typography/Typography.tsx +112 -0
  76. package/src/components/Typography/typography.types.ts +65 -0
  77. package/src/components/Typography/typography.variants.ts +113 -0
  78. package/src/components/VisuallyHidden/VisuallyHidden.test.tsx +86 -0
  79. package/src/components/VisuallyHidden/VisuallyHidden.tsx +59 -0
  80. package/src/components/VisuallyHidden/visuallyHidden.types.ts +45 -0
  81. package/src/index.ts +49 -0
  82. package/dist/components/AppShell/AppShell.d.ts +0 -32
  83. package/dist/components/AppShell/AppShell.d.ts.map +0 -1
  84. package/dist/components/AppShell/appShell.types.d.ts +0 -62
  85. package/dist/components/AppShell/appShell.types.d.ts.map +0 -1
  86. package/dist/components/AppShell/appShell.variants.d.ts +0 -65
  87. package/dist/components/AppShell/appShell.variants.d.ts.map +0 -1
  88. package/dist/components/Autocomplete/Autocomplete.d.ts +0 -32
  89. package/dist/components/Autocomplete/Autocomplete.d.ts.map +0 -1
  90. package/dist/components/Autocomplete/autocomplete.types.d.ts +0 -214
  91. package/dist/components/Autocomplete/autocomplete.types.d.ts.map +0 -1
  92. package/dist/components/Autocomplete/autocomplete.variants.d.ts +0 -214
  93. package/dist/components/Autocomplete/autocomplete.variants.d.ts.map +0 -1
  94. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +0 -23
  95. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts.map +0 -1
  96. package/dist/components/Breadcrumbs/breadcrumbs.types.d.ts +0 -98
  97. package/dist/components/Breadcrumbs/breadcrumbs.types.d.ts.map +0 -1
  98. package/dist/components/Breadcrumbs/breadcrumbs.variants.d.ts +0 -85
  99. package/dist/components/Breadcrumbs/breadcrumbs.variants.d.ts.map +0 -1
  100. package/dist/components/Button/Button.d.ts +0 -44
  101. package/dist/components/Button/Button.d.ts.map +0 -1
  102. package/dist/components/Button/button.types.d.ts +0 -66
  103. package/dist/components/Button/button.types.d.ts.map +0 -1
  104. package/dist/components/Button/button.variants.d.ts +0 -104
  105. package/dist/components/Button/button.variants.d.ts.map +0 -1
  106. package/dist/components/Checkbox/Checkbox.d.ts +0 -31
  107. package/dist/components/Checkbox/Checkbox.d.ts.map +0 -1
  108. package/dist/components/Checkbox/checkbox.types.d.ts +0 -86
  109. package/dist/components/Checkbox/checkbox.types.d.ts.map +0 -1
  110. package/dist/components/Checkbox/checkbox.variants.d.ts +0 -109
  111. package/dist/components/Checkbox/checkbox.variants.d.ts.map +0 -1
  112. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +0 -38
  113. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +0 -1
  114. package/dist/components/ConfirmDialog/confirmDialog.types.d.ts +0 -80
  115. package/dist/components/ConfirmDialog/confirmDialog.types.d.ts.map +0 -1
  116. package/dist/components/ConfirmDialog/confirmDialog.variants.d.ts +0 -90
  117. package/dist/components/ConfirmDialog/confirmDialog.variants.d.ts.map +0 -1
  118. package/dist/components/DateTimePicker/DateTimePicker.d.ts +0 -49
  119. package/dist/components/DateTimePicker/DateTimePicker.d.ts.map +0 -1
  120. package/dist/components/DateTimePicker/dateTimePicker.types.d.ts +0 -95
  121. package/dist/components/DateTimePicker/dateTimePicker.types.d.ts.map +0 -1
  122. package/dist/components/DateTimePicker/dateTimePicker.variants.d.ts +0 -165
  123. package/dist/components/DateTimePicker/dateTimePicker.variants.d.ts.map +0 -1
  124. package/dist/components/LeftNav/LeftNav.d.ts +0 -34
  125. package/dist/components/LeftNav/LeftNav.d.ts.map +0 -1
  126. package/dist/components/LeftNav/leftNav.types.d.ts +0 -136
  127. package/dist/components/LeftNav/leftNav.types.d.ts.map +0 -1
  128. package/dist/components/LeftNav/leftNav.variants.d.ts +0 -143
  129. package/dist/components/LeftNav/leftNav.variants.d.ts.map +0 -1
  130. package/dist/components/NumberField/NumberField.d.ts +0 -18
  131. package/dist/components/NumberField/NumberField.d.ts.map +0 -1
  132. package/dist/components/NumberField/numberField.types.d.ts +0 -79
  133. package/dist/components/NumberField/numberField.types.d.ts.map +0 -1
  134. package/dist/components/NumberField/numberField.variants.d.ts +0 -169
  135. package/dist/components/NumberField/numberField.variants.d.ts.map +0 -1
  136. package/dist/components/OTPField/OTPField.d.ts +0 -25
  137. package/dist/components/OTPField/OTPField.d.ts.map +0 -1
  138. package/dist/components/OTPField/otpField.types.d.ts +0 -74
  139. package/dist/components/OTPField/otpField.types.d.ts.map +0 -1
  140. package/dist/components/OTPField/otpField.variants.d.ts +0 -105
  141. package/dist/components/OTPField/otpField.variants.d.ts.map +0 -1
  142. package/dist/components/RadioGroup/RadioGroup.d.ts +0 -35
  143. package/dist/components/RadioGroup/RadioGroup.d.ts.map +0 -1
  144. package/dist/components/RadioGroup/radioGroup.types.d.ts +0 -103
  145. package/dist/components/RadioGroup/radioGroup.types.d.ts.map +0 -1
  146. package/dist/components/RadioGroup/radioGroup.variants.d.ts +0 -166
  147. package/dist/components/RadioGroup/radioGroup.variants.d.ts.map +0 -1
  148. package/dist/components/Snackbar/Snackbar.d.ts +0 -37
  149. package/dist/components/Snackbar/Snackbar.d.ts.map +0 -1
  150. package/dist/components/Snackbar/snackbar.types.d.ts +0 -86
  151. package/dist/components/Snackbar/snackbar.types.d.ts.map +0 -1
  152. package/dist/components/Snackbar/snackbar.variants.d.ts +0 -153
  153. package/dist/components/Snackbar/snackbar.variants.d.ts.map +0 -1
  154. package/dist/components/Switch/Switch.d.ts +0 -15
  155. package/dist/components/Switch/Switch.d.ts.map +0 -1
  156. package/dist/components/Switch/switch.types.d.ts +0 -47
  157. package/dist/components/Switch/switch.types.d.ts.map +0 -1
  158. package/dist/components/Switch/switch.variants.d.ts +0 -105
  159. package/dist/components/Switch/switch.variants.d.ts.map +0 -1
  160. package/dist/components/TextField/TextField.d.ts +0 -25
  161. package/dist/components/TextField/TextField.d.ts.map +0 -1
  162. package/dist/components/TextField/textField.types.d.ts +0 -72
  163. package/dist/components/TextField/textField.types.d.ts.map +0 -1
  164. package/dist/components/TextField/textField.variants.d.ts +0 -160
  165. package/dist/components/TextField/textField.variants.d.ts.map +0 -1
  166. package/dist/components/Textarea/Textarea.d.ts +0 -16
  167. package/dist/components/Textarea/Textarea.d.ts.map +0 -1
  168. package/dist/components/Textarea/textarea.types.d.ts +0 -63
  169. package/dist/components/Textarea/textarea.types.d.ts.map +0 -1
  170. package/dist/components/Textarea/textarea.variants.d.ts +0 -197
  171. package/dist/components/Textarea/textarea.variants.d.ts.map +0 -1
  172. package/dist/components/TopBar/TopBar.d.ts +0 -33
  173. package/dist/components/TopBar/TopBar.d.ts.map +0 -1
  174. package/dist/components/TopBar/topBar.types.d.ts +0 -49
  175. package/dist/components/TopBar/topBar.types.d.ts.map +0 -1
  176. package/dist/components/TopBar/topBar.variants.d.ts +0 -79
  177. package/dist/components/TopBar/topBar.variants.d.ts.map +0 -1
  178. package/dist/components/_shared/resolveValidationState.d.ts +0 -42
  179. package/dist/components/_shared/resolveValidationState.d.ts.map +0 -1
  180. package/dist/hooks/useAccessState.d.ts +0 -37
  181. package/dist/hooks/useAccessState.d.ts.map +0 -1
  182. package/dist/index.d.ts.map +0 -1
  183. package/dist/tsconfig.lib.tsbuildinfo +0 -1
  184. package/dist/utils/cn.d.ts +0 -26
  185. package/dist/utils/cn.d.ts.map +0 -1
@@ -0,0 +1,86 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, it, expect } from 'vitest';
3
+ import { render } from '@testing-library/react';
4
+ import { VisuallyHidden } from './VisuallyHidden.js';
5
+
6
+ describe('<VisuallyHidden>', () => {
7
+ it('renders a <span> by default', () => {
8
+ const { container } = render(<VisuallyHidden>label</VisuallyHidden>);
9
+ expect(container.firstElementChild?.tagName).toBe('SPAN');
10
+ });
11
+
12
+ it('has the sr-only class', () => {
13
+ const { container } = render(<VisuallyHidden>label</VisuallyHidden>);
14
+ expect(container.firstElementChild?.className).toContain('sr-only');
15
+ });
16
+
17
+ it('preserves the text content (so screen readers can read it)', () => {
18
+ const { container } = render(<VisuallyHidden>Close dialog</VisuallyHidden>);
19
+ expect(container.firstElementChild?.textContent).toBe('Close dialog');
20
+ });
21
+
22
+ it('as="div" renders <div>', () => {
23
+ const { container } = render(<VisuallyHidden as="div">label</VisuallyHidden>);
24
+ expect(container.firstElementChild?.tagName).toBe('DIV');
25
+ });
26
+
27
+ it('sx adds utilities (merged with sr-only)', () => {
28
+ const { container } = render(
29
+ <VisuallyHidden sx="text-xs">label</VisuallyHidden>,
30
+ );
31
+ const cls = container.firstElementChild?.className ?? '';
32
+ expect(cls).toContain('sr-only');
33
+ expect(cls).toContain('text-xs');
34
+ });
35
+
36
+ it('forwards data-* + aria-*', () => {
37
+ const { container } = render(
38
+ <VisuallyHidden data-testid="vh" aria-live="polite">x</VisuallyHidden>,
39
+ );
40
+ const el = container.firstElementChild;
41
+ expect(el?.getAttribute('data-testid')).toBe('vh');
42
+ expect(el?.getAttribute('aria-live')).toBe('polite');
43
+ });
44
+
45
+ it('typical pattern — icon button label', () => {
46
+ const { container } = render(
47
+ <button type="button">
48
+ <span aria-hidden="true">✕</span>
49
+ <VisuallyHidden>Close</VisuallyHidden>
50
+ </button>,
51
+ );
52
+ const btn = container.querySelector('button');
53
+ // textContent includes the hidden label so AT can read it
54
+ expect(btn?.textContent).toBe('✕Close');
55
+ // visually, the Close span has sr-only
56
+ const hidden = btn?.querySelector('.sr-only');
57
+ expect(hidden?.textContent).toBe('Close');
58
+ });
59
+
60
+ // ─── F11-bis edge cases ─────────────────────────────────────────────
61
+ it('empty children renders empty element with sr-only', () => {
62
+ const { container } = render(<VisuallyHidden>{''}</VisuallyHidden>);
63
+ const el = container.firstElementChild;
64
+ expect(el?.className).toContain('sr-only');
65
+ expect(el?.textContent).toBe('');
66
+ });
67
+
68
+ it('aria-live="polite" pattern for status announcements', () => {
69
+ const { container } = render(
70
+ <VisuallyHidden aria-live="polite">Saved successfully</VisuallyHidden>,
71
+ );
72
+ const el = container.firstElementChild;
73
+ expect(el?.getAttribute('aria-live')).toBe('polite');
74
+ expect(el?.textContent).toBe('Saved successfully');
75
+ });
76
+
77
+ it('as="div" renders block element (consumer choice for block hidden content)', () => {
78
+ const { container } = render(
79
+ <VisuallyHidden as="div">
80
+ Block content hidden from sight but readable by AT
81
+ </VisuallyHidden>,
82
+ );
83
+ expect(container.firstElementChild?.tagName).toBe('DIV');
84
+ expect(container.firstElementChild?.className).toContain('sr-only');
85
+ });
86
+ });
@@ -0,0 +1,59 @@
1
+ import { forwardRef, type ElementType } from 'react';
2
+ import { cn } from '../../utils/cn.js';
3
+ import type { VisuallyHiddenProps } from './visuallyHidden.types.js';
4
+
5
+ /**
6
+ * `<VisuallyHidden>` — the accessibility primitive.
7
+ *
8
+ * Hides children from sighted users (zero pixels rendered, no layout
9
+ * impact) while keeping them in the accessibility tree. Screen readers
10
+ * speak the content; voice control software uses it for click targets;
11
+ * keyboard users see nothing — same as if it weren't there.
12
+ *
13
+ * Implementation: Tailwind's built-in `sr-only` utility, which expands to:
14
+ *
15
+ * .sr-only {
16
+ * position: absolute;
17
+ * width: 1px;
18
+ * height: 1px;
19
+ * padding: 0;
20
+ * margin: -1px;
21
+ * overflow: hidden;
22
+ * clip: rect(0,0,0,0);
23
+ * white-space: nowrap;
24
+ * border-width: 0;
25
+ * }
26
+ *
27
+ * This is the canonical "visually-hidden but screen-reader-accessible"
28
+ * pattern, also known as the WebAIM clip technique. Critically:
29
+ *
30
+ * • NOT `display: none` (removes from a11y tree)
31
+ * • NOT `visibility: hidden` (also removes from a11y tree)
32
+ * • NOT `opacity: 0` (technically still rendered, doesn't help AT)
33
+ * • NOT `width/height: 0` (collapses, some AT skips it)
34
+ *
35
+ * Default tag is `<span>` (inline) — the 99% case is "label inside a
36
+ * button or link". For block content, override with `as="div"`, but
37
+ * be aware nesting block inside inline is invalid HTML.
38
+ *
39
+ * The component is intentionally tiny (~30 LoC total): one className,
40
+ * one tag. The value is the COMPONENT NAME — `<VisuallyHidden>` reads
41
+ * as an intentional a11y decision in code review, while
42
+ * `className="sr-only"` looks like a typo or a forgotten utility.
43
+ */
44
+ export const VisuallyHidden = forwardRef<HTMLElement, VisuallyHiddenProps>(
45
+ function VisuallyHidden(props, ref) {
46
+ const { as, sx, children, ...rest } = props;
47
+
48
+ const Tag = (as ?? 'span') as ElementType;
49
+ const classes = cn('sr-only', sx);
50
+
51
+ return (
52
+ <Tag ref={ref as never} className={classes} {...rest}>
53
+ {children}
54
+ </Tag>
55
+ );
56
+ },
57
+ );
58
+
59
+ VisuallyHidden.displayName = 'VisuallyHidden';
@@ -0,0 +1,45 @@
1
+ import type { ElementType, HTMLAttributes, ReactElement } from 'react';
2
+
3
+ /**
4
+ * Props for `<VisuallyHidden>` — the a11y primitive.
5
+ *
6
+ * Hides content visually (zero pixels rendered) while keeping it
7
+ * accessible to assistive technology (screen readers, voice control).
8
+ * The canonical use case: icon-only buttons that need an audible label
9
+ * for non-visual users.
10
+ *
11
+ * <button>
12
+ * <CloseIcon />
13
+ * <VisuallyHidden>Close dialog</VisuallyHidden>
14
+ * </button>
15
+ *
16
+ * Implementation uses Tailwind's `sr-only` utility, which sets
17
+ * `position: absolute; width: 1px; height: 1px; padding: 0;
18
+ * margin: -1px; overflow: hidden; clip: rect(0,0,0,0);
19
+ * white-space: nowrap; border-width: 0;` — the canonical
20
+ * "visually-hidden but screen-reader-accessible" pattern. Better
21
+ * than `display: none` (removes from a11y tree) and better than
22
+ * `visibility: hidden` (also removes from a11y tree).
23
+ */
24
+ export interface VisuallyHiddenProps
25
+ extends Omit<HTMLAttributes<HTMLElement>, 'className'> {
26
+ /**
27
+ * The text or markup hidden from sighted users but read by AT.
28
+ * Most often a string label.
29
+ */
30
+ children?: ReactElement | string | number;
31
+
32
+ /**
33
+ * Override the rendered HTML tag. Defaults to `'span'` — inline
34
+ * placement is the most common case (label inside a button or link).
35
+ * Use `as="div"` when the hidden content is block-level, but be
36
+ * aware: nesting a block inside an inline parent is invalid HTML.
37
+ */
38
+ as?: ElementType;
39
+
40
+ /**
41
+ * Utility classes appended to `sr-only`. RARELY needed for this
42
+ * primitive (it's just hidden text) — kept for API parity.
43
+ */
44
+ sx?: string;
45
+ }
package/src/index.ts CHANGED
@@ -174,6 +174,55 @@ export type {
174
174
  } from './components/Snackbar/snackbar.types.js';
175
175
  export { snackbarVariants } from './components/Snackbar/snackbar.variants.js';
176
176
 
177
+ // F9 foundation: typography + layout primitives. These sit BENEATH
178
+ // every other component (Button's label, TextField's helper text, the
179
+ // surface of an AppShell card) and are what app-level code reaches for
180
+ // before it reaches for any specific UI atom.
181
+
182
+ export { Typography } from './components/Typography/Typography.js';
183
+ export type { TypographyProps } from './components/Typography/typography.types.js';
184
+ export { typographyVariants } from './components/Typography/typography.variants.js';
185
+
186
+ export { Box } from './components/Box/Box.js';
187
+ export type { BoxProps } from './components/Box/box.types.js';
188
+ export { boxVariants } from './components/Box/box.variants.js';
189
+
190
+ export { Stack } from './components/Stack/Stack.js';
191
+ export type { StackProps } from './components/Stack/stack.types.js';
192
+ export { stackVariants } from './components/Stack/stack.variants.js';
193
+
194
+ export { Grid } from './components/Grid/Grid.js';
195
+ export type {
196
+ GridProps,
197
+ GridContainerProps,
198
+ GridItemProps,
199
+ ColSpan,
200
+ GridSpacingStep,
201
+ } from './components/Grid/grid.types.js';
202
+ export { gridVariants } from './components/Grid/grid.variants.js';
203
+
204
+ // F10 foundation completions: Container, Divider, AspectRatio, VisuallyHidden.
205
+ // The page-root chrome + visual separators + content-shape primitives +
206
+ // the a11y baseline. With these, the foundation layer matches what
207
+ // Chakra/Mantine/Joy ship for layout-level primitives.
208
+
209
+ export { Container } from './components/Container/Container.js';
210
+ export type { ContainerProps } from './components/Container/container.types.js';
211
+ export { containerVariants } from './components/Container/container.variants.js';
212
+
213
+ export { Divider } from './components/Divider/Divider.js';
214
+ export type { DividerProps } from './components/Divider/divider.types.js';
215
+ export {
216
+ dividerVariants,
217
+ dividerLineVariants,
218
+ } from './components/Divider/divider.variants.js';
219
+
220
+ export { AspectRatio } from './components/AspectRatio/AspectRatio.js';
221
+ export type { AspectRatioProps } from './components/AspectRatio/aspectRatio.types.js';
222
+
223
+ export { VisuallyHidden } from './components/VisuallyHidden/VisuallyHidden.js';
224
+ export type { VisuallyHiddenProps } from './components/VisuallyHidden/visuallyHidden.types.js';
225
+
177
226
  // ───── Hooks ─────
178
227
  export { useAccessState } from './hooks/useAccessState.js';
179
228
 
@@ -1,32 +0,0 @@
1
- import type { AppShellProps } from './appShell.types.js';
2
- /**
3
- * Dashforge TW AppShell — top-level layout orchestrator.
4
- *
5
- * ┌──────────────────────────────────────────┐
6
- * │ header │ ← `header` slot
7
- * ├────────┬─────────────────────────────────┤
8
- * │ │ │
9
- * │ nav │ main │ ← `nav` + `children`
10
- * │ │ │
11
- * ├────────┴─────────────────────────────────┤
12
- * │ footer │ ← `footer` slot
13
- * └──────────────────────────────────────────┘
14
- *
15
- * **Responsive**:
16
- * - `≥ md`: nav stays in the inline slot at the left.
17
- * - `< md`: nav becomes a slide-in drawer toggled by `navOpen`.
18
- * A backdrop closes the drawer on click (mirrors `<Dialog>` UX).
19
- *
20
- * **Body scroll lock**: when the mobile drawer is open we add
21
- * `overflow-hidden` to `<body>` to prevent dual-scroll wobble. The
22
- * effect cleans up on close + on unmount.
23
- *
24
- * **A11y**:
25
- * - `<main>` landmark wraps the content area.
26
- * - `<header>` / `<footer>` come for free from their HTML tags.
27
- * - The mobile drawer + backdrop participate in the standard
28
- * "click outside to close" pattern — `Escape` closes the drawer
29
- * too (added via global keydown).
30
- */
31
- export declare function AppShell(props: AppShellProps): import("react/jsx-runtime").JSX.Element;
32
- //# sourceMappingURL=AppShell.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../../../src/components/AppShell/AppShell.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,2CA+E5C"}
@@ -1,62 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import type { AppShellVariants } from './appShell.variants.js';
3
- export interface AppShellSlotProps {
4
- root?: {
5
- className?: string;
6
- };
7
- header?: {
8
- className?: string;
9
- };
10
- nav?: {
11
- className?: string;
12
- };
13
- navMobile?: {
14
- className?: string;
15
- };
16
- main?: {
17
- className?: string;
18
- };
19
- footer?: {
20
- className?: string;
21
- };
22
- backdrop?: {
23
- className?: string;
24
- };
25
- }
26
- /**
27
- * Props for `<AppShell>`.
28
- *
29
- * Top-level layout orchestrator with 4 named slots:
30
- *
31
- * - `header` (top, sticky)
32
- * - `nav` (left side, fixed-width on desktop, drawer on mobile)
33
- * - `footer` (bottom, non-sticky)
34
- * - `children` (main content, scrolls independently)
35
- *
36
- * Responsive behavior:
37
- * - **≥ md (768px)**: nav is rendered inline at the left.
38
- * - **< md**: nav slides in as an overlay drawer when
39
- * `navOpen={true}` (controlled).
40
- *
41
- * The shell is router-agnostic — pass any nav/header content. Typical
42
- * pairing is `<LeftNav>` + `<TopBar>` (with a hamburger button in
43
- * `TopBar.start` that flips `navOpen`).
44
- */
45
- export interface AppShellProps extends AppShellVariants {
46
- header?: ReactNode;
47
- nav?: ReactNode;
48
- footer?: ReactNode;
49
- children?: ReactNode;
50
- /**
51
- * Mobile drawer open state. Controlled — provide
52
- * `onNavOpenChange` to update. When `undefined`, the mobile drawer
53
- * is always closed (consumer hasn't wired up the toggle yet).
54
- */
55
- navOpen?: boolean;
56
- onNavOpenChange?: (open: boolean) => void;
57
- /** Root className shortcut. */
58
- sx?: string;
59
- /** Per-slot className overrides. */
60
- slotProps?: AppShellSlotProps;
61
- }
62
- //# sourceMappingURL=appShell.types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"appShell.types.d.ts","sourceRoot":"","sources":["../../../src/components/AppShell/appShell.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,GAAG,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,aAAc,SAAQ,gBAAgB;IACrD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,+BAA+B;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B"}
@@ -1,65 +0,0 @@
1
- import { type VariantProps } from 'tailwind-variants';
2
- /**
3
- * Tailwind-variants recipe for `<AppShell>`.
4
- *
5
- * Slots:
6
- * - `root` — outer flex column (full viewport)
7
- * - `header` — top region
8
- * - `body` — flex row holding nav + main
9
- * - `nav` — desktop nav rail (md+)
10
- * - `navMobile` — mobile drawer (slide-in)
11
- * - `main` — scrollable content area
12
- * - `footer` — bottom region
13
- * - `backdrop` — semi-opaque overlay behind the mobile drawer
14
- */
15
- export declare const appShellVariants: import("tailwind-variants").TVReturnType<{
16
- navOpen: {
17
- true: {
18
- navMobile: string;
19
- backdrop: string;
20
- };
21
- };
22
- }, {
23
- root: string;
24
- header: string;
25
- body: string;
26
- nav: string;
27
- navMobile: string[];
28
- main: string;
29
- footer: string;
30
- backdrop: string[];
31
- }, undefined, {
32
- navOpen: {
33
- true: {
34
- navMobile: string;
35
- backdrop: string;
36
- };
37
- };
38
- }, {
39
- root: string;
40
- header: string;
41
- body: string;
42
- nav: string;
43
- navMobile: string[];
44
- main: string;
45
- footer: string;
46
- backdrop: string[];
47
- }, import("tailwind-variants").TVReturnType<{
48
- navOpen: {
49
- true: {
50
- navMobile: string;
51
- backdrop: string;
52
- };
53
- };
54
- }, {
55
- root: string;
56
- header: string;
57
- body: string;
58
- nav: string;
59
- navMobile: string[];
60
- main: string;
61
- footer: string;
62
- backdrop: string[];
63
- }, undefined, unknown, unknown, undefined>>;
64
- export type AppShellVariants = VariantProps<typeof appShellVariants>;
65
- //# sourceMappingURL=appShell.variants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"appShell.variants.d.ts","sourceRoot":"","sources":["../../../src/components/AppShell/appShell.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA8B3B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -1,32 +0,0 @@
1
- import type { AutocompleteOption, AutocompleteProps } from './autocomplete.types.js';
2
- /**
3
- * Dashforge TW Autocomplete — bridge-integrated single-select combobox.
4
- *
5
- * **Implementation note (F5-A, rev. 2)**
6
- *
7
- * The first revision wrapped `react-aria-components`' `<ComboBox>` to get
8
- * AAA-grade a11y for free. In practice React Aria's internal state
9
- * machine fought every controlled-state pattern we tried (the input text
10
- * would not clear when `selectedKey` went to `null`, even with a forced
11
- * remount via `key` bumping). To get deterministic behaviour we own all
12
- * of the state ourselves:
13
- *
14
- * - `inputValue` — the visible text in the `<input>`
15
- * - `isOpen` — popover visibility
16
- * - `highlightedIndex` — keyboard navigation cursor
17
- *
18
- * A11y is still solid:
19
- * - `role="combobox"` + `aria-autocomplete="list"` on the input
20
- * - `aria-expanded`, `aria-controls`, `aria-activedescendant`
21
- * - `role="listbox"` / `role="option"` with `aria-selected`
22
- * - Full keyboard nav (↑/↓ navigate, Enter selects, Escape closes,
23
- * Home/End jump, Tab closes, click-outside closes)
24
- * - Required field gets `aria-required="true"`
25
- *
26
- * F5-A scope: single-select, static options, contains-substring filter
27
- * (case-insensitive). Multi-select, free-solo text, generic option
28
- * shapes, and async runtime options (`optionsFromFieldData`) are
29
- * deferred to F5-A-bis.
30
- */
31
- export declare function Autocomplete<TOption = AutocompleteOption>(props: AutocompleteProps<TOption>): import("react/jsx-runtime").JSX.Element | null;
32
- //# sourceMappingURL=Autocomplete.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Autocomplete.d.ts","sourceRoot":"","sources":["../../../src/components/Autocomplete/Autocomplete.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,yBAAyB,CAAC;AAuCjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAG,kBAAkB,EACvD,KAAK,EAAE,iBAAiB,CAAC,OAAO,CAAC,kDAu4BlC"}
@@ -1,214 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import type { Engine } from '@dashforge/ui-core';
3
- import type { AccessRequirement } from '@dashforge/rbac';
4
- import type { AutocompleteVariants } from './autocomplete.variants.js';
5
- /**
6
- * Default `{ value, label, disabled? }` option shape.
7
- *
8
- * The simplest shape and the one used by the component when no
9
- * `getOptionValue` / `getOptionLabel` props are provided. For richer
10
- * option shapes (e.g., `{ id, name, country, ... }`) make the component
11
- * generic by passing `<TOption>` and providing the accessors:
12
- *
13
- * ```tsx
14
- * type User = { id: string; name: string; admin?: boolean };
15
- *
16
- * <Autocomplete<User>
17
- * name="owner"
18
- * options={users}
19
- * getOptionValue={(u) => u.id}
20
- * getOptionLabel={(u) => u.name}
21
- * getOptionDisabled={(u) => !u.admin}
22
- * />
23
- * ```
24
- */
25
- export interface AutocompleteOption {
26
- /** Value persisted on the form. */
27
- value: string;
28
- /** Display label (string or any React node). */
29
- label: ReactNode;
30
- /** Per-option explicit disable. */
31
- disabled?: boolean;
32
- }
33
- export interface AutocompleteSlotProps {
34
- root?: {
35
- className?: string;
36
- };
37
- label?: {
38
- className?: string;
39
- };
40
- requiredMark?: {
41
- className?: string;
42
- };
43
- inputWrapper?: {
44
- className?: string;
45
- };
46
- input?: {
47
- className?: string;
48
- };
49
- trigger?: {
50
- className?: string;
51
- };
52
- clearButton?: {
53
- className?: string;
54
- };
55
- popover?: {
56
- className?: string;
57
- };
58
- listBox?: {
59
- className?: string;
60
- };
61
- listItem?: {
62
- className?: string;
63
- };
64
- emptyState?: {
65
- className?: string;
66
- };
67
- helperText?: {
68
- className?: string;
69
- };
70
- errorText?: {
71
- className?: string;
72
- };
73
- /** Wrapper around the chip list (multi-select only). */
74
- chipsList?: {
75
- className?: string;
76
- };
77
- /** Individual chip displayed in multi-select. */
78
- chip?: {
79
- className?: string;
80
- };
81
- /** `×` button on a chip. */
82
- chipRemove?: {
83
- className?: string;
84
- };
85
- }
86
- /**
87
- * Union of the value shapes `<Autocomplete>` accepts.
88
- *
89
- * - **Single-select (default)**: `string | null`
90
- * - **Multi-select** (`multiple` prop): `string[] | null`
91
- *
92
- * `null` means "no selection" in both modes — a multi-select with no
93
- * picks emits an empty array on first commit, then keeps emitting arrays.
94
- */
95
- export type AutocompleteValue = string | string[] | null;
96
- /**
97
- * Props for `<Autocomplete>`.
98
- *
99
- * Bridge-integrated single-select combobox with full ARIA combobox
100
- * a11y, keyboard navigation, and Form Closure v1 error gating.
101
- *
102
- * Mirrors the MUI-side `@dashforge/ui/Autocomplete` at the bridge
103
- * level — same `name` / `rules` / `visibleWhen` / `access` semantics,
104
- * same StrictMode-safe unregister-on-unmount.
105
- *
106
- * @typeParam TOption Shape of an option. Defaults to
107
- * `AutocompleteOption` (`{ value, label, disabled? }`).
108
- * Pass `<TOption>` + `getOptionValue` / `getOptionLabel`
109
- * for arbitrary domain types.
110
- */
111
- export interface AutocompleteProps<TOption = AutocompleteOption> extends AutocompleteVariants {
112
- name: string;
113
- rules?: unknown;
114
- options: TOption[];
115
- label?: ReactNode;
116
- helperText?: ReactNode;
117
- required?: boolean;
118
- error?: boolean;
119
- disabled?: boolean;
120
- /** Placeholder shown when the input is empty. */
121
- placeholder?: string;
122
- /** Engine predicate — field not rendered when it returns `false`. */
123
- visibleWhen?: (engine: Engine) => boolean;
124
- /** RBAC access requirement. */
125
- access?: AccessRequirement;
126
- /** Root className shortcut. */
127
- sx?: string;
128
- /** Per-slot className overrides. */
129
- slotProps?: AutocompleteSlotProps;
130
- /** Controlled value (form mode reads from the bridge if omitted). */
131
- value?: AutocompleteValue;
132
- /** Default value for uncontrolled mode (no-op in form mode). */
133
- defaultValue?: AutocompleteValue;
134
- /** Fires when the user picks an option (after bridge update in form mode). */
135
- onValueChange?: (value: AutocompleteValue) => void;
136
- /** Fallback text when no option matches the typed filter. */
137
- emptyMessage?: string;
138
- /**
139
- * Multi-select mode. When `true`:
140
- *
141
- * - `value` / `defaultValue` accept `string[]` (or `null`).
142
- * - Picks are toggled rather than replaced; the popover stays open.
143
- * - Selected items render as chips inside the input wrapper.
144
- * - Backspace at the start of an empty input removes the last chip.
145
- * - The clear button (`×`) clears the entire selection.
146
- */
147
- multiple?: boolean;
148
- /**
149
- * Allow committing arbitrary strings (not just option values).
150
- *
151
- * When `true`:
152
- * - **Enter** commits the typed text as the value when no option
153
- * row is highlighted (or no rows match the filter).
154
- * - **Blur** commits the typed text the same way, unless the text
155
- * exactly matches an existing option's label (in which case the
156
- * option's value snaps in).
157
- * - In multi mode, each free-solo commit adds a new chip whose key
158
- * and label are the typed string.
159
- *
160
- * Free-solo is independent of `multiple` — works in both modes.
161
- */
162
- freeSolo?: boolean;
163
- /**
164
- * Async option loader. Called (debounced by `loadDebounceMs`) every
165
- * time the user types in the input. Results replace the static
166
- * `options` prop while the user is actively filtering.
167
- *
168
- * Return a promise that resolves with the new option list. Reject /
169
- * throw to surface a generic empty state.
170
- *
171
- * @example
172
- * ```tsx
173
- * <Autocomplete
174
- * name="user"
175
- * options={[]}
176
- * loadOptions={async (q) => {
177
- * const res = await fetch(`/api/users?q=${q}`);
178
- * return res.ok ? res.json() : [];
179
- * }}
180
- * />
181
- * ```
182
- */
183
- loadOptions?: (query: string) => Promise<TOption[]>;
184
- /**
185
- * Debounce window (ms) for `loadOptions`. The loader fires after the
186
- * user stops typing for this long.
187
- * @default 250
188
- */
189
- loadDebounceMs?: number;
190
- /** Text displayed in the popover while a fetch is in flight. */
191
- loadingMessage?: ReactNode;
192
- /**
193
- * Extract the persistable value (string) from an option.
194
- * @default `(o) => (o as AutocompleteOption).value`
195
- */
196
- getOptionValue?: (option: TOption) => string;
197
- /**
198
- * Extract the display label from an option.
199
- * @default `(o) => (o as AutocompleteOption).label`
200
- */
201
- getOptionLabel?: (option: TOption) => ReactNode;
202
- /**
203
- * Per-option disabled flag.
204
- * @default `(o) => Boolean((o as AutocompleteOption).disabled)`
205
- */
206
- getOptionDisabled?: (option: TOption) => boolean;
207
- /**
208
- * Unique React key for an option. Defaults to `getOptionValue`.
209
- * Override if your `value` strings can collide across distinct
210
- * option records (rare).
211
- */
212
- getOptionKey?: (option: TOption) => string;
213
- }
214
- //# sourceMappingURL=autocomplete.types.d.ts.map