@dev-dga/react 0.4.0 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,111 @@
1
1
  # @dev-dga/react
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ #### Components (7 new)
8
+
9
+ - **`DatePicker`** — single-date picker on `react-aria-components` + `@internationalized/date` (new deps). Gregorian ↔ Hijri (Umm al-Qura) toggle via a scoped `I18nProvider`; the public value stays `Date | null`. Month + Year `<select>` dropdowns in the header, outside-month days selectable, today indicator, optional dual-calendar display, Latin digits at all times (DGA convention), RTL-native. 28 unit + 10 Playwright tests.
10
+
11
+ - **`FileUpload`** — controlled, presentational uploader (no network I/O). Owns selection (drag-drop + click + keyboard), validation (`accept` / `maxSize` / `maxFiles`) with reject-before-accept (`onFilesAdded(File[])` / `onFilesRejected(rejections)` carrying `file-too-large` / `file-invalid-type` / `too-many-files`), and renders the file list with a per-row `Progress` bar. The consumer owns the `files` array and performs the upload. Accessible drop zone (focusable input; drag-drop is a mouse enhancement). New internal `Upload` icon.
12
+
13
+ - **`Slider`** — range input on Radix Slider. Single **and** range in one component: pass a `number` for one thumb or `number[]` for a range, and the emitted value mirrors that shape. `showValue` readout + `formatValue` (→ `aria-valuetext`), range `thumbLabels`, sizes, error state. RTL-native via the provider direction.
14
+
15
+ - **`NumberInput`** — numeric field with flanking − / + steppers. `value: number | null` (controlled/uncontrolled); free typing clamped to `[min, max]` on blur while `step` drives the buttons + ArrowUp/Down; a focused string draft preserves partials (`-`, `1.`); non-numeric input is rejected at `onChange`; display stays plain-decimal (no scientific notation). Latin + LTR digits inside RTL forms, `inputmode` numeric/decimal. New internal `Plus` icon.
16
+
17
+ - **`Rating`** — star rating, interactive (`role="slider"`: Arrow/Home/End + pointer half-detection) or `readOnly` (`role="img"`). Whole or half-star (`allowHalf`) precision; RTL-aware fill + pointer math. `max`, sizes, error tint, `formatValueText` (i18n). Recolor via the `--ddga-rating-color` CSS variable. New solid `Star` icon.
18
+
19
+ - **`Toggle` + `ToggleGroup` + `ToggleGroupItem`** — Radix Toggle. Standalone two-state button (`role="button"` + `aria-pressed`) plus a group that is a segmented control (`type="single"`) or a multi-select toolbar (`type="multiple"`), via a discriminated union on `type`. `default` / `outline` variants (outline joins items into one segmented bar), sizes; item visuals cascade from the group via CSS. Dev-warns on a missing group accessible name.
20
+
21
+ - **`DescriptionList` + `DescriptionItem` + `DescriptionTerm` + `DescriptionDetails`** — semantic `<dl>/<dt>/<dd>` key–value list for review / summary screens. `orientation` horizontal (label beside value, auto-stacks under 480px) or vertical; `divided` rows; term-column width via the `--ddga-dl-term-width` CSS variable. RTL via logical properties. No Radix.
22
+
23
+ #### Architecture
24
+
25
+ - **Body-level portal container for overlays.** `DgaProvider` now creates a `<div data-slot="dga-portal">` appended to `document.body` and exposes it as `DgaContext.portalEl`, mirroring `data-theme` / `dir` / theme CSS variables. All overlay components (Tooltip, Modal, Drawer, DropdownMenu, Select, Combobox, DatePicker) portal there instead of `rootEl`, so they escape any consumer `overflow: hidden` / `transform` ancestor while still inheriting theming. Falls back to `rootEl` during SSR / first commit.
26
+
27
+ #### Tooling
28
+
29
+ - **Bundle-size budgets** (`size-limit`, brotli) per component with a CI gate that fails PRs on regression.
30
+
31
+ #### New dependencies
32
+
33
+ - `react-aria-components` and `@internationalized/date` (DatePicker only; both externalized in the build).
34
+
35
+ ## 0.5.0
36
+
37
+ ### Minor Changes
38
+
39
+ #### Navigation batch (5 components)
40
+
41
+ - **`Tabs`** — Radix Tabs compound (`Tabs` + `TabsList` + `TabsTrigger` + `TabsContent`). Two variants — `line` (underline indicator) and `pill` (filled pill on muted bg) — cascade from the root via CSS so a single source-of-truth on the root drives the look. Sizes `sm`/`md`, `fullWidth` on `TabsList`, `orientation` horizontal/vertical, `activationMode` automatic/manual pass through to Radix. Indicator uses logical properties so RTL flip is free (Radix wires `dir` from `DgaProvider`). `asChild` on `Trigger`/`Content` via Radix native. Disabled state matches `[data-disabled]` and `[aria-disabled='true']` for asChild parity. 21 unit tests + 7 Playwright tests covering the JSDOM-impossible flows (Arrow LTR/RTL, Home/End, manual activation, disabled-skip, vertical).
42
+
43
+ - **`Breadcrumb`** — shadcn-style compound (`Breadcrumb` + `BreadcrumbList` + `BreadcrumbItem` + `BreadcrumbLink` + `BreadcrumbPage` + `BreadcrumbSeparator` + `BreadcrumbEllipsis`). `<nav aria-label="Breadcrumb">` default with `<ol>` semantic list. Current page uses `aria-current="page"` (not a link); separators are `role="presentation" aria-hidden` and the default `ChevronRight` flips via `[dir='rtl'] transform: scaleX(-1)`. `asChild` on `Link` + `Page` for router/heading composition.
44
+
45
+ - **`Pagination`** — shadcn-style compound (`Pagination` + `PaginationContent` + `PaginationItem` + `PaginationLink` + `PaginationPrevious` + `PaginationNext` + `PaginationEllipsis`). `PaginationLink` has `isActive` as the single source of truth for both visual state and `aria-current='page'` (can't drift). Previous/Next chevrons flip via CSS so "back" and "forward" are always direction-correct.
46
+
47
+ - **`Accordion`** — Radix Accordion compound (`Accordion` + `AccordionItem` + `AccordionTrigger` + `AccordionContent`). Discriminated union on `type`: `'single'` (with optional `collapsible`) vs `'multiple'`. `ChevronDown` rotates 180° via `data-state='open'`. Content height animated using Radix's `--radix-accordion-content-height` CSS var (inner div carries padding so the clipped wrapper doesn't pop).
48
+
49
+ - **`Steps`** — visual-only stepper. `<ol>` semantic list; each `Step` has `state: 'completed' | 'current' | 'upcoming'` as the single source of truth for both `aria-current='step'` and visual classes. Indicator is a numbered circle for current/upcoming and a primary-filled check for completed. Separator lines drawn as `::before` pseudo-elements between siblings (primary when both adjacent steps are completed, neutral otherwise). Horizontal + vertical orientations.
50
+
51
+ #### Next-wave batch (6 components)
52
+
53
+ - **`Spinner`** — promoted from internal to public. Animated SVG loading indicator with cva `size` variants (sm/md/lg), `role='status'` + default `aria-label='Loading'`. Passing `aria-hidden='true'` (e.g. from a Button label) drops both so it stays invisible to AT inside an already-labeled parent. Sized via inherited `font-size` (1em) unless an explicit `size` is passed.
54
+
55
+ - **`Skeleton`** — pure-CSS placeholder. `shape: text | circle | rectangle`, `animation: pulse | wave | none`, plus numeric or string `width`/`height` props. Decorative — `aria-hidden` by default; parent surface should carry `aria-busy`. RTL shimmer reverses direction; `prefers-reduced-motion` suppresses both animations.
56
+
57
+ - **`Progress` + `CircularProgress`** — linear bar (Radix Progress) plus a custom-SVG circular ring. Both share `value`/`max`/`size` (sm/md/lg)/`color` (primary/success/warning/destructive). `value=null` (or omitted) renders the indeterminate animation. `data-state` mirrors Radix vocabulary (`loading` / `complete` / `indeterminate`) across both so consumers can target one selector. `CircularProgress` supports an optional inline `showLabel` and a `thickness` override; SVG dasharray math handles the determinate offset. RTL indeterminate slide reverses on the linear bar; `prefers-reduced-motion` drops both animations.
58
+
59
+ - **`DropdownMenu`** — Radix DropdownMenu compound (`Root` + `Trigger` + `Content` + `Item` + `CheckboxItem` + `RadioGroup`/`RadioItem` + `Label` + `Separator` + `Group` + `Sub`/`SubTrigger`/`SubContent`). Portal anchored to `DgaContext.rootEl` so theming + dark mode inherit (regression test mirrors Select). Items support `startIcon` + `shortcut` hint + `destructive`. **`CheckboxItem` and `RadioItem` default `onSelect` to `preventDefault`** so the menu stays open across toggles — multi-select + radio confirmation feel right; consumers override by passing their own `onSelect`. Sub chevron flips in RTL. 15 unit tests + 9 Playwright tests covering click/Space open, Arrow + Home/End, ESC close + focus return, type-ahead, ArrowRight/Left submenu (incl. RTL), disabled-skip.
60
+
61
+ - **`Drawer`** — off-canvas panel on Radix Dialog. Same focus-trap + scroll-lock + ESC + overlay-click contract as `Modal`, but slides in from an edge. `side: 'start' | 'end' | 'top' | 'bottom'` is logical (`start`/`end` flip in RTL); slide animations branch on `[dir]` so the panel always emerges from the correct edge. `size` (sm/md/lg/full) controls inline-size for start/end and block-size for top/bottom, capped at viewport. Compound: `Trigger` + `Content` + `Header` + `Title` + `Description` + `Body` (scrollable) + `Footer` + `Close`. Portal anchored to `DgaContext.rootEl`. 7 Playwright tests for focus trap (12-cycle Tab + Shift+Tab), ESC + focus return, overlay/X close, and scroll lock — also retroactively cover `Modal` (same Radix Dialog underneath).
62
+
63
+ - **`Combobox` + `ComboboxItem` + `ComboboxGroup` + `ComboboxSeparator`** — searchable Select built on Radix Popover + `cmdk` (new dep, see below). Closed compound: pass `ComboboxItem` children (+ optional `ComboboxGroup`/`ComboboxSeparator`). Field a11y wires the same way as Select (`label`/`helperText`/`error`/`errorMessage`/`required`). Synchronous `React.Children` traversal builds the value → label map so the trigger renders the right label on first paint without waiting for the popover to open. `getLabel` prop overrides the lookup for async-loaded options. `keywords` on `ComboboxItem` are extra search terms cmdk matches (synonyms / aliases). 23 unit tests + 8 Playwright tests.
64
+
65
+ #### Button extensions
66
+
67
+ - **3 destructive sub-variants** — `destructive-outline`, `destructive-subtle`, `destructive-ghost` — paralleling the existing non-destructive family.
68
+ - **`inverted` prop** for non-filled variants (outline/ghost/subtle) when rendered on colored or dark surfaces (filled variants ignore it).
69
+
70
+ #### Badge `dismissible`
71
+
72
+ - New `dismissible` + `open` (controlled) + `onDismiss` + `closeLabel` (i18n) props turn `Badge` into the DGA Tag/Chip pattern without a new component. Uncontrolled: clicking the close button hides the badge. Controlled: `open` owns visibility; `onDismiss` is the only signal. Reuses the internal `Close` icon. Dev-warns when combined with `asChild` (would nest an interactive button inside the consumer's `<a>` — invalid HTML); close button is suppressed in that combo.
73
+
74
+ ### Patch Changes
75
+
76
+ - **Vitest 2.x matcher augmentation fix.** `jest-dom` and `vitest-axe` both ship augmentations targeting `vitest`'s `Assertion<T>` (or the legacy `Vi.Assertion`), but Vitest 2.x declares the interface inside `@vitest/expect` and only re-exports it from `vitest` — so neither upstream augmentation actually applied. `src/test/matchers.d.ts` consolidates the augmentation against `@vitest/expect` + the global `jest.Matchers` namespace; the prior `vitest-axe.d.ts` shim is folded in and deleted. Runtime was unaffected (the setup file's `expect.extend(matchers)` works regardless); the symptom was `pnpm typecheck` silently failing for every `toBeInTheDocument` / `toHaveNoViolations` assertion.
77
+ - **`Radio` Storybook documentation.** Added `tags: ['autodocs']` and a component-level description covering the compound-API contract, `useFieldA11y` wiring, and controlled/uncontrolled modes. (No code change.)
78
+ - **Spinner CSS moved out of `button.css`.** `.ddga-spinner` + `@keyframes ddga-spin` + the spinner clause of `prefers-reduced-motion` now live in `spinner.css`. The `.ddga-spinner` class name is preserved so existing Button spinner-class assertions still hit. `button.css` keeps the Button-specific `transition: none` in the reduced-motion media query.
79
+ - **Playwright e2e harness.** Standalone Playwright in `apps/docs/e2e/`, Chromium-only, drives the Storybook dev server via `playwright.config.ts`'s `webServer` block. New scripts: `pnpm --filter docs test:e2e[:install]`. CI step appended to the existing `verify` job with browser cache keyed on `pnpm-lock.yaml` hash. Specs in this release: `tabs.spec.ts` (7 tests), `dropdown-menu.spec.ts` (9), `drawer.spec.ts` (7), `combobox.spec.ts` (8).
80
+
81
+ ### New Dependencies
82
+
83
+ - **`cmdk@^1.1.1`** — for `Combobox`. Direct dep + `tsup` external so consumers transitively install it. ~3KB additional install footprint.
84
+
85
+ ## 0.4.0
86
+
87
+ ### Minor Changes
88
+
89
+ #### Display batch (4 components)
90
+
91
+ - **`Card`** — compound (`Card` + `CardImage` + `CardHeader` + `CardTitle` + `CardDescription` + `CardContent` + `CardFooter`). 6 variants: `default`, `outline`, `elevated`, `filled`, `gradient` (SA-Green hero), `ghost` (bare). `padding` scale (`sm`/`md`/`lg`), `interactive` (hover + focus ring), `orientation` (`vertical`/`horizontal` for side-by-side media + content). `CardImage` with `aspectRatio`. `asChild` on the root + every subcomponent.
92
+
93
+ - **`Badge`** — 14 variants total: 8 solid (`default`, `primary`, `secondary`, `outline`, `destructive`, `success`, `warning`, `info`) + 6 subtle/tonal counterparts (`primary-subtle`, `secondary-subtle`, `destructive-subtle`, `success-subtle`, `warning-subtle`, `info-subtle`). Sizes `sm`/`md`. `dot` prop (status pill), `startIcon`/`endIcon` props (parallel to Button). `asChild`.
94
+
95
+ - **`Divider`** — `orientation` horizontal/vertical, `variant` solid/dashed, optional label `children` with `labelPosition` start/center/end (logical, RTL-aware). `decorative` prop strips the role from the a11y tree.
96
+
97
+ - **`Avatar`** — built on Radix Avatar primitive. Compound (`Avatar` + `AvatarImage` + `AvatarFallback` + `AvatarGroup`). Sizes `xs`/`sm`/`md`/`lg`/`xl`, shapes `circle`/`square`, `status` corner indicator (`online`/`busy`/`away`/`offline`, RTL-aware). `AvatarFallback` ships `colorScheme` with 7 tonal `-100`/`-700` pairs. `AvatarGroup` cascades size/shape to children and collapses overflow into a `+N` chip.
98
+
99
+ #### Feedback / overlay batch (4 components)
100
+
101
+ - **`Tooltip`** — Radix Tooltip. Compound (`Tooltip` + `TooltipTrigger` + `TooltipContent`). Sizes `sm`/`md`. `arrow` (default true) + `sideOffset` (default 6). Portal anchored to `DgaContext.rootEl` for theme inheritance. `TooltipProvider` already nested in `DgaProvider` — no extra setup needed. `asChild` on `Trigger` via Radix native.
102
+
103
+ - **`Alert`** — compound (`Alert` + `AlertTitle` + `AlertDescription`). 4 variants (`info`/`success`/`warning`/`destructive`) using a subtle tonal palette plus an accent edge. Default per-variant icon from internal icons (Info / Check / AlertTriangle / AlertCircle); override via `icon` prop or hide with `icon={false}`. `dismissible` (uncontrolled or `open`-controlled). `live: 'polite' | 'assertive'` toggles role + aria-live. `asChild` on root.
104
+
105
+ - **`Modal`** — Radix Dialog. Compound (`Modal` + `ModalTrigger` + `ModalContent` + `ModalHeader` + `ModalTitle` + `ModalDescription` + `ModalFooter` + `ModalClose`). Sizes `sm`/`md`/`lg`/`xl`/`full`. `showCloseButton` (corner X, default true) + `closeLabel` for i18n. Portal anchored to `DgaContext.rootEl`. `aria-labelledby`/`aria-describedby` auto-wired by Radix `Title`/`Description`. Focus trap + scroll lock + ESC/overlay close handled by Radix.
106
+
107
+ - **`Toast`** — Radix Toast + module-level singleton store (Sonner pattern). Imperative API: `toast()`, `toast.success/info/warning/error/destructive/dismiss`. `<Toaster />` mounted once inside `DgaProvider`. 5 variants with per-variant icons + accent edge. 6 logical positions (`top`/`bottom` × `start`/`center`/`end`; `start`/`end` flip in RTL). `duration` per-toast or via Toaster default. `action: { label, onClick }`, `closeButton`, `closeLabel`. Reusing the same `id` updates in place (loading → success pattern). z-index 70 (above Modal).
108
+
3
109
  ## 0.3.0
