@fictjs/ui-primitives 0.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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +181 -0
  3. package/dist/index.cjs +5091 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1123 -0
  6. package/dist/index.d.ts +1123 -0
  7. package/dist/index.js +4907 -0
  8. package/dist/index.js.map +1 -0
  9. package/docs/README.md +39 -0
  10. package/docs/accessibility.md +50 -0
  11. package/docs/api-reference.md +200 -0
  12. package/docs/architecture.md +113 -0
  13. package/docs/components/core/accessible-icon.md +23 -0
  14. package/docs/components/core/id.md +26 -0
  15. package/docs/components/core/portal.md +30 -0
  16. package/docs/components/core/presence.md +27 -0
  17. package/docs/components/core/primitive.md +22 -0
  18. package/docs/components/core/separator.md +25 -0
  19. package/docs/components/core/slot.md +25 -0
  20. package/docs/components/core/visually-hidden.md +21 -0
  21. package/docs/components/disclosure/accordion.md +33 -0
  22. package/docs/components/disclosure/collapsible.md +29 -0
  23. package/docs/components/disclosure/navigation-menu.md +43 -0
  24. package/docs/components/disclosure/tabs.md +35 -0
  25. package/docs/components/feedback/toast.md +60 -0
  26. package/docs/components/form/calendar.md +35 -0
  27. package/docs/components/form/controls.md +52 -0
  28. package/docs/components/form/date-picker.md +44 -0
  29. package/docs/components/form/form-field.md +39 -0
  30. package/docs/components/form/inputs.md +99 -0
  31. package/docs/components/interaction/dismissable-layer.md +28 -0
  32. package/docs/components/interaction/focus-scope.md +27 -0
  33. package/docs/components/interaction/live-region.md +26 -0
  34. package/docs/components/interaction/popper.md +30 -0
  35. package/docs/components/interaction/roving-focus.md +27 -0
  36. package/docs/components/interaction/scroll-lock.md +22 -0
  37. package/docs/components/layout/layout.md +61 -0
  38. package/docs/components/menu/context-menu.md +44 -0
  39. package/docs/components/menu/dropdown-menu.md +62 -0
  40. package/docs/components/menu/menubar.md +38 -0
  41. package/docs/components/overlay/alert-dialog.md +46 -0
  42. package/docs/components/overlay/command-palette.md +54 -0
  43. package/docs/components/overlay/dialog.md +69 -0
  44. package/docs/components/overlay/hover-card.md +25 -0
  45. package/docs/components/overlay/popover.md +36 -0
  46. package/docs/components/overlay/tooltip.md +28 -0
  47. package/docs/examples.md +155 -0
  48. package/docs/release.md +60 -0
  49. package/docs/testing.md +36 -0
  50. package/package.json +89 -0
