@dashforge/tw 0.11.0-beta → 1.1.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 (134) hide show
  1. package/CHANGELOG.md +234 -12
  2. package/COVERAGE.md +2 -2
  3. package/PARITY.md +7 -9
  4. package/PERFORMANCE.md +3 -4
  5. package/README.md +74 -15
  6. package/THEME-AUDIT.md +3 -4
  7. package/dashforge-tw-1.0.0.tgz +0 -0
  8. package/dist/index.esm.js +3127 -748
  9. package/dist/src/components/Alert/Alert.d.ts +65 -0
  10. package/dist/src/components/Alert/Alert.d.ts.map +1 -0
  11. package/dist/src/components/Alert/alert.types.d.ts +130 -0
  12. package/dist/src/components/Alert/alert.types.d.ts.map +1 -0
  13. package/dist/src/components/Alert/alert.variants.d.ts +85 -0
  14. package/dist/src/components/Alert/alert.variants.d.ts.map +1 -0
  15. package/dist/src/components/Avatar/Avatar.d.ts +48 -0
  16. package/dist/src/components/Avatar/Avatar.d.ts.map +1 -0
  17. package/dist/src/components/Avatar/avatar.types.d.ts +162 -0
  18. package/dist/src/components/Avatar/avatar.types.d.ts.map +1 -0
  19. package/dist/src/components/Avatar/avatar.variants.d.ts +208 -0
  20. package/dist/src/components/Avatar/avatar.variants.d.ts.map +1 -0
  21. package/dist/src/components/Badge/Badge.d.ts +63 -0
  22. package/dist/src/components/Badge/Badge.d.ts.map +1 -0
  23. package/dist/src/components/Badge/badge.types.d.ts +124 -0
  24. package/dist/src/components/Badge/badge.types.d.ts.map +1 -0
  25. package/dist/src/components/Badge/badge.variants.d.ts +262 -0
  26. package/dist/src/components/Badge/badge.variants.d.ts.map +1 -0
  27. package/dist/src/components/Box/Box.d.ts.map +1 -1
  28. package/dist/src/components/Box/box.types.d.ts +53 -0
  29. package/dist/src/components/Box/box.types.d.ts.map +1 -1
  30. package/dist/src/components/Button/Button.d.ts.map +1 -1
  31. package/dist/src/components/Button/button.types.d.ts +35 -0
  32. package/dist/src/components/Button/button.types.d.ts.map +1 -1
  33. package/dist/src/components/Card/Card.d.ts +107 -0
  34. package/dist/src/components/Card/Card.d.ts.map +1 -0
  35. package/dist/src/components/Card/card.types.d.ts +119 -0
  36. package/dist/src/components/Card/card.types.d.ts.map +1 -0
  37. package/dist/src/components/Chip/Chip.d.ts +67 -0
  38. package/dist/src/components/Chip/Chip.d.ts.map +1 -0
  39. package/dist/src/components/Chip/chip.types.d.ts +113 -0
  40. package/dist/src/components/Chip/chip.types.d.ts.map +1 -0
  41. package/dist/src/components/Chip/chip.variants.d.ts +155 -0
  42. package/dist/src/components/Chip/chip.variants.d.ts.map +1 -0
  43. package/dist/src/components/IconButton/IconButton.d.ts +57 -0
  44. package/dist/src/components/IconButton/IconButton.d.ts.map +1 -0
  45. package/dist/src/components/IconButton/iconButton.types.d.ts +96 -0
  46. package/dist/src/components/IconButton/iconButton.types.d.ts.map +1 -0
  47. package/dist/src/components/IconButton/iconButton.variants.d.ts +26 -0
  48. package/dist/src/components/IconButton/iconButton.variants.d.ts.map +1 -0
  49. package/dist/src/components/Menu/Menu.d.ts +118 -0
  50. package/dist/src/components/Menu/Menu.d.ts.map +1 -0
  51. package/dist/src/components/Menu/menu.types.d.ts +179 -0
  52. package/dist/src/components/Menu/menu.types.d.ts.map +1 -0
  53. package/dist/src/components/Menu/menu.variants.d.ts +129 -0
  54. package/dist/src/components/Menu/menu.variants.d.ts.map +1 -0
  55. package/dist/src/components/Snackbar/Snackbar.d.ts.map +1 -1
  56. package/dist/src/components/Snackbar/snackbar.types.d.ts +40 -3
  57. package/dist/src/components/Snackbar/snackbar.types.d.ts.map +1 -1
  58. package/dist/src/components/Snackbar/snackbar.variants.d.ts +12 -57
  59. package/dist/src/components/Snackbar/snackbar.variants.d.ts.map +1 -1
  60. package/dist/src/components/Spinner/Spinner.d.ts +44 -0
  61. package/dist/src/components/Spinner/Spinner.d.ts.map +1 -0
  62. package/dist/src/components/Spinner/spinner.types.d.ts +89 -0
  63. package/dist/src/components/Spinner/spinner.types.d.ts.map +1 -0
  64. package/dist/src/components/Spinner/spinner.variants.d.ts +111 -0
  65. package/dist/src/components/Spinner/spinner.variants.d.ts.map +1 -0
  66. package/dist/src/components/Table/cells/RenderChip.d.ts +15 -72
  67. package/dist/src/components/Table/cells/RenderChip.d.ts.map +1 -1
  68. package/dist/src/components/_shared/severity/index.d.ts +21 -0
  69. package/dist/src/components/_shared/severity/index.d.ts.map +1 -0
  70. package/dist/src/components/_shared/severity/severity.types.d.ts +48 -0
  71. package/dist/src/components/_shared/severity/severity.types.d.ts.map +1 -0
  72. package/dist/src/components/_shared/severity/severityIcons.d.ts +45 -0
  73. package/dist/src/components/_shared/severity/severityIcons.d.ts.map +1 -0
  74. package/dist/src/components/_shared/severity/severityVariants.d.ts +22 -0
  75. package/dist/src/components/_shared/severity/severityVariants.d.ts.map +1 -0
  76. package/dist/src/index.d.ts +27 -2
  77. package/dist/src/index.d.ts.map +1 -1
  78. package/package.json +8 -7
  79. package/src/components/Alert/Alert.test.tsx +302 -0
  80. package/src/components/Alert/Alert.tsx +186 -0
  81. package/src/components/Alert/alert.types.ts +144 -0
  82. package/src/components/Alert/alert.variants.ts +71 -0
  83. package/src/components/Autocomplete/autocomplete.variants.ts +1 -1
  84. package/src/components/Avatar/Avatar.test.tsx +287 -0
  85. package/src/components/Avatar/Avatar.tsx +304 -0
  86. package/src/components/Avatar/avatar.types.ts +205 -0
  87. package/src/components/Avatar/avatar.variants.ts +194 -0
  88. package/src/components/Badge/Badge.test.tsx +385 -0
  89. package/src/components/Badge/Badge.tsx +174 -0
  90. package/src/components/Badge/badge.types.ts +154 -0
  91. package/src/components/Badge/badge.variants.ts +161 -0
  92. package/src/components/Box/Box.test.tsx +21 -0
  93. package/src/components/Box/Box.tsx +32 -3
  94. package/src/components/Box/box.types.ts +55 -0
  95. package/src/components/Button/Button.test.tsx +21 -0
  96. package/src/components/Button/Button.tsx +28 -27
  97. package/src/components/Button/button.types.ts +36 -0
  98. package/src/components/Card/Card.test.tsx +291 -0
  99. package/src/components/Card/Card.tsx +241 -0
  100. package/src/components/Card/card.types.ts +132 -0
  101. package/src/components/Chip/Chip.test.tsx +316 -0
  102. package/src/components/Chip/Chip.tsx +224 -0
  103. package/src/components/Chip/chip.types.ts +128 -0
  104. package/src/components/Chip/chip.variants.ts +173 -0
  105. package/src/components/DataGrid/visibility/ColumnVisibilityMenu.tsx +1 -1
  106. package/src/components/IconButton/IconButton.test.tsx +367 -0
  107. package/src/components/IconButton/IconButton.tsx +159 -0
  108. package/src/components/IconButton/iconButton.types.ts +106 -0
  109. package/src/components/IconButton/iconButton.variants.ts +31 -0
  110. package/src/components/LeftNav/leftNav.variants.ts +2 -2
  111. package/src/components/Menu/Menu.test.tsx +408 -0
  112. package/src/components/Menu/Menu.tsx +335 -0
  113. package/src/components/Menu/menu.types.ts +221 -0
  114. package/src/components/Menu/menu.variants.ts +132 -0
  115. package/src/components/Pagination/pagination.variants.ts +1 -1
  116. package/src/components/Snackbar/Snackbar.tsx +46 -28
  117. package/src/components/Snackbar/snackbar.types.ts +47 -3
  118. package/src/components/Snackbar/snackbar.variants.ts +29 -22
  119. package/src/components/Spinner/Spinner.test.tsx +199 -0
  120. package/src/components/Spinner/Spinner.tsx +158 -0
  121. package/src/components/Spinner/spinner.types.ts +113 -0
  122. package/src/components/Spinner/spinner.variants.ts +83 -0
  123. package/src/components/Table/cells/RenderChip.tsx +24 -87
  124. package/src/components/Table/cells/RowActionsMenu.tsx +1 -1
  125. package/src/components/TextField/TextField.test.tsx +5 -1
  126. package/src/components/_shared/severity/index.ts +33 -0
  127. package/src/components/_shared/severity/severity.types.ts +50 -0
  128. package/src/components/_shared/severity/severityIcons.tsx +104 -0
  129. package/src/components/_shared/severity/severityVariants.test.ts +136 -0
  130. package/src/components/_shared/severity/severityVariants.ts +115 -0
  131. package/src/index.ts +163 -1
  132. package/vite.config.ts +8 -0
  133. package/vitest.config.mts +8 -1
  134. package/LICENSE +0 -21