4
110
 
5
111
  ### Breaking Changes
package/README.md CHANGED
@@ -82,7 +82,15 @@ function MyField({ label, helperText, error, errorMessage, ...rest }) {
82
82
 
83
83
  ## Components
84
84
 
85
- **Form:** `Button` · `Input` · `Textarea` · `Checkbox` · `RadioGroup` + `Radio` · `Switch` · `Select` + `SelectItem`
85
+ **Form:** `Button` · `Input` · `Textarea` · `NumberInput` · `Checkbox` · `RadioGroup` + `Radio` · `Switch` · `Select` + `SelectItem` · `Combobox` + `ComboboxItem` (+ `ComboboxGroup` · `ComboboxSeparator`) · `DatePicker` (Hijri toggle) · `Slider` (single/range) · `Rating` (half-star) · `FileUpload` · `Toggle` + `ToggleGroup` (+ `ToggleGroupItem`)
86
+
87
+ **Display:** `Card` (+ `CardImage`/`CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`) · `Badge` · `Divider` · `Avatar` (+ `AvatarImage`/`AvatarFallback`/`AvatarGroup`) · `DescriptionList` (+ `DescriptionItem`/`DescriptionTerm`/`DescriptionDetails`)
88
+
89
+ **Feedback / overlay:** `Tooltip` · `Alert` · `Modal` · `Toast` (imperative API) · `Drawer` (off-canvas, 4 sides) · `DropdownMenu` (compound w/ CheckboxItem, RadioGroup, Sub)
90
+
91
+ **Navigation:** `Tabs` · `Breadcrumb` · `Pagination` · `Accordion` · `Steps`
92
+
93
+ **Status:** `Spinner` · `Skeleton` · `Progress` + `CircularProgress`
86
94
 
87
95
  **Primitives:** `DgaProvider` · `useDga` · `useDir` · `useFieldA11y` · `FieldMessage` · `cn`
88
96