@@ -0,0 +1,62 @@
1
+ # DropdownMenu
2
+
3
+ Compound dropdown menu built on Popover + roving focus.
4
+
5
+ ## Components
6
+
7
+ - `DropdownMenuRoot`
8
+ - `DropdownMenuTrigger`
9
+ - `DropdownMenuContent`
10
+ - `DropdownMenuItem`
11
+ - `DropdownMenuCheckboxItem`
12
+ - `DropdownMenuRadioGroup`
13
+ - `DropdownMenuRadioItem`
14
+ - `DropdownMenuSub`
15
+ - `DropdownMenuSubTrigger`
16
+ - `DropdownMenuSubContent`
17
+ - `DropdownMenuLabel`
18
+ - `DropdownMenuSeparator`
19
+
20
+ ## Root API
21
+
22
+ - `open?: boolean | () => boolean`
23
+ - `defaultOpen?: boolean`
24
+ - `onOpenChange?: (open: boolean) => void`
25
+
26
+ ## Item Semantics
27
+
28
+ - `DropdownMenuItem` defaults to `role="menuitem"` and closes menu unless `keepOpen`
29
+ - `DropdownMenuCheckboxItem` defaults `keepOpen=true` and exposes `data-checked`
30
+ - `DropdownMenuRadioGroup` + `DropdownMenuRadioItem` provide single-select semantics (`role="menuitemradio"`)
31
+
32
+ ## Content Behavior
33
+
34
+ - `DropdownMenuContent` renders as `role="menu"` with vertical roving focus
35
+ - Supports `portal?: boolean` through inherited popover content props
36
+ - `DropdownMenuSub*` composes nested menus with side positioning (`right/start` by default)
37
+
38
+ ## Minimal Example
39
+
40
+ ```tsx
41
+ import {
42
+ DropdownMenuRoot,
43
+ DropdownMenuTrigger,
44
+ DropdownMenuContent,
45
+ DropdownMenuItem,
46
+ DropdownMenuSeparator,
47
+ } from '@fictjs/ui-primitives'
48
+
49
+ <DropdownMenuRoot>
50
+ <DropdownMenuTrigger>Actions</DropdownMenuTrigger>
51
+ <DropdownMenuContent side="bottom" align="end">
52
+ <DropdownMenuItem>Edit</DropdownMenuItem>
53
+ <DropdownMenuSeparator />
54
+ <DropdownMenuItem>Archive</DropdownMenuItem>
55
+ </DropdownMenuContent>
56
+ </DropdownMenuRoot>
57
+ ```
58
+
59
+ ## Accessibility Notes
60
+
61
+ - Keep menu item roles aligned with behavior (`menuitem`, `menuitemcheckbox`, `menuitemradio`).
62
+ - Use roving focus with visible focus styles so keyboard users can track current item.
@@ -0,0 +1,38 @@
1
+ # Menubar
2
+
3
+ Desktop-style menubar primitives with top-level menu activation.
4
+
5
+ ## Components
6
+
7
+ - `MenubarRoot`
8
+ - `MenubarMenu`
9
+ - `MenubarTrigger`
10
+ - `MenubarContent`
11
+ - `MenubarItem`
12
+
13
+ ## Minimal Example
14
+
15
+ ```tsx
16
+ import {
17
+ MenubarRoot,
18
+ MenubarMenu,
19
+ MenubarTrigger,
20
+ MenubarContent,
21
+ MenubarItem,
22
+ } from '@fictjs/ui-primitives'
23
+
24
+ <MenubarRoot>
25
+ <MenubarMenu value="file">
26
+ <MenubarTrigger>File</MenubarTrigger>
27
+ <MenubarContent>
28
+ <MenubarItem>New</MenubarItem>
29
+ <MenubarItem>Open</MenubarItem>
30
+ </MenubarContent>
31
+ </MenubarMenu>
32
+ </MenubarRoot>
33
+ ```
34
+
35
+ ## Accessibility Notes
36
+
37
+ - Top-level triggers should remain in a single horizontal tab stop group (`menubar` semantics).
38
+ - Opening one menu should not trap focus permanently; users must escape or choose an item.
@@ -0,0 +1,46 @@
1
+ # AlertDialog
2
+
3
+ Alert dialog wrappers built on top of `Dialog` with modal semantics and `role="alertdialog"` defaults.
4
+
5
+ ## Components
6
+
7
+ - `AlertDialogRoot`
8
+ - `AlertDialogTrigger`
9
+ - `AlertDialogPortal`
10
+ - `AlertDialogOverlay`
11
+ - `AlertDialogContent`
12
+ - `AlertDialogTitle`
13
+ - `AlertDialogDescription`
14
+ - `AlertDialogAction`
15
+ - `AlertDialogCancel`
16
+
17
+ ## Minimal Example
18
+
19
+ ```tsx
20
+ import {
21
+ AlertDialogRoot,
22
+ AlertDialogTrigger,
23
+ AlertDialogOverlay,
24
+ AlertDialogContent,
25
+ AlertDialogTitle,
26
+ AlertDialogDescription,
27
+ AlertDialogCancel,
28
+ AlertDialogAction,
29
+ } from '@fictjs/ui-primitives'
30
+
31
+ <AlertDialogRoot>
32
+ <AlertDialogTrigger>Delete</AlertDialogTrigger>
33
+ <AlertDialogOverlay />
34
+ <AlertDialogContent>
35
+ <AlertDialogTitle>Delete item?</AlertDialogTitle>
36
+ <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
37
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
38
+ <AlertDialogAction>Confirm</AlertDialogAction>
39
+ </AlertDialogContent>
40
+ </AlertDialogRoot>
41
+ ```
42
+
43
+ ## Accessibility Notes
44
+
45
+ - Use concise, high-signal titles/descriptions because `alertdialog` is announced with higher urgency.
46
+ - Keep both cancel and confirm actions keyboard accessible in logical focus order.
@@ -0,0 +1,54 @@
1
+ # CommandPalette
2
+
3
+ Dialog-based command palette for searchable action lists.
4
+
5
+ ## Components
6
+
7
+ - `CommandPaletteRoot`
8
+ - `CommandPaletteTrigger`
9
+ - `CommandPaletteContent`
10
+ - `CommandPaletteInput`
11
+ - `CommandPaletteList`
12
+ - `CommandPaletteItem`
13
+ - `CommandPaletteEmpty`
14
+ - `CommandPaletteGroup`
15
+ - `CommandPaletteSeparator`
16
+ - `CommandPaletteClose`
17
+
18
+ ## Key APIs
19
+
20
+ - `CommandPaletteRoot`: controlled/uncontrolled `open`, `value`, and `query` state
21
+ - `CommandPaletteInput`: drives filtering query and supports keyboard entry into list
22
+ - `CommandPaletteItem`: supports `as/asChild`, `keywords`, `keepOpen`, and selection callbacks
23
+ - `CommandPaletteEmpty`: renders only when no items match current query
24
+
25
+ ## Minimal Example
26
+
27
+ ```tsx
28
+ import {
29
+ CommandPaletteRoot,
30
+ CommandPaletteTrigger,
31
+ CommandPaletteContent,
32
+ CommandPaletteInput,
33
+ CommandPaletteList,
34
+ CommandPaletteItem,
35
+ CommandPaletteEmpty,
36
+ } from '@fictjs/ui-primitives'
37
+
38
+ <CommandPaletteRoot>
39
+ <CommandPaletteTrigger>Open Command Menu</CommandPaletteTrigger>
40
+ <CommandPaletteContent>
41
+ <CommandPaletteInput placeholder="Type a command" />
42
+ <CommandPaletteList>
43
+ <CommandPaletteItem value="profile">Profile</CommandPaletteItem>
44
+ <CommandPaletteItem value="settings">Settings</CommandPaletteItem>
45
+ <CommandPaletteEmpty>No results</CommandPaletteEmpty>
46
+ </CommandPaletteList>
47
+ </CommandPaletteContent>
48
+ </CommandPaletteRoot>
49
+ ```
50
+
51
+ ## Accessibility Notes
52
+
53
+ - Built on dialog semantics, so focus and dismissal behavior follows overlay contracts.
54
+ - Keep command labels concise and unique for predictable keyboard filtering.
@@ -0,0 +1,69 @@
1
+ # Dialog
2
+
3
+ Compound modal/non-modal dialog primitives.
4
+
5
+ ## Components
6
+
7
+ - `DialogRoot`
8
+ - `DialogTrigger`
9
+ - `DialogPortal`
10
+ - `DialogOverlay`
11
+ - `DialogContent`
12
+ - `DialogTitle`
13
+ - `DialogDescription`
14
+ - `DialogClose`
15
+
16
+ Supports controlled/uncontrolled state via `open/defaultOpen/onOpenChange`.
17
+
18
+ ## Root API
19
+
20
+ - `DialogRoot`
21
+ - `id?: string` optional deterministic base id for content/title/description wiring
22
+ - `open?: boolean | () => boolean` controlled state
23
+ - `defaultOpen?: boolean` uncontrolled initial state
24
+ - `onOpenChange?: (open: boolean) => void`
25
+ - `modal?: boolean` default `true`
26
+
27
+ ## Composition API
28
+
29
+ - `DialogTrigger` / `DialogClose` support `asChild`
30
+ - `DialogContent` supports `onEscapeKeyDown`, `onPointerDownOutside`, `onFocusOutside`, `onInteractOutside`
31
+ - Outside handlers are interceptable: calling `event.preventDefault()` blocks dismissal
32
+
33
+ ## Content Behavior
34
+
35
+ - `DialogContent` defaults to `role="dialog"`
36
+ - `forceMount` keeps content mounted while closed (state reflects via `data-state`)
37
+ - `portal?: boolean` defaults to `true`; set `false` for inline rendering/testing
38
+ - Escape and outside interactions are handled via `DismissableLayer`
39
+ - Modal mode enables `ScrollLock` + focus trap semantics
40
+
41
+ ## Accessibility Contract
42
+
43
+ - Trigger exposes `aria-haspopup="dialog"` and `aria-controls`
44
+ - Content wires `aria-labelledby` and `aria-describedby` to `DialogTitle` / `DialogDescription`
45
+ - `DialogClose` emits close semantics through `onOpenChange`
46
+
47
+ ## Minimal Example
48
+
49
+ ```tsx
50
+ import {
51
+ DialogRoot,
52
+ DialogTrigger,
53
+ DialogOverlay,
54
+ DialogContent,
55
+ DialogTitle,
56
+ DialogDescription,
57
+ DialogClose,
58
+ } from '@fictjs/ui-primitives'
59
+
60
+ <DialogRoot>
61
+ <DialogTrigger>Open settings</DialogTrigger>
62
+ <DialogOverlay />
63
+ <DialogContent>
64
+ <DialogTitle>Settings</DialogTitle>
65
+ <DialogDescription>Update your preferences.</DialogDescription>
66
+ <DialogClose>Done</DialogClose>
67
+ </DialogContent>
68
+ </DialogRoot>
69
+ ```
@@ -0,0 +1,25 @@
1
+ # HoverCard
2
+
3
+ Interactive hover content with separate open/close delays.
4
+
5
+ ## Components
6
+
7
+ - `HoverCardRoot`
8
+ - `HoverCardTrigger`
9
+ - `HoverCardContent`
10
+
11
+ ## Minimal Example
12
+
13
+ ```tsx
14
+ import { HoverCardRoot, HoverCardTrigger, HoverCardContent } from '@fictjs/ui-primitives'
15
+
16
+ <HoverCardRoot openDelay={100} closeDelay={150}>
17
+ <HoverCardTrigger>@fictjs</HoverCardTrigger>
18
+ <HoverCardContent side="bottom">Project profile preview</HoverCardContent>
19
+ </HoverCardRoot>
20
+ ```
21
+
22
+ ## Accessibility Notes
23
+
24
+ - Hover-only disclosure is insufficient; this primitive also opens on focus for keyboard users.
25
+ - Keep hover card content supplemental and non-blocking for primary task flow.
@@ -0,0 +1,36 @@
1
+ # Popover
2
+
3
+ Floating, dismissable content anchored to a trigger.
4
+
5
+ ## Components
6
+
7
+ - `PopoverRoot`
8
+ - `PopoverTrigger`
9
+ - `PopoverContent`
10
+ - `PopoverClose`
11
+
12
+ ## Key APIs
13
+
14
+ - `PopoverRoot` accepts `id?: string` for deterministic trigger/content aria wiring
15
+ - `PopoverTrigger` and `PopoverClose` support `asChild`
16
+ - `PopoverContent` supports `onEscapeKeyDown`, `onPointerDownOutside`, `onFocusOutside`, `onInteractOutside`
17
+ - Outside handlers are interceptable: calling `event.preventDefault()` blocks dismissal
18
+
19
+ ## Minimal Example
20
+
21
+ ```tsx
22
+ import { PopoverRoot, PopoverTrigger, PopoverContent, PopoverClose } from '@fictjs/ui-primitives'
23
+
24
+ <PopoverRoot>
25
+ <PopoverTrigger>Open filters</PopoverTrigger>
26
+ <PopoverContent side="bottom" align="start">
27
+ Filter options
28
+ <PopoverClose>Close</PopoverClose>
29
+ </PopoverContent>
30
+ </PopoverRoot>
31
+ ```
32
+
33
+ ## Accessibility Notes
34
+
35
+ - Popover content should expose an appropriate role (`dialog` by default in this implementation).
36
+ - Provide a deterministic close action in addition to outside dismissal.
@@ -0,0 +1,28 @@
1
+ # Tooltip
2
+
3
+ Hover/focus tooltip primitives with open delay.
4
+
5
+ ## Components
6
+
7
+ - `TooltipProvider`
8
+ - `TooltipRoot`
9
+ - `TooltipTrigger`
10
+ - `TooltipContent`
11
+
12
+ ## Minimal Example
13
+
14
+ ```tsx
15
+ import { TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent } from '@fictjs/ui-primitives'
16
+
17
+ <TooltipProvider delayDuration={200}>
18
+ <TooltipRoot>
19
+ <TooltipTrigger>Hover me</TooltipTrigger>
20
+ <TooltipContent side="top">Helpful hint</TooltipContent>
21
+ </TooltipRoot>
22
+ </TooltipProvider>
23
+ ```
24
+
25
+ ## Accessibility Notes
26
+
27
+ - Tooltip text should supplement, not replace, the control's accessible name.
28
+ - Keep tooltip content short and avoid interactive controls inside tooltip surfaces.
@@ -0,0 +1,155 @@
1
+ # Usage Examples
2
+
3
+ Examples below use TSX syntax with `@fictjs/ui-primitives`.
4
+
5
+ For a runnable end-to-end demo, see `examples/README.md`.
6
+
7
+ ## Dialog (controlled)
8
+
9
+ ```tsx
10
+ import { createSignal } from '@fictjs/runtime/advanced'
11
+ import {
12
+ DialogRoot,
13
+ DialogTrigger,
14
+ DialogOverlay,
15
+ DialogContent,
16
+ DialogTitle,
17
+ DialogDescription,
18
+ DialogClose,
19
+ } from '@fictjs/ui-primitives'
20
+
21
+ const open = createSignal(false)
22
+
23
+ <DialogRoot open={() => open()} onOpenChange={next => open(next)}>
24
+ <DialogTrigger>Edit profile</DialogTrigger>
25
+ <DialogOverlay class="overlay" />
26
+ <DialogContent>
27
+ <DialogTitle>Profile</DialogTitle>
28
+ <DialogDescription>Update your display settings.</DialogDescription>
29
+ <DialogClose>Done</DialogClose>
30
+ </DialogContent>
31
+ </DialogRoot>
32
+ ```
33
+
34
+ ## Dropdown Menu (checkbox + radio)
35
+
36
+ ```tsx
37
+ import {
38
+ DropdownMenuRoot,
39
+ DropdownMenuTrigger,
40
+ DropdownMenuContent,
41
+ DropdownMenuCheckboxItem,
42
+ DropdownMenuRadioGroup,
43
+ DropdownMenuRadioItem,
44
+ } from '@fictjs/ui-primitives'
45
+
46
+ <DropdownMenuRoot>
47
+ <DropdownMenuTrigger>Preferences</DropdownMenuTrigger>
48
+ <DropdownMenuContent side="bottom" align="start">
49
+ <DropdownMenuCheckboxItem defaultChecked>Show line numbers</DropdownMenuCheckboxItem>
50
+ <DropdownMenuRadioGroup defaultValue="compact">
51
+ <DropdownMenuRadioItem value="compact">Compact</DropdownMenuRadioItem>
52
+ <DropdownMenuRadioItem value="comfortable">Comfortable</DropdownMenuRadioItem>
53
+ </DropdownMenuRadioGroup>
54
+ </DropdownMenuContent>
55
+ </DropdownMenuRoot>
56
+ ```
57
+
58
+ ## Toast (hook + viewport)
59
+
60
+ ```tsx
61
+ import { ToastProvider, ToastViewport, useToast } from '@fictjs/ui-primitives'
62
+
63
+ function SaveButton() {
64
+ const toast = useToast()
65
+ return (
66
+ <button
67
+ type="button"
68
+ onClick={() => toast.show({ title: 'Saved', description: 'Changes were persisted.' })}
69
+ >
70
+ Save
71
+ </button>
72
+ )
73
+ }
74
+
75
+ <ToastProvider duration={4000}>
76
+ <SaveButton />
77
+ <ToastViewport />
78
+ </ToastProvider>
79
+ ```
80
+
81
+ ## Tabs (controlled)
82
+
83
+ ```tsx
84
+ import { createSignal } from '@fictjs/runtime/advanced'
85
+ import { TabsRoot, TabsList, TabsTrigger, TabsContent } from '@fictjs/ui-primitives'
86
+
87
+ const tab = createSignal('account')
88
+
89
+ <TabsRoot value={() => tab()} onValueChange={next => tab(next)}>
90
+ <TabsList>
91
+ <TabsTrigger value="account">Account</TabsTrigger>
92
+ <TabsTrigger value="security">Security</TabsTrigger>
93
+ </TabsList>
94
+ <TabsContent value="account">Account settings</TabsContent>
95
+ <TabsContent value="security" forceMount>
96
+ Security settings
97
+ </TabsContent>
98
+ </TabsRoot>
99
+ ```
100
+
101
+ ## Form Field (label + message wiring)
102
+
103
+ ```tsx
104
+ import {
105
+ Form,
106
+ FormField,
107
+ FormLabel,
108
+ FormControl,
109
+ FormDescription,
110
+ FormMessage,
111
+ } from '@fictjs/ui-primitives'
112
+
113
+ <Form>
114
+ <FormField name="email">
115
+ <FormLabel>Email</FormLabel>
116
+ <FormControl as="input" type="email" required />
117
+ <FormDescription>Use your work email.</FormDescription>
118
+ <FormMessage>Invalid email format.</FormMessage>
119
+ </FormField>
120
+ </Form>
121
+ ```
122
+
123
+ ## Select + Combobox
124
+
125
+ ```tsx
126
+ import {
127
+ SelectRoot,
128
+ SelectTrigger,
129
+ SelectValue,
130
+ SelectContent,
131
+ SelectItem,
132
+ ComboboxRoot,
133
+ ComboboxInput,
134
+ ComboboxList,
135
+ ComboboxItem,
136
+ } from '@fictjs/ui-primitives'
137
+
138
+ <SelectRoot defaultValue="apple">
139
+ <SelectTrigger>
140
+ <SelectValue placeholder="Choose fruit" />
141
+ </SelectTrigger>
142
+ <SelectContent>
143
+ <SelectItem value="apple">Apple</SelectItem>
144
+ <SelectItem value="orange">Orange</SelectItem>
145
+ </SelectContent>
146
+ </SelectRoot>
147
+
148
+ <ComboboxRoot>
149
+ <ComboboxInput placeholder="Search assignee" />
150
+ <ComboboxList>
151
+ <ComboboxItem value="alice">Alice</ComboboxItem>
152
+ <ComboboxItem value="bob">Bob</ComboboxItem>
153
+ </ComboboxList>
154
+ </ComboboxRoot>
155
+ ```
@@ -0,0 +1,60 @@
1
+ # Release Checklist
2
+
3
+ Use this checklist for publishing `@fictjs/ui-primitives`.
4
+
5
+ ## 1. Pre-release validation
6
+
7
+ Run all quality gates:
8
+
9
+ ```bash
10
+ pnpm lint
11
+ pnpm typecheck
12
+ pnpm test
13
+ pnpm build
14
+ pnpm examples:build
15
+ ```
16
+
17
+ If visual or interaction behavior changed:
18
+
19
+ ```bash
20
+ pnpm examples:screenshots
21
+ ```
22
+
23
+ ## 2. Documentation validation
24
+
25
+ Confirm docs are updated for behavior/API changes:
26
+
27
+ - `README.md`
28
+ - `docs/components/*`
29
+ - `docs/api-reference.md` (if exports changed)
30
+ - `docs/testing.md` / `docs/accessibility.md` where relevant
31
+ - `examples/README.md` if demo workflow changed
32
+
33
+ ## 3. Versioning
34
+
35
+ Bump version in `package.json` using your preferred release process.
36
+
37
+ Example (patch):
38
+
39
+ ```bash
40
+ pnpm version patch
41
+ ```
42
+
43
+ ## 4. Publish
44
+
45
+ Publish from a clean git state.
46
+
47
+ ```bash
48
+ pnpm publish --access public --provenance --no-git-checks
49
+ ```
50
+
51
+ Notes:
52
+
53
+ - Package already includes `publishConfig.access=public` and `provenance=true`.
54
+ - Remove `--no-git-checks` if your release environment enforces clean checks automatically.
55
+
56
+ ## 5. Post-publish
57
+
58
+ - Verify package on npm registry
59
+ - Verify install in a clean consumer app
60
+ - Tag release in git and attach release notes
@@ -0,0 +1,36 @@
1
+ # Testing Notes
2
+
3
+ This package uses Vitest + JSDOM and focuses on behavior-level tests instead of snapshot-only assertions.
4
+
5
+ ## Current coverage focus
6
+
7
+ - Controlled vs uncontrolled state for core compound components
8
+ - Open/close semantics for overlay/menu/disclosure primitives
9
+ - Accessibility state attributes (`aria-*`, `role`, `data-state`)
10
+ - Keyboard and pointer dismissal boundaries
11
+ - Queue and timeout lifecycle for Toast
12
+
13
+ ## Run locally
14
+
15
+ ```bash
16
+ pnpm test
17
+ pnpm test:coverage
18
+ ```
19
+
20
+ For demo-level visual checks:
21
+
22
+ ```bash
23
+ pnpm examples:build
24
+ pnpm examples:screenshots
25
+ ```
26
+
27
+ See also:
28
+
29
+ - `docs/accessibility.md` for manual a11y verification contracts
30
+ - `docs/examples.md` for copyable composition patterns
31
+
32
+ ## When adding components
33
+
34
+ 1. Add at least one uncontrolled test and one controlled test.
35
+ 2. Add one accessibility-semantic assertion (`role`, `aria-*`, or keyboard behavior).
36
+ 3. Add one cleanup/dispose or close-path assertion.