package/CHANGELOG.md CHANGED
@@ -12,6 +12,238 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
12
12
  > duplicated intentionally — no shared "lowest common denominator" headless
13
13
  > layer.
14
14
 
15
+ ## [1.1.0] — 2026-06-18
16
+
17
+ ### Added
18
+
19
+ - **`<Alert>` + `<AlertTitle>` components.** New inline persistent
20
+ status surface — companion to `<Snackbar>`'s transient toast. Full
21
+ MUI Alert API parity (`severity`, `variant`, `icon`, `onClose`,
22
+ `action`, `role`, `<AlertTitle>` sub-component). Single deliberate
23
+ divergence: `severity="danger"` instead of MUI's `severity="error"`
24
+ — aligned with the `danger.*` token palette (semantically identical,
25
+ documented in the migration guide). Adds the Dashforge-specific
26
+ `visibleWhen` (engine-reactive predicate) and `access` (RBAC) props,
27
+ same contract as `<TextField>` / `<Button>` / etc.
28
+ - **Menu family — `<Menu>`, `<MenuTrigger>`, `<MenuContent>`,
29
+ `<MenuItem>`, `<MenuLabel>`, `<MenuSeparator>`, `<MenuSkeleton>`
30
+ (P8, Sprint 4.4).** Compound action-menu API built on
31
+ `@radix-ui/react-dropdown-menu` — the purpose-built primitive
32
+ ships full WAI-ARIA menu pattern (`role="menu"` / `role="menuitem"`
33
+ / `role="separator"`), keyboard navigation (↑↓ Home End Enter
34
+ Esc Tab), type-ahead, focus management, and lazy portal mount.
35
+ `<MenuItem>` is `React.memo`-wrapped (Atlaskit-style perf — each
36
+ item re-renders only on prop change, not when siblings mutate).
37
+ `<MenuSkeleton>` provides Atlaskit-inspired loading state:
38
+ N placeholder rows matching real-item geometry, useful during
39
+ fetch-while-open patterns where a generic spinner would be a
40
+ perceived-perf regression. `<MenuItem color="danger">` highlights
41
+ destructive actions with a red soft-bg hover state.
42
+ Bridge integration on `<MenuItem>`: `access` (hide/disable per
43
+ RBAC) + `visibleWhen` (engine-reactive predicate — falsy → item
44
+ renders `null`, doesn't occupy a row). `closeOnItemClick` on
45
+ `<Menu>` (default `true`) for the standard action-menu pattern;
46
+ flip to `false` for filter / multi-select menus. Skipped for v1:
47
+ sub-menus (Atlaskit default — composable via Radix primitives if
48
+ needed later as additive change) and controlled selection mode
49
+ (use `<CheckboxGroup>` / `<RadioGroup>` standalone instead). New
50
+ runtime dep: `@radix-ui/react-dropdown-menu` (added to
51
+ `@dashforge/tw` `dependencies`, transitive — no consumer install
52
+ step required).
53
+ - **`<Badge>` component (P7, Sprint 4.4).** Anchored indicator
54
+ (count / dot / short text overlay) — wrapper mode. For inline
55
+ standalone pills (status labels, removable tags), use `<Chip>` —
56
+ Badge and Chip are complementary: Chip is interactive
57
+ (`onClick`, `onDelete`, `selected`), Badge is passive overlay.
58
+ API: `content` (number/string), `dot` mode, `max` (default 99,
59
+ overflow renders as `"N+"`), `showZero` (default false — typical
60
+ notification UX), `invisible` (DOM-stay hide for fade animations),
61
+ `placement` (4 corners), `overlap` (`'rectangular'` default for
62
+ IconButton / Card; `'circular'` for Avatar — adds 14% inset to
63
+ align with the round edge), `withRing` default true (auto-inverting
64
+ `ring-neutral-50` for visual separation from the anchor surface).
65
+ Default color `'danger'` matches the standard "needs attention"
66
+ notification UX (red dot/count). Bridge: `access` + `visibleWhen`
67
+ — gate the badge while the anchor always renders. Skipped: size
68
+ axis (badge sizes to content; demand emerges → add later);
69
+ standalone mode (use `<Chip>` instead — TypeScript enforces
70
+ `children` required); `<Badge.Ribbon>` corner pattern (AntD-only
71
+ edge case).
72
+ - **`<Spinner>` component (P6, Sprint 4.4).** Rotating-arc loading
73
+ indicator. SVG path + Tailwind `animate-spin` (pure CSS,
74
+ GPU-accelerated, gated on `motion-reduce` per WCAG 2.3.3). Color
75
+ inherits via `currentColor` when `color` is omitted — works
76
+ seamlessly inside `<Button>`, `<Alert>`, `<Card>`, or any colored
77
+ container with zero configuration. Pass an explicit `color`
78
+ (7 intents) for standalone usage. Size axis (`'xs' | 'sm' | 'md' |
79
+ 'lg' | 'xl'`) maps to spacing tokens; `thickness` (`'thin' | 'md' |
80
+ 'thick'`) maps to SVG `stroke-width`. **`withTrack` opt-in** renders
81
+ a faint ghost ring (20% opacity of currentColor) behind the
82
+ spinning arc — the Stripe / Vercel / Linear "premium spinner" look,
83
+ useful on busy backgrounds and for slow operations. **`delay` prop
84
+ (Atlassian-style anti-flash)** mounts the spinner as `null` for the
85
+ first N ms — quick operations that finish before the delay
86
+ never render the spinner. Pairs naturally with `visibleWhen` for
87
+ the canonical pattern `<Spinner visibleWhen={() => isSubmitting}
88
+ delay={150} />`. A11y: `role="status"` + `aria-live="polite"` +
89
+ visually-hidden label (default `'Loading'`). Decorative mode
90
+ (`label=""`) suppresses role + label entirely — used internally by
91
+ Button / IconButton loading state to avoid duplicate
92
+ announcements (the parent button already carries `aria-busy`).
93
+ **Refactor**: `<Button>` and `<IconButton>` loading state now
94
+ delegates to `<Spinner>` internally — single source of truth, the
95
+ spinner look propagates everywhere automatically if it changes.
96
+ No `access` (loading state is not permission-driven; wrap in `Box`
97
+ if needed).
98
+ - **`<Avatar>` + `<AvatarGroup>` components (P5, Sprint 4.4).**
99
+ Image / initials / icon visual identity primitive. `<Avatar>` falls
100
+ back through a 4-step chain: `src` loads OK → `<img>`; `src` fails
101
+ → initials from `name`; no `src` + `name` set → initials from
102
+ `name` (first letter of first 2 whitespace-separated words,
103
+ uppercased — Mantine-style auto-generation); everything absent →
104
+ generic user SVG icon. Visual axes: `shape: 'circle' | 'rounded' |
105
+ 'square'` (semantic shortcut) + `radius` from the full Box token
106
+ scale (explicit token wins over shape); `size: 'xs' | 'sm' | 'md' |
107
+ 'lg' | 'xl'` mapped to spacing tokens; `color` (7 intents) +
108
+ optional `tone` (50-900) for type-safe access to any palette shade.
109
+ Truly custom colours route through `sx`. `<AvatarGroup>` is a thin
110
+ horizontal wrapper with negative-margin overlap, `max` slice with
111
+ trailing "+N" overflow indicator, optional `ring-2 ring-white`
112
+ halo per child (default on), `size` propagation to children.
113
+ Skipped: built-in status/presence dots (compose with future
114
+ `<Badge>` via `<Badge dot><Avatar /></Badge>`), MUI-style nested
115
+ `<AvatarImage>` / `<AvatarFallback>` sub-components (single-element
116
+ API is more ergonomic). No `access` / `visibleWhen` — Avatar is
117
+ display-only; wrap in `<Box>` for visibility gating.
118
+ - **`<Card>`, `<CardContent>`, `<CardActionArea>` components (P2,
119
+ Sprint 4.4).** Opinionated surface preset over `<Box>`. `<Card>` is
120
+ a thin alias with card-shaped defaults (`variant='outlined'`,
121
+ `rounded='lg'`, `elevation=1`, no padding) and a restricted variant
122
+ axis (`'outlined' | 'elevated' | 'plain'` — `'soft'` / `'solid'`
123
+ belong to Box callouts and banners, not cards). `<CardContent>` is
124
+ a padded inner section (`p=4` default). `<CardActionArea>` is the
125
+ real value-add: a clickable wrapper with focus ring + hover state
126
+ + Radix Slot polymorphism (router `<Link>` without `<a>`-in-
127
+ `<button>` a11y violation) + `selected` for option-card patterns
128
+ (`aria-pressed`).
129
+ Skipped MUI's `CardHeader`, `CardMedia`, `CardActions` —
130
+ composable via `Stack` + `Box` + `Typography`, no value-add to
131
+ ship as separate components. Atlassian DS validates the
132
+ minimalist take (they ship no Card primitive at all).
133
+ - **`access` + `visibleWhen` retrofit to `<Box>` (Sprint 4.4 surface
134
+ alignment, additive).** The bridge integration is now available on
135
+ Dashforge's surface primitive too. Use case: dashboard with
136
+ role-based cards (`access` hides revenue card from non-billing
137
+ roles), state-driven sections (`visibleWhen` toggles a section
138
+ based on form / external state) without `{condition && <Box>...}`
139
+ JSX guards. Idempotent for existing consumers — both props default
140
+ to no-op. RBAC-disabled / readonly Box surfaces dim visually and
141
+ carry `aria-disabled` / `aria-readonly` so descendants and
142
+ assistive tech can react. By extension, `<Card>` (which extends
143
+ `BoxProps`) inherits both props automatically.
144
+ - **`visibleWhen` prop extended to `<Button>` + `<IconButton>` (Sprint
145
+ 4.4 alignment).** Previously available only on form fields and the
146
+ new `<Alert>` / `<Chip>`, the engine-reactive visibility predicate
147
+ now ships on the action-trigger components too. The pattern is now
148
+ uniform across every interactive Dashforge TW primitive (Button,
149
+ IconButton, Chip, plus all form fields + Alert): `visibleWhen?:
150
+ (engine: Engine) => boolean` returns `null` when false; reactive on
151
+ engine state changes inside `<DashForm>`, closure-based outside.
152
+ Idempotent for consumers who don't use it.
153
+ - **`<Chip>` component.** Public status / filter / tag pill — promoted
154
+ from the internal `Table/cells/RenderChip`. The 3 × 7 (variant ×
155
+ color) matrix is preserved byte-identical and now lives in
156
+ `Chip/chip.variants.ts` as the single source of truth, consumed by
157
+ both the public `<Chip>` and (via thin wrapper) the legacy
158
+ `RenderChip` — zero breaking change for Table cell consumers.
159
+ Variant axis is `'soft' | 'solid' | 'outline'` (default `'soft'`,
160
+ Dashforge chip vocabulary — distinct from Button's
161
+ `'solid' | 'outline' | 'ghost' | 'link'` and Alert's
162
+ `'standard' | 'filled' | 'outlined'`, see the design note in
163
+ `MIGRATION.md`). Full MUI Chip API parity: `label`, `icon`, `avatar`
164
+ (avatar wins over icon when both set), `clickable`, `onClick`,
165
+ `onDelete`, `deleteIcon`, `deleteLabel`. Plus Dashforge extras:
166
+ `selected` (filter-pill pressed state with `aria-pressed`) and
167
+ `access` (RBAC integration, same contract as `<Button>` /
168
+ `<IconButton>`). Static chips render as `<span>`; clickable chips
169
+ render as `<button>` with focus ring + hover state. 7 colors, 2
170
+ sizes.
171
+ - **`<IconButton>` component.** Square, icon-only action button —
172
+ reuses `buttonVariants` 1:1 (`variant: 'solid' | 'outline' | 'ghost'
173
+ | 'link'`, `color: 'primary' | 'secondary' | 'success' | 'warning' |
174
+ 'danger'`, `size: 'sm' | 'md' | 'lg'`, `loading`). Adds square
175
+ geometry (token-driven `w-N + px-0 + aspect-square`), a
176
+ TS-enforced `aria-label` (icon-only buttons MUST have an accessible
177
+ name), `asChild` via Radix Slot, and the standard `access` RBAC
178
+ integration. No `visibleWhen` / `slotProps` by design — mirrors
179
+ `<Button>`. Bundles `<IconButton>` exports + `ICON_BUTTON_BASE` /
180
+ `ICON_BUTTON_SIZE_OVERRIDES` constants for advanced overrides.
181
+ - **`_shared/severity/` foundation.** New shared module
182
+ (`_shared/severity/{severity.types, severityVariants, severityIcons,
183
+ index}`) consumed by `<Alert>` and the refactored `<Snackbar>` (and
184
+ future Banner). Centralises the 3×4 (variant × severity) color
185
+ matrix and the per-severity default icons. Every cell is
186
+ token-driven via `dashforgePreset()` — no hardcoded hex, no `dark:`
187
+ variants on neutral.
188
+
189
+ ### Changed (BREAKING — visual only)
190
+
191
+ - **`<Snackbar>` default appearance updated.** Snackbar now consumes
192
+ the same 3-variant severity surface as `<Alert>` (`standard` /
193
+ `filled` / `outlined`), with `standard` (soft tinted) as the new
194
+ default. Previously, severity discriminated only border + icon
195
+ colour; the surface bg + text stayed neutral. The new default
196
+ visually communicates severity at first glance (the previous
197
+ pattern read as "neutral message with coloured trim"). Consumers
198
+ who want the closest visual match to 1.0.x can pass
199
+ `variant="outlined"` on each enqueue or set
200
+ `<SnackbarProvider defaults={{ variant: 'outlined' }}>`.
201
+ - **`<Snackbar>` Unicode-glyph icons replaced with inline SVG.** The
202
+ per-severity defaults are no longer `ⓘ ✓ ⚠ ✕` Unicode glyphs but
203
+ inline stroke SVG icons shared with `<Alert>` via
204
+ `_shared/severity/severityIcons`. Consumers who want the legacy
205
+ glyphs can pass `icon={<span>{glyph}</span>}` on each enqueue.
206
+ - **`<Snackbar>` `severity="info"` now uses the dedicated `info-*`
207
+ token scale.** Previously aliased to `primary-*` (inadvertent
208
+ inconsistency with the rest of the catalog). `patchTheme({ info:
209
+ ... })` now correctly targets the info snackbar surface without
210
+ spilling into primary consumers.
211
+
212
+ ### Added — `<Snackbar>` API extensions
213
+
214
+ - **`variant` option on `enqueue()` and `defaults`** —
215
+ `'standard' | 'filled' | 'outlined'`. Same axis as `<Alert>`.
216
+ - **`icon` option on `enqueue()`** — same tristate semantics as Alert
217
+ (`undefined` → default per severity, `ReactNode` → custom, `false`
218
+ → no icon).
219
+ - New exported type `SnackbarVariant`.
220
+
221
+ ### Fixed
222
+
223
+ - **Defensive list-style reset across interactive `<ul>` lists.**
224
+ `Autocomplete` (listbox), `Pagination`, `LeftNav` (outer list + group
225
+ children), `DataGrid` column-visibility menu, and `Table` row-actions
226
+ menu now ship `list-none pl-0 m-0` directly on their `<ul>` variants
227
+ / inline classes instead of relying on the consumer environment
228
+ having Tailwind preflight active. Previously, environments without
229
+ preflight — or with a **scoped** preflight that intentionally omits
230
+ the `ol, ul { list-style: none }` reset (multi-ecosystem docs sites,
231
+ apps that opt out of preflight) — would render browser-default disc
232
+ bullets next to each option / row. The change is idempotent: in
233
+ consumers that have preflight, the new classes are no-ops; in
234
+ consumers without, the components render correctly out of the box.
235
+
236
+ ## [1.0.0] — 2026-05-23
237
+
238
+ **Stable release.** First semver-stable version. The public API is now
239
+ governed by strict semver — any future breaking change requires a major
240
+ bump. Functionally identical to the previous beta tarball.
241
+
242
+ - Version: `1.0.0`
243
+ - Cross-package `@dashforge/*` peer-dependency ranges updated to `^1.0.0`.
244
+ - See the [top-level CHANGELOG](https://github.com/kensaadi/dashforge/blob/main/CHANGELOG.md#100---2026-05-23) for the coordinated release context.
245
+ - See [`MIGRATION.md`](https://github.com/kensaadi/dashforge/blob/main/MIGRATION.md) for the upgrade guide from any `0.x-beta` to `1.0.0` (no code changes required).
246
+
15
247
  ## [0.11.0-beta] — 2026-05-22
16
248
 
17
249
  **Sprint 7 — Tabs.** `<Tabs>` rebuilt as a custom, clean-room component.
@@ -137,8 +369,8 @@ Strictly additive — no breaking changes on existing component APIs.
137
369
  starts a column-reorder drag. On coarse-pointer (touch) devices the
138
370
  reorder `draggable` affordance is disabled — native HTML5
139
371
  drag-and-drop does not fire touch events, so it was a dead
140
- interaction. (A pointer-event reorder covering touch is tracked in
141
- `REFINEMENT-NOTES.md`.)
372
+ interaction. A pointer-event reorder covering touch is tracked
373
+ internally.
142
374
  - **`Table`** now emits a dev-only `console.warn` when `getRowId` is
143
375
  omitted while sort / search / selection / expandable rows are
144
376
  active — the positional-index fallback breaks row identity on
@@ -1349,16 +1581,6 @@ have shipped as `0.2.2-beta` in isolation.
1349
1581
  Breadcrumbs in its center slot, so fixing the Breadcrumbs link
1350
1582
  fixes TopBar transitively.
1351
1583
 
1352
- ### Internal
1353
-
1354
- - **`libs/dashforge/tw/CONSUMER-VALIDATION.md`** — Sprint 2 P1
1355
- deliverable. Per-component status table for the dash-consumer
1356
- end-to-end validation pass (24 components, 7-point check each).
1357
- Records the pattern lesson that motivated the Autocomplete
1358
- async fix: the bug was invisible to both unit tests (using
1359
- static `options`) and the docs lab (static demo) — only a real
1360
- consumer with `loadOptions` configured exposed it.
1361
-
1362
1584
  ### Compatibility
1363
1585
 
1364
1586
  | Compatibility axis | Pre-`0.3.0` | Post-`0.3.0` |
package/COVERAGE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # COVERAGE — `@dashforge/tw`
2
2
 
3
- > Sprint 6 P4 deliverable (2026-05-20). Test-coverage audit + the
4
- > gap-fill done this sprint, plus the tracked debt.
3
+ > Test-coverage audit for `@dashforge/tw`. Current numbers, the gap-fill
4
+ > performed, and the tracked debt.
5
5
 
6
6
  ## Current coverage (`vitest --coverage`, v8 provider)
7
7
 
package/PARITY.md CHANGED
@@ -1,19 +1,17 @@
1
1
  # `@dashforge/tw` ↔ `@dashforge/ui` parity audit
2
2
 
3
- > Sprint 3 P1 deliverable (2026-05-19). Per-component diff between the
4
- > two Dashforge UI lines for the **10 bridge-integrated components**.
3
+ > Per-component diff between the two Dashforge UI lines for the
4
+ > **10 bridge-integrated components**.
5
5
  >
6
- > **Motivation (revised post-Sprint 2).** This audit does NOT exist to
7
- > support customer migration MUI→TW (no consumer switches across UI
8
- > ecosystems in real life). It exists because:
6
+ > **Motivation.** This audit ensures:
9
7
  >
10
8
  > 1. **Internal consistency** — a refactor on `@dashforge/ui` that
11
9
  > doesn't land on `@dashforge/tw` would otherwise be invisible.
12
- > 2. **Bridge contract validation** — proves that the same
13
- > `@dashforge/forms` schema works identically on both lines.
14
- > 3. **Foundation for Sprint 5 starter kits** — two parallel kits
10
+ > 2. **Bridge contract validation** — the same `@dashforge/forms`
11
+ > schema works identically on both lines.
12
+ > 3. **Parallel starter-kit maintainability** — two parallel kits
15
13
  > (one MUI, one TW) require call-site-level parity to stay
16
- > parallel-maintainable.
14
+ > in sync.
17
15
 
18
16
  ## Versions audited
19
17
 
package/PERFORMANCE.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # `@dashforge/tw` performance baseline
2
2
 
3
- > Sprint 3 P4 deliverable (2026-05-19). Establishes the pre-`1.0.0`
4
- > performance commitment for `@dashforge/tw@0.4.0-beta` (29
5
- > components). Every subsequent release MUST hold this line or
6
- > justify the regression in `CHANGELOG.md`.
3
+ > Establishes the performance commitment for `@dashforge/tw`. Every
4
+ > subsequent release should hold these numbers or justify any
5
+ > regression in `CHANGELOG.md`.
7
6
 
8
7
  ## Bundle size
9
8
 
package/README.md CHANGED
@@ -1,38 +1,97 @@
1
1
  # @dashforge/tw
2
2
 
3
- > **Status**: `0.1.0-beta` — first public beta. Sixteen components
4
- > shipped across forms, layout, and providers. The MUI side of
5
- > Dashforge (`@dashforge/ui`, `@dashforge/theme-mui`,
6
- > `@dashforge/theme-core`) is **fully isolated** from this package —
7
- > the two ecosystems share only the bridge layer (`@dashforge/forms` +
3
+ **A props-driven React UI library on top of Tailwind CSS.** Every utility
4
+ that matters for the public API becomes a typed prop — `size`, `color`,
5
+ `variant`, `layout`, … — so you write components that read like a design
6
+ system and render output that's pure Tailwind. Raw `className` / `sx` /
7
+ `slotProps` stay available as escape hatches for the cases the prop
8
+ surface doesn't cover.
9
+
10
+ > **Status**: `1.0.0` — **stable release**. Public API frozen, semver
11
+ > guaranteed. 37 components shipped across forms, data display,
12
+ > navigation, feedback, layout primitives, and providers. The MUI side
13
+ > of Dashforge (`@dashforge/ui`, `@dashforge/theme-mui`,
14
+ > `@dashforge/theme-core`) is **fully isolated** from this package — the
15
+ > two ecosystems share only the bridge layer (`@dashforge/forms` +
8
16
  > `@dashforge/ui-core` + `@dashforge/rbac`).
9
17
 
10
- Tailwind-rendered UI components for the Dashforge ecosystem.
11
-
12
- Components are **props-driven** (every Tailwind utility that matters
13
- for the public API becomes a typed prop — `size`, `color`, `variant`,
14
- `layout`, …). Raw `className` / `sx` / `slotProps` exist as escape
15
- hatches for the cases the prop surface doesn't cover.
18
+ ## Why Dashforge TW
19
+
20
+ - **Props, not utility soup** — component APIs that read like MUI,
21
+ render output that's pure Tailwind. No more 40-class `<button>` tags
22
+ copied across the codebase.
23
+ - **Dark mode built in** — CSS-variable inversion via the
24
+ `dashforgePreset` Tailwind preset. Same JSX renders in light and dark
25
+ without a single `dark:` variant.
26
+ - **RBAC-aware out of the box** — every interactive component takes an
27
+ `access` prop, hidden / disabled / read-only centrally via
28
+ `@dashforge/rbac`.
29
+ - **Bridge-integrated forms** — Form Closure v1, controlled error
30
+ gating, StrictMode-safe registration, per-field re-render isolation
31
+ via the shared `@dashforge/forms` engine.
32
+ - **Router-agnostic** — pass `linkComponent` to use React Router, Next,
33
+ TanStack Router, or any other navigation primitive.
34
+ - **TypeScript-first** — typed tokens, typed variants, typed slot
35
+ overrides, augmentable per-package.
16
36
 
17
37
  ## Component catalog
18
38
 
19
- ### Form components (10)
39
+ ### Form components (13)
20
40
 
21
41
  `Button` · `TextField` · `Checkbox` · `Switch` · `RadioGroup` ·
22
42
  `Textarea` · `NumberField` · `OTPField` · `Autocomplete` ·
23
- `DateTimePicker`
43
+ `DatePicker` · `DateRangePicker` · `TimePicker` · `DateTimePicker`
24
44
 
25
45
  All bridge-integrated, RBAC-aware (`access` prop), Form Closure v1
26
46
  error gating, StrictMode-safe.
27
47
 
28
- ### Layout components (4)
48
+ ### Navigation & shell (4)
29
49
 
30
- `Breadcrumbs` · `LeftNav` · `TopBar` · `AppShell`
50
+ `AppShell` · `LeftNav` · `TopBar` · `Breadcrumbs`
31
51
 
32
52
  Router-agnostic — pass a `linkComponent` prop for SPA navigation
33
53
  (React Router, Next, TanStack Router, …). Mobile-responsive shell
34
54
  with drawer + body scroll lock.
35
55
 
56
+ ### Layout primitives (8)
57
+
58
+ `Box` · `Container` · `Stack` · `Grid` · `Divider` · `AspectRatio` ·
59
+ `Typography` · `VisuallyHidden`
60
+
61
+ Polymorphic via `as` prop, dark-mode-aware, prop-driven spacing /
62
+ sizing / alignment.
63
+
64
+ ### Data display (3)
65
+
66
+ `Table` · `DataGrid` · `Pagination`
67
+
68
+ Virtualized rows, sticky columns (left + right), server-side mode,
69
+ per-column filter chips, column resize / reorder / visibility,
70
+ controlled or uncontrolled state.
71
+
72
+ ### Disclosure (2)
73
+
74
+ `Accordion` · `Tabs`
75
+
76
+ Radix-based, keyboard-accessible, fully styled through props.
77
+
78
+ ### Overlay (3)
79
+
80
+ `Dialog` · `Popover` · `Tooltip`
81
+
82
+ Portal-rendered, focus-trapped, dismiss-on-esc + click-outside
83
+ out of the box.
84
+
85
+ ### Feedback (1)
86
+
87
+ `Skeleton`
88
+
89
+ ### Date (1)
90
+
91
+ `Calendar` — standalone month grid. Also powers `DatePicker` /
92
+ `DateRangePicker` / `DateTimePicker` under the hood, but exported on
93
+ its own for custom layouts.
94
+
36
95
  ### Providers (2)
37
96
 
38
97
  `ConfirmDialogProvider` + `useConfirm()` · `SnackbarProvider` +
package/THEME-AUDIT.md CHANGED
@@ -1,15 +1,14 @@
1
1
  # THEME-AUDIT — @dashforge/tw catalog identity sweep
2
2
 
3
- > Sprint 4.3 deliverable (2026-05-19). Audit of every `@dashforge/tw`
4
- > component against the **default `dashforgePreset()` identity rule**
5
- > (memory: `feedback_dashforge_preset_is_identity`).
3
+ > Audit of every `@dashforge/tw` component against the **default
4
+ > `dashforgePreset()` identity rule**.
6
5
  >
7
6
  > **Rule recap.** The `dashforgePreset()` CSS-variable swap
8
7
  > auto-inverts the neutral palette:
9
8
  > `bg-neutral-50` / `text-neutral-900` etc. resolve to the
10
9
  > appropriate physical color via `--df-tw-color-neutral-N`. Adding a
11
10
  > `dark:` variant on a neutral class **double-inverts** the value
12
- > and breaks dark mode. The Sprint 4.1 Table fix established the
11
+ > and breaks dark mode. The Table fix established the
13
12
  > canonical patterns; Sprint 4.3 applies them to the whole catalog.
14
13
 
15
14
  ## Scoring legend
Binary file