@abuzareal/contour-ui 0.6.0 → 0.6.2
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 +8 -0
- package/COMBOBOX.md +4 -4
- package/COMPOSITION.md +4 -0
- package/CONTRACTS.md +11 -11
- package/DOCS.md +8 -2
- package/FORMS.md +4 -0
- package/FOUNDATION.md +1 -1
- package/GETTING-STARTED.md +7 -3
- package/HELPERS.md +33 -0
- package/HOOKS.md +67 -0
- package/MANUAL-QA.md +38 -0
- package/MIGRATION.md +44 -0
- package/MODELS.md +18 -0
- package/NEXTJS.md +1 -1
- package/OVERLAYS.md +6 -0
- package/PROP-REFERENCE.md +37 -0
- package/PUBLIC-API.md +166 -166
- package/README.md +5 -3
- package/RECIPES.md +3 -3
- package/REFERENCE.md +193 -0
- package/RELEASING.md +7 -1
- package/STYLING.md +4 -0
- package/SUPPORT.md +36 -0
- package/THREE.md +40 -0
- package/dist/components/ui/Combobox.js +18 -3
- package/dist/components/ui/Tooltip.js +1 -1
- package/dist/hooks/useInitialHashScroll.js +5 -1
- package/dist/hooks/usePrintPreparation.js +12 -1
- package/dist/hooks/useScrollSpy.js +6 -3
- package/docs/prop-metadata.json +2668 -0
- package/examples/onboarding/SettingsForm.jsx +30 -0
- package/examples/onboarding/SettingsForm.tsx +50 -0
- package/examples/reference/HookExamples.tsx +146 -0
- package/examples/reproduction/README.md +1 -1
- package/examples/reproduction/package.json +1 -1
- package/examples/starters/next/README.md +1 -1
- package/examples/starters/next/package.json +1 -1
- package/examples/starters/vite/README.md +1 -1
- package/examples/starters/vite/package.json +1 -1
- package/package.json +22 -4
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Use it when you want this visual style with typed controls, feedback, navigation
|
|
|
6
6
|
|
|
7
7
|
[Live catalogue](https://contour.abuzr.in/) · [npm package](https://www.npmjs.com/package/@abuzareal/contour-ui) · [Maintainer](https://github.com/abuzareal)
|
|
8
8
|
|
|
9
|
-
This source checkout targets **0.6.
|
|
9
|
+
This source checkout targets **0.6.2**. Package publication and application upgrades are separate; check the npm registry for release availability and each application's manifest for its installed version. Catalogue examples include application patterns as well as package components. Check the exports below before treating an example as an importable component.
|
|
10
10
|
|
|
11
11
|
[Public API and maturity register](PUBLIC-API.md) · [Architecture, scope and compatibility](CONTRACTS.md)
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ Version 0.6 adds a single-select [Combobox](COMBOBOX.md) backed by pinned Base U
|
|
|
23
23
|
Use an existing React application with a bundler that resolves package CSS imports. Contour ships ESM and TypeScript declarations. The package declares Node.js 22 or newer; repository tooling uses Vite 8, which needs Node.js 22.12+ or 24+.
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
|
-
npm install @abuzareal/contour-ui@0.6.
|
|
26
|
+
npm install @abuzareal/contour-ui@0.6.2 --save-exact
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Your app must provide matching `react` and `react-dom` versions: **18.3.1 or React 19**. The compatibility script covers 18.3.1, 19.0.0, and 19.3.0; it doesn't establish support for every framework or React Server Component setup. Put interactive components inside a client boundary when your framework requires one.
|
|
@@ -180,7 +180,7 @@ Give scenes a sized container and a usable static fallback. `SceneBoundary` hide
|
|
|
180
180
|
**0.2.0** adds native field refs, controlled tabs and popover/menu open state, menu keyboard improvements, native reset synchronization, Three.js lifecycle fixes and a tested Next.js App Router integration. Existing uncontrolled defaults and React 18/19 support remain. `fonts-latin.css`, introduced in 0.1.2, now uses packaged relative font URLs for webpack resolution. `CHANGELOG.md` is included in the package archive and [npm's Code view](https://www.npmjs.com/package/@abuzareal/contour-ui?activeTab=code); it contains the upgrade details for each version.
|
|
181
181
|
|
|
182
182
|
```sh
|
|
183
|
-
npm install @abuzareal/contour-ui@0.6.
|
|
183
|
+
npm install @abuzareal/contour-ui@0.6.2 --save-exact
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
Commit your manifest and lockfile, run your application's checks, and review both themes, dialogs, forms, and motion before deploying. Version 0.1.1 includes a document scroll lock for dialogs and drawers. Review any app-level lock before removing it, including nested dialogs and short screens. Package publication doesn't update deployed consumers automatically.
|
|
@@ -259,3 +259,5 @@ Legacy aggregate styles remain global. The new isolated CSS path is documented i
|
|
|
259
259
|
Menus and popovers remain local panels without portals or collision detection; use them where the container can accommodate their content. No submenu or arbitrary trigger-composition contract is claimed. BrandMark and page/editorial helpers preserve existing identity and layout assumptions; they are optional exports rather than universal primitives. Do not copy private internals or deep-import them.
|
|
260
260
|
|
|
261
261
|
For contribution setup and review expectations, see [CONTRIBUTING.md](CONTRIBUTING.md). Contour currently provides React components; no Vue, Svelte or Angular adapter is included.
|
|
262
|
+
|
|
263
|
+
Public references: [hooks](HOOKS.md), [helpers](HELPERS.md), [optional Three](THREE.md), [prop metadata](PROP-REFERENCE.md), [export register](REFERENCE.md), [migration/history](MIGRATION.md), [support evidence](SUPPORT.md) and [manual QA](MANUAL-QA.md).
|
package/RECIPES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Application recipes — 0.6.
|
|
1
|
+
# Application recipes — 0.6.1
|
|
2
2
|
|
|
3
|
-
The source linked here is the code copied, compiled and exercised by the package checks. These files are application code, not additional exports. Import components directly from the public package; copy only the recipe needed. There are no live services or fabricated successful operations. [Source at this release](https://github.com/abuzareal/contour-ui/tree/v0.6.
|
|
3
|
+
The source linked here is the code copied, compiled and exercised by the package checks. These files are application code, not additional exports. Import components directly from the public package; copy only the recipe needed. There are no live services or fabricated successful operations. [Source at this release](https://github.com/abuzareal/contour-ui/tree/v0.6.1/examples/recipes).
|
|
4
4
|
|
|
5
5
|
## Async single-select
|
|
6
6
|
|
|
@@ -40,4 +40,4 @@ The optional **password visibility recipe** keeps the same input mounted, name a
|
|
|
40
40
|
|
|
41
41
|
Use native p/span and h1–h6 with [typography tokens](STYLING.md). Heading level follows the document outline; size/weight are CSS choices. No Text/Heading wrappers are added without an independent semantic/variant contract. These explicit scope decisions do not complete deferred NumberField, full grid, calendar or other optional features.
|
|
42
42
|
|
|
43
|
-
[Report Table/recipes 0.6.
|
|
43
|
+
[Report Table/recipes 0.6.2](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&title=Table%20recipes%200.6.2%3A%20&component=Table%20recipes&version=0.6.2); [standalone reproduction](examples/reproduction). See [public API](PUBLIC-API.md) for exact types, [styling](STYLING.md) and [onboarding](GETTING-STARTED.md). Release source links become available with the published tag.
|
package/REFERENCE.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Export reference register
|
|
2
|
+
|
|
3
|
+
Generated for 0.6.2 from actual source/runtime declarations and the manifest. This register maps all symbols and CSS/data entry points; it does not promote every component page. Human behavior guidance lives in the linked references. Source and exact types remain in [PUBLIC-API.md](PUBLIC-API.md). Run npm run check:reference; newly added hook/helper sources need an authored mapping before this register can update.
|
|
4
|
+
|
|
5
|
+
| Entry | Symbol | Kind | Reference |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| . | Alert | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
8
|
+
| . | Avatar | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
9
|
+
| . | Badge | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
10
|
+
| . | BrandMark | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
11
|
+
| . | Breadcrumbs | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
12
|
+
| . | Button | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
13
|
+
| . | Card | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
14
|
+
| . | Checkbox | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
15
|
+
| . | CountUp | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
16
|
+
| . | DataTable | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
17
|
+
| . | DepthButton | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
18
|
+
| . | Dialog | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
19
|
+
| . | Disclosure | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
20
|
+
| . | Divider | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
21
|
+
| . | DropdownMenu | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
22
|
+
| . | EmptyState | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
23
|
+
| . | ExternalLink | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
24
|
+
| . | Field | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
25
|
+
| . | FlipCard | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
26
|
+
| . | IconButton | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
27
|
+
| . | Kbd | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
28
|
+
| . | Magnetic | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
29
|
+
| . | Marquee | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
30
|
+
| . | Pagination | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
31
|
+
| . | Popover | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
32
|
+
| . | ProgressBar | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
33
|
+
| . | RadioGroup | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
34
|
+
| . | Reveal | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
35
|
+
| . | RevealHeading | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
36
|
+
| . | ScrollProgress | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
37
|
+
| . | SectionLabel | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
38
|
+
| . | SegmentedControl | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
39
|
+
| . | SelectField | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
40
|
+
| . | Skeleton | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
41
|
+
| . | Slider | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
42
|
+
| . | GitHubIcon | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
43
|
+
| . | LinkedInIcon | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
44
|
+
| . | Spinner | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
45
|
+
| . | Stat | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
46
|
+
| . | Stepper | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
47
|
+
| . | Switch | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
48
|
+
| . | Tabs | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
49
|
+
| . | Tag | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
50
|
+
| . | TextArea | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
51
|
+
| . | TextField | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
52
|
+
| . | ThemeToggle | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
53
|
+
| . | TiltCard | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
54
|
+
| . | Timeline | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
55
|
+
| . | ToastProvider | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
56
|
+
| . | Tooltip | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
57
|
+
| . | useClipboardCopy | runtime | [HOOKS.md#clipboard](HOOKS.md#clipboard) |
|
|
58
|
+
| . | useDismiss | runtime | [HOOKS.md#dismissal-and-mobile-menus](HOOKS.md#dismissal-and-mobile-menus) |
|
|
59
|
+
| . | useHeaderScroll | runtime | [HOOKS.md#scroll-and-navigation](HOOKS.md#scroll-and-navigation) |
|
|
60
|
+
| . | useIdleTrigger | runtime | [HOOKS.md#idle-and-print](HOOKS.md#idle-and-print) |
|
|
61
|
+
| . | useInitialHashScroll | runtime | [HOOKS.md#scroll-and-navigation](HOOKS.md#scroll-and-navigation) |
|
|
62
|
+
| . | useMobileMenu | runtime | [HOOKS.md#dismissal-and-mobile-menus](HOOKS.md#dismissal-and-mobile-menus) |
|
|
63
|
+
| . | useMotionPreference | runtime | [HOOKS.md#motion](HOOKS.md#motion) |
|
|
64
|
+
| . | usePrintPreparation | runtime | [HOOKS.md#idle-and-print](HOOKS.md#idle-and-print) |
|
|
65
|
+
| . | useScrollSpy | runtime | [HOOKS.md#scroll-and-navigation](HOOKS.md#scroll-and-navigation) |
|
|
66
|
+
| . | useTheme | runtime | [HOOKS.md#theme](HOOKS.md#theme) |
|
|
67
|
+
| . | useToast | runtime | [HOOKS.md#toast](HOOKS.md#toast) |
|
|
68
|
+
| . | Section | type | [HELPERS.md#public-types](HELPERS.md#public-types) |
|
|
69
|
+
| . | SceneBoundary | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
70
|
+
| . | safeHref | runtime | [HELPERS.md](HELPERS.md) |
|
|
71
|
+
| . | ThemeScope | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
72
|
+
| . | FloatingOptions | type | [HOOKS.md#dismissal-and-mobile-menus](HOOKS.md#dismissal-and-mobile-menus) |
|
|
73
|
+
| . | PanelFocusOptions | type | [HOOKS.md#dismissal-and-mobile-menus](HOOKS.md#dismissal-and-mobile-menus) |
|
|
74
|
+
| . | DismissReason | type | [HELPERS.md#public-types](HELPERS.md#public-types) |
|
|
75
|
+
| . | Table | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
76
|
+
| . | TableProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
77
|
+
| . | Combobox | runtime | [PUBLIC-API.md](PUBLIC-API.md) |
|
|
78
|
+
| . | ComboboxProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
79
|
+
| . | ComboboxOption | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
80
|
+
| . | AlertTone | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
81
|
+
| . | AlertProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
82
|
+
| . | AvatarProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
83
|
+
| . | BadgeTone | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
84
|
+
| . | BadgeProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
85
|
+
| . | BrandMarkProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
86
|
+
| . | BreadcrumbsProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
87
|
+
| . | ButtonProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
88
|
+
| . | CardProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
89
|
+
| . | CheckboxProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
90
|
+
| . | CountUpProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
91
|
+
| . | TableColumn | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
92
|
+
| . | DataTableProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
93
|
+
| . | DepthButtonProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
94
|
+
| . | DialogProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
95
|
+
| . | DisclosureProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
96
|
+
| . | DividerProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
97
|
+
| . | MenuItem | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
98
|
+
| . | DropdownMenuProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
99
|
+
| . | EmptyStateProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
100
|
+
| . | ExternalLinkProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
101
|
+
| . | FieldProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
102
|
+
| . | FlipCardProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
103
|
+
| . | IconButtonProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
104
|
+
| . | MagneticProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
105
|
+
| . | MarqueeProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
106
|
+
| . | PaginationProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
107
|
+
| . | PopoverProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
108
|
+
| . | ProgressBarProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
109
|
+
| . | RadioGroupProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
110
|
+
| . | RevealProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
111
|
+
| . | HeadingLine | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
112
|
+
| . | RevealHeadingProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
113
|
+
| . | SectionLabelProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
114
|
+
| . | SegmentedControlProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
115
|
+
| . | SelectFieldProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
116
|
+
| . | SkeletonProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
117
|
+
| . | SliderProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
118
|
+
| . | SocialIconProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
119
|
+
| . | SpinnerProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
120
|
+
| . | StatProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
121
|
+
| . | StepperProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
122
|
+
| . | SwitchProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
123
|
+
| . | TabItem | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
124
|
+
| . | TabsProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
125
|
+
| . | TagProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
126
|
+
| . | TextAreaProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
127
|
+
| . | TextFieldProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
128
|
+
| . | ThemeToggleProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
129
|
+
| . | TiltCardProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
130
|
+
| . | TimelineProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
131
|
+
| . | ToastProviderProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
132
|
+
| . | TooltipProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
133
|
+
| . | CopyStatus | type | [HOOKS.md#clipboard](HOOKS.md#clipboard) |
|
|
134
|
+
| . | DismissOptions | type | [HOOKS.md#dismissal-and-mobile-menus](HOOKS.md#dismissal-and-mobile-menus) |
|
|
135
|
+
| . | Theme | type | [HOOKS.md#theme](HOOKS.md#theme) |
|
|
136
|
+
| . | ToastInput | type | [HOOKS.md#toast](HOOKS.md#toast) |
|
|
137
|
+
| . | ToastContextValue | type | [HOOKS.md#toast](HOOKS.md#toast) |
|
|
138
|
+
| . | ToastContext | type | [HOOKS.md#toast](HOOKS.md#toast) |
|
|
139
|
+
| . | cx | runtime | [HELPERS.md](HELPERS.md) |
|
|
140
|
+
| . | ccx | runtime | [HELPERS.md](HELPERS.md) |
|
|
141
|
+
| . | ButtonVariant | type | [HELPERS.md](HELPERS.md) |
|
|
142
|
+
| . | ButtonSize | type | [HELPERS.md](HELPERS.md) |
|
|
143
|
+
| . | buttonClassName | runtime | [HELPERS.md](HELPERS.md) |
|
|
144
|
+
| . | formatIndex | runtime | [HELPERS.md](HELPERS.md) |
|
|
145
|
+
| . | readStorage | runtime | [HELPERS.md](HELPERS.md) |
|
|
146
|
+
| . | writeStorage | runtime | [HELPERS.md](HELPERS.md) |
|
|
147
|
+
| . | storageKeys | runtime | [HELPERS.md](HELPERS.md) |
|
|
148
|
+
| . | nextIndexForKey | runtime | [HELPERS.md](HELPERS.md) |
|
|
149
|
+
| . | fieldDescribedBy | runtime | [HELPERS.md](HELPERS.md) |
|
|
150
|
+
| . | motionDisabledFor | runtime | [HOOKS.md#motion](HOOKS.md#motion) |
|
|
151
|
+
| . | ThemeScopeProps | type | [PROP-REFERENCE.md](PROP-REFERENCE.md) |
|
|
152
|
+
| ./three | Sculpture | runtime | [THREE.md](THREE.md) |
|
|
153
|
+
| ./three | ObjectStudy | runtime | [THREE.md](THREE.md) |
|
|
154
|
+
| ./three | useThreeStage | runtime | [THREE.md](THREE.md) |
|
|
155
|
+
| ./three | StageFrame | type | [THREE.md](THREE.md) |
|
|
156
|
+
| ./three | StageScene | type | [THREE.md](THREE.md) |
|
|
157
|
+
| ./three | StageContext | type | [THREE.md](THREE.md) |
|
|
158
|
+
| ./three | SculptureProps | type | [THREE.md](THREE.md) |
|
|
159
|
+
| ./three | ObjectStudyProps | type | [THREE.md](THREE.md) |
|
|
160
|
+
| ./three | createLinkGeometry | runtime | [THREE.md](THREE.md) |
|
|
161
|
+
| ./three | createChrome | runtime | [THREE.md](THREE.md) |
|
|
162
|
+
| ./three | createLime | runtime | [THREE.md](THREE.md) |
|
|
163
|
+
| ./three | createInk | runtime | [THREE.md](THREE.md) |
|
|
164
|
+
| ./three | createGlass | runtime | [THREE.md](THREE.md) |
|
|
165
|
+
| ./three | createMaterialSet | runtime | [THREE.md](THREE.md) |
|
|
166
|
+
| ./three | createGeometrySet | runtime | [THREE.md](THREE.md) |
|
|
167
|
+
| ./three | ObjectSet | type | [THREE.md](THREE.md) |
|
|
168
|
+
| ./three | objectStudies | runtime | [THREE.md](THREE.md) |
|
|
169
|
+
| ./three | ObjectStudyKind | type | [THREE.md](THREE.md) |
|
|
170
|
+
| ./scroll | useSmoothScroll | runtime | [HOOKS.md#optional-scroll](HOOKS.md#optional-scroll) |
|
|
171
|
+
| ./theme-bootstrap | themeColors | runtime | [HOOKS.md#theme](HOOKS.md#theme) |
|
|
172
|
+
| ./theme-bootstrap | themeBootstrapScript | runtime | [HOOKS.md#theme](HOOKS.md#theme) |
|
|
173
|
+
|
|
174
|
+
## Styles and data
|
|
175
|
+
|
|
176
|
+
| Public path | Contract |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| ./styles.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
179
|
+
| ./reset.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
180
|
+
| ./tokens.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
181
|
+
| ./fonts.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
182
|
+
| ./fonts-latin.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
183
|
+
| ./scoped.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
184
|
+
| ./scoped-tokens.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
185
|
+
| ./minimal-reset.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
186
|
+
| ./tokens.json | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
187
|
+
| ./actions.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
188
|
+
| ./forms.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
189
|
+
| ./navigation.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
190
|
+
| ./data-display.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
191
|
+
| ./feedback.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
192
|
+
| ./overlays.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
|
193
|
+
| ./effects.css | [STYLING.md](STYLING.md), [SIZE.md](SIZE.md) |
|
package/RELEASING.md
CHANGED
|
@@ -9,7 +9,7 @@ Use [the public contract and compatibility policy](CONTRACTS.md#change-deprecati
|
|
|
9
9
|
1. Obtain maintainer authorization to publish; validation alone is not authorization.
|
|
10
10
|
2. Select an unused registry version and update package.json, its lockfile and release notes. Never reuse an existing registry version; a locally verified archive does not make it publishable under an already released version. Use a reviewed release commit on main and a matching `vVERSION` tag. The hosted workflow checks the tag version and that its source is an ancestor of origin/main. It cannot publish from a pull request.
|
|
11
11
|
3. Run `npm ci --ignore-scripts`; install Chromium once with `npx playwright install chromium`. Use Node 22.12+ or 24+.
|
|
12
|
-
4. Set `CONTOUR_RELEASE_DIR` to a temporary directory and run `npm run verify:release`. It runs validate once, packs one archive, tests that archive in clean React 18/19 core and optional consumers plus the pinned Next App Router fixtures, checks public API/documentation/generated styles and production size budgets, audits dependencies, and writes `verified-archive.json` with its SHA-256. Core consumers must have no Three.js, Lenis, RHF, TanStack Table or optional date peers installed. Copied adoption recipes run on React 18/19; standalone Vite/Next/reproduction folders run from that archive with their exact versions and production CSP. Review failures and advisories instead of bypassing gates.
|
|
12
|
+
4. Set `CONTOUR_RELEASE_DIR` to a fresh temporary directory without an existing verified-archive.json identity and run `npm run verify:release`. It runs validate once, packs one archive, tests that archive in clean React 18/19 core and optional consumers plus the pinned Next App Router fixtures, checks public API/documentation/generated styles and production size budgets, audits dependencies, runs the mandatory strict accessibility/visual QA for the shipped component, and writes `verified-archive.json` with its SHA-256. Core consumers must have no Three.js, Lenis, RHF, TanStack Table or optional date peers installed. Copied adoption recipes run on React 18/19; standalone Vite/Next/reproduction folders run from that archive with their exact versions and production CSP. Review failures and advisories instead of bypassing gates.
|
|
13
13
|
5. Inspect the archive contents, verify its checksum against `verified-archive.json`, and publish that exact path using `npm publish /absolute/path/to/archive.tgz --ignore-scripts --access public`. `--ignore-scripts` is appropriate here because that exact archive has already passed the release gates; it is not permission to publish an unchecked package. Source `npm publish` retains a prepublishOnly guard. The hosted workflow verifies the checksum again and publishes the archive with provenance, avoiding duplicate source gates.
|
|
14
14
|
6. The owner completes npm authentication/2FA personally. Never put tokens, OTPs or credentials in this repository or logs. Prefer configured trusted publishing and short-lived identity over persistent tokens.
|
|
15
15
|
7. Verify registry version, tarball/integrity and publication date; install that exact registry version in each affected consumer, commit its manifest/lockfile, and run its required checks before deployment. Before closing the starter publication gate, run `CONTOUR_STARTER_REGISTRY=1 npm run test:starters` to verify clean published-package installs; the prepublish archive run alone does not satisfy that gate. Do not substitute a local link or source copy for release validation.
|
|
@@ -21,3 +21,9 @@ The tag workflow is configured for a public repository on main. Configuration do
|
|
|
21
21
|
Browser checks remain for native dialog, reset timing and graphics lifecycle behavior. jsdom does not reproduce all browser default actions. Compatibility checks reuse one archive and avoid another library build when `CONTOUR_ARCHIVE` is provided. Documentation-only diffs retain types, lint, build, archive checks and audit; runtime diffs keep component, browser and complete compatibility checks. Changes to components, hooks, entries, styles, build/package configuration or the Next fixture also run the pinned Next check. Unknown history falls back to complete gates. No measured CI speedup is claimed until the updated workflow has run.
|
|
22
22
|
|
|
23
23
|
Dependabot proposes dependency/action changes for review; changes are not auto-merged. Actions use pinned revisions and minimal permissions. Do not enable paid runners or private distribution as part of a release. Contributor and application checks remain separate from registry/deployment verification.
|
|
24
|
+
|
|
25
|
+
## Strict QA and publisher verification
|
|
26
|
+
|
|
27
|
+
The current candidate adds test:qa as a final release gate. Known violations remain failures; do not write verified-archive.json or publish a candidate after that gate fails. SUPPORT.md names current findings and manual gaps. The separate test:diagnostic:upstream command retains a strict reproduction for the unmodified upstream Popup composition, which the fixed Contour component no longer uses. Do not confuse that diagnostic with the shipped component gate or remove findings from either assertion. Earlier0.6.0 verification predates this stronger gate and is not re-labelled as a clean accessibility result. Visual baseline changes need review of the actual rendered images; do not regenerate them merely to pass a changed UI.
|
|
28
|
+
|
|
29
|
+
`npm trust list @abuzareal/contour-ui --json` can inspect active publisher relationships without creating one, but npm may require owner browser authorization even for that read. EOTP or unavailable browser access means unverified, not enabled/disabled. The release workflow's id-token:write/provenance flag alone proves neither the active relationship nor an artifact attestation. Review actual registry dist.attestations for the specific release before claiming provenance. Never retrieve/record tokens or change trust relationships as a side effect of verification.
|
package/STYLING.md
CHANGED
|
@@ -66,3 +66,7 @@ Caller content/labels remain application-owned. New local overrides cover Button
|
|
|
66
66
|
Promoted forms, horizontal Tabs/SegmentedControl, pagination icons, menu placement and text alignment are checked in RTL; the keyboard helper accepts an optional direction while retaining LTR defaults. CSS uses logical inline spacing/borders where applicable. Coordinate-driven tab indicators remain physical measurements. No universal RTL promise is made for experimental 3D/effects or application scenes.
|
|
67
67
|
|
|
68
68
|
Forced-color rules preserve focus, selected control outlines, radio marks, invalid field borders and floating panel boundaries. Production emulation checks both themes and focus; they do not certify every Windows theme or manual screen-reader workflow. Branded paper/ink/lime colors, outlines, typography and depth are retained by compatibility mode and by the isolated branded-font recipe; system-font first use is an intentional option.
|
|
69
|
+
|
|
70
|
+
## Version and reproduction
|
|
71
|
+
|
|
72
|
+
Reference version **0.6.2**. A source version does not establish publication; check the npm registry for availability. [Versioned source](https://github.com/abuzareal/contour-ui/tree/v0.6.2/src) and [emitted type inventory](PUBLIC-API.md) describe this contract; tag links resolve after release. [Report Styles 0.6.2](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&component=Styles&version=0.6.2), using the [public minimal reproduction](examples/reproduction) and synthetic data.
|
package/SUPPORT.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Support and validation evidence
|
|
2
|
+
|
|
3
|
+
This matrix describes the current QA work on14 October2026. It is a dated record of selected fixtures, not certification or a claim that every component/browser combination passes. Candidate source and published0.6.0 must not be confused; release artifact/registry evidence is recorded separately. No manual screen-reader session has been completed for this batch.
|
|
4
|
+
|
|
5
|
+
| Environment / check | Current evidence | Limits / disposition |
|
|
6
|
+
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| Chromium153.0.8010.12 | Production native forms/reset, selected layouts and axe scans exercised. Four light/dark390/1440 layouts passed the initial run. | Open and closed Combobox whole-page scans pass after the non-modal popup correction. Visual baselines are authored/reviewed separately, not a full-site audit. |
|
|
8
|
+
| Playwright WebKit26.6 | Production selected forms/layout scans exercised; four light/dark narrow/desktop layouts pass. | Open and closed Combobox scans pass. Playwright WebKit is not physical Safari or VoiceOver proof. Forced-colors emulation is scoped to Chromium. |
|
|
9
|
+
| Firefox installed1543 build | Launch fails before page load: “Could not find profile folder”. | Local environment-blocked, not an application/browser pass. A different working runner is needed for browser evidence. |
|
|
10
|
+
| VoiceOver + Safari | Not tested manually. | QA-13 remains pending; see MANUAL-QA.md. |
|
|
11
|
+
| NVDA + Firefox | Not tested manually. | QA-14 remains pending; see MANUAL-QA.md. |
|
|
12
|
+
| Physical mobile keyboard, Japanese IME, touch devices | No fresh physical session. | Browser touch/composition emulation is a separate bounded result, not device certification. |
|
|
13
|
+
| React/framework/package matrix | Published0.6.0 has archived same-artifact React18.3.1/19.0.0/19.3.0, optional, Vite and pinned Next App Router/webpack evidence. | This is inherited release evidence. The final 0.6.1 archive must pass its own release matrix before publication. Other frameworks remain unverified. |
|
|
14
|
+
| Hook lifecycles | Print repeat/unmount/absent-theme restoration, delayed hash cancellation and delimiter-safe scroll IDs have failing-before/passing-after regressions. | Unit/component evidence does not verify printer hardware, lazy router mounting or every document ownership composition. |
|
|
15
|
+
|
|
16
|
+
## Combobox correction and retained diagnostic
|
|
17
|
+
|
|
18
|
+
The initial 0.6.1 whole-document scan reproduced **aria-hidden-focus** (serious), **page-has-heading-one** and **region** (moderate best-practice findings) in Chromium and WebKit. The input-outside-popup composition used Base UI's Popup focus manager, which hid background content even with Root modal=false. The failed scans are retained as before-fix evidence.
|
|
19
|
+
|
|
20
|
+
Contour now composes Base UI's public Root, Input, Positioner, List and Item parts with its own **non-modal, labelled popup region**. The listbox shares the visible field label; the popup is hidden when closed. The public Root actions ref completes the immediate closing phase and restores controlled query text to the selected label. Selection, active-descendant navigation, native forms and positioning still use the pinned foundation. The enclosing Dialog remains responsible for modal focus containment. No ARIA is stripped, private upstream internals patched, or axe rule excluded. Whole-document open/closed scans and Tab/Shift+Tab journeys pass in Chromium and WebKit; the existing native-modal, iframe, touch, CSS zoom and form regressions also pass.
|
|
21
|
+
|
|
22
|
+
`npm run test:diagnostic:upstream` retains the unmodified Base UI 1.9.0 Popup reproduction, including its strict zero-violation assertion. It currently fails in both tested engines. This diagnostic exercises a composition Contour no longer ships; `test:qa` remains the mandatory strict gate for the actual Contour component. A dependency reproduction is not a manual AT result or a universal upstream defect claim. Manual VoiceOver/Safari and NVDA/Firefox reviews remain pending.
|
|
23
|
+
|
|
24
|
+
## Commands and evidence layers
|
|
25
|
+
|
|
26
|
+
- `npm test`: deterministic state/helpers/component/lifecycle behavior; no arbitrary coverage target.
|
|
27
|
+
- `npm run test:browser`: existing native dialog/forms/overlay/style/optional scene journeys in Chromium.
|
|
28
|
+
- `npm run test:qa`: production fixture, strict axe assertion, focus/forms/overlay journeys and a small visual baseline. Any finding in the shipped fixture produces a failing result. Set CONTOUR_QA_ENGINES=webkit or a comma-separated engine set to exercise other installed browsers; browser launch failures remain visible.
|
|
29
|
+
- `npm run test:compat`: the packed React/optional/source-declaration matrix and copied recipes, using one archive when CONTOUR_ARCHIVE is set.
|
|
30
|
+
- Exact Vite/Next starter, Next integration, size and registry checks have separate scripts in RELEASING.md. Passing build/types does not prove a browser/deployment.
|
|
31
|
+
|
|
32
|
+
Every result should name package/commit/archive, date, OS/browser/tool versions, checked components/states and passed/failed/skipped/blocked outcomes. Keep failed first-pass evidence, identify authored fixture corrections and rerun only affected work. A screenshot baseline cannot establish accessible names/announcements; axe cannot certify WCAG or physical AT. Important errors need persistent text and chart data needs meaningful text/table alternatives in their applications.
|
|
33
|
+
|
|
34
|
+
## Version and reproduction
|
|
35
|
+
|
|
36
|
+
Reference version **0.6.2**. A source version does not establish publication; check the npm registry for availability. [Versioned source](https://github.com/abuzareal/contour-ui/tree/v0.6.2/src) and [emitted type inventory](PUBLIC-API.md) describe this contract; tag links resolve after release. [Report Support matrix 0.6.2](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&component=Support%20matrix&version=0.6.2), using the [public minimal reproduction](examples/reproduction) and synthetic data.
|
package/THREE.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Optional Three reference
|
|
2
|
+
|
|
3
|
+
These experimental exports live at `@abuzareal/contour-ui/three`. Core components do not import Three or Lenis. Install the declared Three peer (and matching @types/three for TypeScript), load the entry lazily and import component styles deliberately. [GETTING-STARTED.md](GETTING-STARTED.md) contains the actual lazy static-fallback/sizing/pause recipe. [PUBLIC-API.md](PUBLIC-API.md) links exact source and types; experimental does not mean unversioned or safe to deep-import.
|
|
4
|
+
|
|
5
|
+
## Scene components
|
|
6
|
+
|
|
7
|
+
Sculpture requires `{motionEnabled: boolean}` and renders the fixed three-link brand scene in a loading/ready/unavailable host. ObjectStudy requires `{label: string, motionEnabled: boolean, study: "materials" | "geometry"}` and renders an aria-labelled image host with four related objects. These are authored visual studies, not a general model viewer, arbitrary asset loader or application data visualization. The caller supplies block sizing and adjacent meaningful text. No native ref/imperative scene API is exposed by these two components. Key/remount when setup inputs such as study must change; current scene setup is captured at mount.
|
|
8
|
+
|
|
9
|
+
Unavailable WebGL or partial setup leaves an unavailable host; it does not manufacture a fallback. Keep useful static DOM/SVG outside SceneBoundary/Suspense. SceneBoundary catches React descendant errors and hides failed scene content; it has no fallback prop and does not replace domain content. Headless success does not certify physical GPUs, every browser or context restoration with custom resources.
|
|
10
|
+
|
|
11
|
+
## useThreeStage
|
|
12
|
+
|
|
13
|
+
`useThreeStage(hostRef, {motionEnabled, setup, cameraDistance})` returns void. hostRef targets a connected sized HTMLDivElement. setup(context) and cameraDistance(aspect) are captured once per mount; remount for a new setup/framing contract. motionEnabled updates without remounting. Camera distance must be finite and appropriate for the scene/aspect; no automatic framing of arbitrary external objects is promised.
|
|
14
|
+
|
|
15
|
+
StageContext contains scene, PerspectiveCamera, WebGLRenderer and optional onDispose(cleanup). Register each allocated resource immediately, before later code can throw. StageScene requires update(frame), rest() and dispose(); resize() is optional. StageFrame contains delta seconds (bounded to 0–0.05), accumulated running elapsed seconds and a Vector2 pointer offset in -0.5..0.5. Do not dispose the same material/geometry through both onDispose and dispose; register one owner. When shared among meshes, dispose shared resources once.
|
|
16
|
+
|
|
17
|
+
The stage owns renderer/canvas, neutral tone mapping, studio lights/environment, resize/intersection/visibility/context listeners and its animation frame. Device pixel ratio is capped at 1.75. Frames run only with motion enabled, intersection visibility, visible document and usable context; pause snaps to rest and redraws. The application combines system reduced motion and app pause before passing motionEnabled. Context loss marks unavailable and stops updates; restoration redraws/resumes. Setup failures and unmount run registered disposers in reverse order, including allocations registered before setup returned. A failing disposer is reported and does not prevent later cleanup. The caller owns custom resource allocation, cleanup, fetching, asset rights and fallback meaning.
|
|
18
|
+
|
|
19
|
+
## Material and geometry factories
|
|
20
|
+
|
|
21
|
+
| Export | Result and ownership |
|
|
22
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| createChrome | New MeshStandardMaterial: neutral chrome, metalness1/roughness0.19. Caller disposes it. |
|
|
24
|
+
| createLime | New MeshStandardMaterial: authored lime, metalness0.25/roughness0.26. Caller disposes it. |
|
|
25
|
+
| createInk | New MeshStandardMaterial: dark matte, metalness0.1/roughness0.62. Caller disposes it. |
|
|
26
|
+
| createGlass | New MeshPhysicalMaterial with transmission/thickness/attenuation; caller disposes it. It is not a general physically validated optical simulation. |
|
|
27
|
+
| createLinkGeometry | New centred beveled/extruded rounded-square link geometry; caller disposes it. |
|
|
28
|
+
| createMaterialSet | ObjectSet of four meshes sharing link geometry with chrome/lime/ink/glass materials. Call set.dispose once; do not also dispose shared members independently. |
|
|
29
|
+
| createGeometrySet | ObjectSet of torus knot, icosahedron, rounded box and capsule meshes with authored materials. Call set.dispose once. |
|
|
30
|
+
| objectStudies | Selection mapping materials→createMaterialSet, geometry→createGeometrySet. Factories create new owned sets; this is not an allocated global scene. |
|
|
31
|
+
|
|
32
|
+
ObjectSet is `{objects: THREE.Object3D[]; dispose: () => void}`. Disposal releases factory-owned geometry/materials; it does not remove caller-added objects from a scene or dispose unrelated textures. ObjectStudyKind is `keyof typeof objectStudies`. Factories do not create render loops, fetch files or install event listeners. Future shape/material additions remain demand-led and measured; importing optional helpers does not justify making Three a core dependency.
|
|
33
|
+
|
|
34
|
+
## Setup and lifecycle limits
|
|
35
|
+
|
|
36
|
+
Use one stage owner per host, stable setup and deliberate size. Product controls, labels, keyboard alternatives and observed data belong outside decorative canvas. There is no animation-control timeline, general object selection, scene editor, SSR WebGL renderer or universally verified third-party modal interoperability. Optional declaration/build and sampled lifecycle checks are distinct from the [dated support matrix](SUPPORT.md). Inspect public code and reproduce with synthetic scenes rather than private assets.
|
|
37
|
+
|
|
38
|
+
## Version and reproduction
|
|
39
|
+
|
|
40
|
+
Reference version **0.6.2**. A source version does not establish publication; check the npm registry for availability. [Versioned source](https://github.com/abuzareal/contour-ui/tree/v0.6.2/src) and [emitted type inventory](PUBLIC-API.md) describe this contract; tag links resolve after release. [Report Three 0.6.2](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&component=Three&version=0.6.2), using the [public minimal reproduction](examples/reproduction) and synthetic data.
|
|
@@ -31,6 +31,13 @@ const Combobox = forwardRef(function Combobox({ label, options, filteredOptions,
|
|
|
31
31
|
const { ref: input, attach } = useControlRef(forwardedRef);
|
|
32
32
|
const [anchor, setAnchor] = useState(null);
|
|
33
33
|
const attachInput = useMemo(() => composeRefs(attach, inputProps?.ref, setAnchor), [attach, inputProps?.ref]);
|
|
34
|
+
const actions = useRef(null);
|
|
35
|
+
// The custom non-modal popup has no exit animation. Complete the public close
|
|
36
|
+
// lifecycle after it is hidden so controlled query text returns to the selected label.
|
|
37
|
+
useLayoutEffect(() => {
|
|
38
|
+
if (!visible)
|
|
39
|
+
actions.current?.unmount();
|
|
40
|
+
}, [visible]);
|
|
34
41
|
const root = useRef(null);
|
|
35
42
|
const attachRoot = useMemo(() => composeRefs(root, rootProps?.ref), [rootProps?.ref]);
|
|
36
43
|
const positioner = useRef(null);
|
|
@@ -65,8 +72,8 @@ const Combobox = forwardRef(function Combobox({ label, options, filteredOptions,
|
|
|
65
72
|
const results = loading || searchError ? [] : filteredOptions;
|
|
66
73
|
const statusId = `${id}-search-status`;
|
|
67
74
|
const positioning = useComboboxAnchor(anchor, positioner);
|
|
68
|
-
const popup = (_jsx(FloatingScope, { anchor: anchor, open: visible, target: target, onDirectionChange: setDirection, children: _jsx(BaseCombobox.Positioner, { ...positioning, ref: attachPositioner, className: ccx("combobox-positioner"), positionMethod: "fixed", side: side, align: align, sideOffset: Number.isFinite(sideOffset) ? sideOffset : 8, collisionPadding: Number.isFinite(collisionPadding) ? Math.max(0, collisionPadding) : 8, children: _jsxs(
|
|
69
|
-
return (_jsx(DirectionProvider, { direction: direction, children: _jsx("div", { ...rootProps, ref: attachRoot, className: ccx("combobox", rootProps?.className), children: _jsxs(BaseCombobox.Root, { items: collection, filteredItems: results, value: missing ? null : value, onValueChange: (next) => {
|
|
75
|
+
const popup = (_jsx(FloatingScope, { anchor: anchor, open: visible, target: target, onDirectionChange: setDirection, children: _jsx(BaseCombobox.Positioner, { ...positioning, ref: attachPositioner, className: ccx("combobox-positioner"), positionMethod: "fixed", side: side, align: align, sideOffset: Number.isFinite(sideOffset) ? sideOffset : 8, collisionPadding: Number.isFinite(collisionPadding) ? Math.max(0, collisionPadding) : 8, children: _jsxs("div", { role: "region", "aria-labelledby": `${id}-label`, ...popupProps, className: ccx("combobox-popup", popupProps?.className), hidden: !visible, children: [_jsx(BaseCombobox.Empty, { className: ccx("combobox-status"), children: loading ? loadingText : (searchError ?? emptyText) }), searchError && onRetry && (_jsx("button", { type: "button", className: ccx("combobox-retry"), onClick: onRetry, children: retryLabel })), _jsx(BaseCombobox.List, { className: ccx("combobox-list"), "aria-labelledby": `${id}-label`, children: (option) => (_jsxs(BaseCombobox.Item, { className: ccx("combobox-option"), value: option.value, disabled: option.disabled, children: [_jsx("span", { children: option.label }), _jsx(BaseCombobox.ItemIndicator, { children: _jsx(Check, { size: 14, "aria-hidden": "true" }) })] }, option.value)) })] }) }) }));
|
|
76
|
+
return (_jsx(DirectionProvider, { direction: direction, children: _jsx("div", { ...rootProps, ref: attachRoot, className: ccx("combobox", rootProps?.className), children: _jsxs(BaseCombobox.Root, { actionsRef: actions, items: collection, filteredItems: results, value: missing ? null : value, onValueChange: (next) => {
|
|
70
77
|
if (controlledValue === undefined)
|
|
71
78
|
setInternalValue(next);
|
|
72
79
|
setQuery(null);
|
|
@@ -86,8 +93,10 @@ const Combobox = forwardRef(function Combobox({ label, options, filteredOptions,
|
|
|
86
93
|
details.cancel();
|
|
87
94
|
return;
|
|
88
95
|
}
|
|
89
|
-
if (!next)
|
|
96
|
+
if (!next) {
|
|
97
|
+
details.preventUnmountOnClose();
|
|
90
98
|
setQuery(null);
|
|
99
|
+
}
|
|
91
100
|
changeOpen(next);
|
|
92
101
|
}, name: name, form: form, required: required, disabled: disabled, readOnly: readOnly, children: [_jsx(Field, { id: id, label: label, hint: hint, error: fieldError, required: required, disabled: disabled, hideLabel: hideLabel, children: _jsxs(BaseCombobox.InputGroup, { className: ccx("field-control combobox-control"), children: [_jsx(BaseCombobox.Input, { ...inputProps, onMouseDown: (event) => {
|
|
93
102
|
inputProps?.onMouseDown?.(event);
|
|
@@ -104,6 +113,12 @@ const Combobox = forwardRef(function Combobox({ label, options, filteredOptions,
|
|
|
104
113
|
if (event.defaultPrevented ||
|
|
105
114
|
(event.key === "Escape" && !visible))
|
|
106
115
|
event.preventBaseUIHandler();
|
|
116
|
+
else if (event.key === "Tab" && visible) {
|
|
117
|
+
// Close even when native traversal leaves the document (for example Safari's last field).
|
|
118
|
+
// Do not preventDefault: the browser still owns the next keyboard target.
|
|
119
|
+
event.preventBaseUIHandler();
|
|
120
|
+
close();
|
|
121
|
+
}
|
|
107
122
|
}, ref: attachInput, id: id, form: form, "aria-labelledby": [
|
|
108
123
|
`${id}-label`,
|
|
109
124
|
inputProps?.["aria-labelledby"],
|
|
@@ -73,5 +73,5 @@ export default function Tooltip({ content, children, placement = "top", align =
|
|
|
73
73
|
collisionPadding,
|
|
74
74
|
portal,
|
|
75
75
|
container,
|
|
76
|
-
}, children: _jsx("span", { ref: panel, id: id, role: "tooltip", className: ccx("tooltip mono", `tooltip-${placement}`, open && "is-open"), onPointerEnter: enter, onPointerLeave: leave, children: content }) })] }));
|
|
76
|
+
}, children: _jsx("span", { ref: panel, id: id, role: "tooltip", hidden: !open, className: ccx("tooltip mono", `tooltip-${placement}`, open && "is-open"), onPointerEnter: enter, onPointerLeave: leave, children: content }) })] }));
|
|
77
77
|
}
|
|
@@ -24,6 +24,10 @@ export default function useInitialHashScroll() {
|
|
|
24
24
|
align();
|
|
25
25
|
userScrollEvents.forEach((event) => window.addEventListener(event, markScrolled, { passive: true }));
|
|
26
26
|
document.fonts.ready.then(align);
|
|
27
|
-
return () =>
|
|
27
|
+
return () => {
|
|
28
|
+
// Font readiness cannot be cancelled; an unmounted owner must not scroll a later page.
|
|
29
|
+
userScrolled = true;
|
|
30
|
+
userScrollEvents.forEach((event) => window.removeEventListener(event, markScrolled));
|
|
31
|
+
};
|
|
28
32
|
}, []);
|
|
29
33
|
}
|
|
@@ -6,7 +6,12 @@ export default function usePrintPreparation() {
|
|
|
6
6
|
const root = document.documentElement;
|
|
7
7
|
let expanded = [];
|
|
8
8
|
let screenTheme;
|
|
9
|
+
let printing = false;
|
|
9
10
|
const prepare = () => {
|
|
11
|
+
// Some browsers repeat beforeprint while the same print preview is open.
|
|
12
|
+
if (printing)
|
|
13
|
+
return;
|
|
14
|
+
printing = true;
|
|
10
15
|
expanded = [
|
|
11
16
|
...document.querySelectorAll("details:not([open])"),
|
|
12
17
|
];
|
|
@@ -15,9 +20,14 @@ export default function usePrintPreparation() {
|
|
|
15
20
|
root.dataset.theme = "light";
|
|
16
21
|
};
|
|
17
22
|
const restore = () => {
|
|
23
|
+
if (!printing)
|
|
24
|
+
return;
|
|
25
|
+
printing = false;
|
|
18
26
|
expanded.forEach((details) => (details.open = false));
|
|
19
27
|
expanded = [];
|
|
20
|
-
if (screenTheme)
|
|
28
|
+
if (screenTheme === undefined)
|
|
29
|
+
delete root.dataset.theme;
|
|
30
|
+
else
|
|
21
31
|
root.dataset.theme = screenTheme;
|
|
22
32
|
};
|
|
23
33
|
window.addEventListener("beforeprint", prepare);
|
|
@@ -25,6 +35,7 @@ export default function usePrintPreparation() {
|
|
|
25
35
|
return () => {
|
|
26
36
|
window.removeEventListener("beforeprint", prepare);
|
|
27
37
|
window.removeEventListener("afterprint", restore);
|
|
38
|
+
restore();
|
|
28
39
|
};
|
|
29
40
|
}, []);
|
|
30
41
|
}
|
|
@@ -5,10 +5,13 @@ import { useEffect, useState } from "react";
|
|
|
5
5
|
const activationLine = 0.3;
|
|
6
6
|
export default function useScrollSpy(ids) {
|
|
7
7
|
const [activeId, setActiveId] = useState("");
|
|
8
|
-
const key =
|
|
8
|
+
const key = JSON.stringify(ids);
|
|
9
9
|
useEffect(() => {
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const parsed = JSON.parse(key);
|
|
11
|
+
if (!Array.isArray(parsed) ||
|
|
12
|
+
!parsed.every((id) => typeof id === "string"))
|
|
13
|
+
return;
|
|
14
|
+
const elements = parsed
|
|
12
15
|
.map((id) => document.getElementById(id))
|
|
13
16
|
.filter((element) => element !== null);
|
|
14
17
|
let frame = 0;
|