@abuzareal/contour-ui 0.5.0 → 0.6.1

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 (87) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/COMBOBOX.md +87 -0
  3. package/COMPOSITION.md +4 -0
  4. package/CONTRACTS.md +27 -27
  5. package/DOCS.md +86 -0
  6. package/FORMS.md +4 -0
  7. package/FOUNDATION.md +35 -0
  8. package/GETTING-STARTED.md +67 -0
  9. package/HELPERS.md +33 -0
  10. package/HOOKS.md +67 -0
  11. package/MANUAL-QA.md +38 -0
  12. package/MIGRATION.md +44 -0
  13. package/MODELS.md +18 -0
  14. package/NEXTJS.md +3 -1
  15. package/OVERLAYS.md +4 -0
  16. package/PROP-REFERENCE.md +37 -0
  17. package/PUBLIC-API.md +174 -164
  18. package/README.md +9 -5
  19. package/RECIPES.md +43 -0
  20. package/REFERENCE.md +193 -0
  21. package/RELEASING.md +8 -2
  22. package/SIZE.md +9 -3
  23. package/STYLING.md +4 -0
  24. package/SUPPORT.md +36 -0
  25. package/THREE.md +40 -0
  26. package/dist/components/ui/Combobox.d.ts +325 -0
  27. package/dist/components/ui/Combobox.js +135 -0
  28. package/dist/components/ui/Combobox.types.d.ts +46 -0
  29. package/dist/components/ui/Combobox.types.js +1 -0
  30. package/dist/components/ui/DataTable.js +5 -4
  31. package/dist/components/ui/Field.js +1 -1
  32. package/dist/components/ui/FloatingPortal.js +2 -40
  33. package/dist/components/ui/FloatingScope.d.ts +9 -0
  34. package/dist/components/ui/FloatingScope.js +43 -0
  35. package/dist/components/ui/Table.d.ts +20 -0
  36. package/dist/components/ui/Table.js +9 -0
  37. package/dist/hooks/useComboboxAnchor.d.ts +17 -0
  38. package/dist/hooks/useComboboxAnchor.js +61 -0
  39. package/dist/hooks/useInitialHashScroll.js +5 -1
  40. package/dist/hooks/usePrintPreparation.js +12 -1
  41. package/dist/hooks/useScrollSpy.js +6 -3
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +2 -0
  44. package/dist/kit/data-display.css +6 -0
  45. package/dist/kit/forms.css +34 -0
  46. package/dist/lib/componentClasses.js +1 -1
  47. package/dist/scoped/kit/data-display.css +6 -0
  48. package/dist/scoped/kit/forms.css +34 -0
  49. package/docs/prop-metadata.json +2668 -0
  50. package/examples/onboarding/SettingsForm.jsx +30 -0
  51. package/examples/onboarding/SettingsForm.tsx +50 -0
  52. package/examples/optional/LazyScene.tsx +78 -0
  53. package/examples/optional/OptionalSmoothScroll.tsx +25 -0
  54. package/examples/optional/SmoothScrollOwner.tsx +7 -0
  55. package/examples/optional/optional.css +25 -0
  56. package/examples/recipes/AsyncProjectPicker.tsx +82 -0
  57. package/examples/recipes/DeleteProjectConfirmation.tsx +97 -0
  58. package/examples/recipes/InputCompositions.tsx +49 -0
  59. package/examples/recipes/RemoteRecordsTable.tsx +256 -0
  60. package/examples/recipes/useRemoteResource.ts +81 -0
  61. package/examples/reference/HookExamples.tsx +146 -0
  62. package/examples/reproduction/README.md +9 -0
  63. package/examples/reproduction/index.html +14 -0
  64. package/examples/reproduction/package.json +27 -0
  65. package/examples/reproduction/src/main.tsx +33 -0
  66. package/examples/reproduction/src/style.css +19 -0
  67. package/examples/reproduction/tsconfig.json +18 -0
  68. package/examples/reproduction/vite.config.ts +19 -0
  69. package/examples/starters/next/README.md +18 -0
  70. package/examples/starters/next/app/Demo.tsx +65 -0
  71. package/examples/starters/next/app/layout.tsx +25 -0
  72. package/examples/starters/next/app/next-page/page.tsx +9 -0
  73. package/examples/starters/next/app/page.tsx +11 -0
  74. package/examples/starters/next/app/style.css +19 -0
  75. package/examples/starters/next/next-env.d.ts +2 -0
  76. package/examples/starters/next/next.config.mjs +1 -0
  77. package/examples/starters/next/package.json +27 -0
  78. package/examples/starters/next/proxy.ts +16 -0
  79. package/examples/starters/next/tsconfig.json +30 -0
  80. package/examples/starters/vite/README.md +16 -0
  81. package/examples/starters/vite/index.html +14 -0
  82. package/examples/starters/vite/package.json +27 -0
  83. package/examples/starters/vite/src/main.tsx +81 -0
  84. package/examples/starters/vite/src/style.css +19 -0
  85. package/examples/starters/vite/tsconfig.json +18 -0
  86. package/examples/starters/vite/vite.config.ts +19 -0
  87. package/package.json +37 -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.5.0**. 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.
9
+ This source checkout targets **0.6.1**. 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
 
@@ -16,12 +16,14 @@ Version 0.4.0 adds native named/external form submission and controlled/default/
16
16
 
17
17
  Version 0.5 adds topmost overlay dismissal, hoverable hints, collision-aware body/modal portals, scoped/prefixed CSS and themes, local labels/formatters, selective style entries and measured size gates. Floating UI DOM is a new runtime positioning dependency. Default portal DOM placement changes ancestor selectors; see [overlay migration](OVERLAYS.md), [styling and embedding](STYLING.md) and [measured costs](SIZE.md). Legacy styles/imports remain available. This is an early 0.x release, not a 1.0 milestone.
18
18
 
19
+ Version 0.6 adds a single-select [Combobox](COMBOBOX.md) backed by pinned Base UI, a semantic [Table and application recipes](RECIPES.md), public standalone Vite/Next starters, CSP setup and a minimal reproduction. [Start here](GETTING-STARTED.md); [foundation decision and measured dependency cost](FOUNDATION.md); [documentation coverage](DOCS.md). DataTable retains local scalar sorting. Async requests, deletion and remote table state stay application-owned. The private catalogue and independent consumers are not upgraded by this release.
20
+
19
21
  ## Install
20
22
 
21
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+.
22
24
 
23
25
  ```sh
24
- npm install @abuzareal/contour-ui@0.5.0 --save-exact
26
+ npm install @abuzareal/contour-ui@0.6.1 --save-exact
25
27
  ```
26
28
 
27
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.
@@ -121,9 +123,9 @@ For theme selection before first paint, inject `themeBootstrapScript` from `@abu
121
123
  | Area | Public exports |
122
124
  | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
123
125
  | Actions | `Button`, `IconButton`, `ExternalLink`, `SegmentedControl`, `ThemeToggle` |
124
- | Forms | `Field`, `TextField`, `TextArea`, `SelectField`, `Checkbox`, `RadioGroup`, `Switch`, `Slider` |
126
+ | Forms | `Field`, `TextField`, `TextArea`, `SelectField`, `Combobox`, `Checkbox`, `RadioGroup`, `Switch`, `Slider` |
125
127
  | Navigation | `Tabs`, `Breadcrumbs`, `Pagination`, `Stepper`, `DropdownMenu` |
126
- | Data and layout | `Avatar`, `Badge`, `Card`, `DataTable`, `Disclosure`, `Divider`, `EmptyState`, `Kbd`, `SectionLabel`, `Stat`, `Tag`, `Timeline` |
128
+ | Data and layout | `Avatar`, `Badge`, `Card`, `DataTable`, `Table`, `Disclosure`, `Divider`, `EmptyState`, `Kbd`, `SectionLabel`, `Stat`, `Tag`, `Timeline` |
127
129
  | Feedback | `Alert`, `ProgressBar`, `Skeleton`, `Spinner`, `ToastProvider`, `useToast` |
128
130
  | Motion and identity | `BrandMark`, `CountUp`, `DepthButton`, `FlipCard`, `Magnetic`, `Marquee`, `Reveal`, `RevealHeading`, `ScrollProgress`, `TiltCard`, `GitHubIcon`, `LinkedInIcon` |
129
131
  | Overlays and scene fallback | `Dialog`, `Popover`, `Tooltip`, `SceneBoundary` |
@@ -178,7 +180,7 @@ Give scenes a sized container and a usable static fallback. `SceneBoundary` hide
178
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.
179
181
 
180
182
  ```sh
181
- npm install @abuzareal/contour-ui@0.5.0 --save-exact
183
+ npm install @abuzareal/contour-ui@0.6.1 --save-exact
182
184
  ```
183
185
 
184
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.
@@ -257,3 +259,5 @@ Legacy aggregate styles remain global. The new isolated CSS path is documented i
257
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.
258
260
 
259
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 ADDED
@@ -0,0 +1,43 @@
1
+ # Application recipes — 0.6.1
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.1/examples/recipes).
4
+
5
+ ## Async single-select
6
+
7
+ Copy [AsyncProjectPicker.tsx](examples/recipes/AsyncProjectPicker.tsx) and [useRemoteResource.ts](examples/recipes/useRemoteResource.ts). Supply a stable searchProjects(query, signal) function, normally defined outside render or with useCallback. It must validate response IDs/labels, reject malformed data, bound results, and map denied requests to RecipeServiceError("permission"). The component retains one selected record separately from current results. It aborts obsolete work and ignores a response even if the transport ignores abort. Debounce, authentication, caching and data updates are application policies.
8
+
9
+ The controlled selection and text query are independent; typed text never becomes a project ID. Filtering/reordering preserves identity. Loading, no matches, permission failure, service failure and retry are explicit. A failed or stale response cannot replace a newer selection. Use the native name/form/value contracts from [Combobox](COMBOBOX.md); parent form reset should reset the application's controlled selected/query state when required. No hidden network request is made by the library.
10
+
11
+ ## Destructive confirmation
12
+
13
+ Copy [DeleteProjectConfirmation.tsx](examples/recipes/DeleteProjectConfirmation.tsx). It composes the existing native **Dialog**; no new AlertDialog export is added. This confirmation is a user-initiated decision with clear consequences, not an urgent unsolicited alert. The title names the project, the description states irreversible consequences, “Keep project” receives initial focus and “Permanently delete project” is explicit. The trigger regains focus after dismissal while it remains connected.
14
+
15
+ The deleteProject(id, signal) function performs the real server operation; resolving it means the server confirmed success. A disabled pending action prevents duplicate submissions; an immediate ref also guards repeated activation before rendering. A rejected operation keeps the dialog open with a persistent error and an explicit retry action. The example does not announce success until the operation resolves. Target identity keys the interaction, so changing projects or unmounting invalidates the old request.
16
+
17
+ Escape, backdrop, close and “Keep project” cancel waiting and dismiss, including while pending. Abort cannot guarantee a server rollback; the pending message says the server may still complete. Cancelled or obsolete requests cannot invoke onDeleted or close a later confirmation. The application must reconcile server state before retrying an uncertain outcome and implement authorization/idempotency at its server boundary. Use a different explicit contract if a product must prohibit cancellation during a critical phase. Dialog semantics, keyboard containment and return are inherited from the released Dialog; physical assistive-technology verification is separate.
18
+
19
+ ## Tables: local versus remote
20
+
21
+ **DataTable** is deliberately small: `Row extends Record<string, string | number>`, caption, columns and a stable rowKey. Local sorting compares string/number values or column.compare; render formats a cell but does not remove the row constraint. Use immutable stable IDs, not array indexes or translated labels. DataTable has no remote sorting/filtering/pagination, selection, bulk actions, virtualization, editing or adjustable density.
22
+
23
+ **Table** is a new semantic presentation primitive for application-owned native thead/tbody/tr/th/td markup. It accepts native table attributes/events, forwards ref to HTMLTableElement, requires a string caption and children, hides the caption visually by default (`showCaption=false`) and offers native scrollProps/ref for the existing focusable scroll region. It owns one caption; do not supply a second caption in children. Use scope, headers, aria-sort and text equivalents according to the data. It adds no sorting engine, ARIA grid keyboard model or layout algorithm. Overflow is horizontally scrollable. Use data-display.css or scoped.css; contour-table-scroll/contour-data-table and semantic typography/border tokens supply the shared styling.
24
+
25
+ Copy [RemoteRecordsTable.tsx](examples/recipes/RemoteRecordsTable.tsx) and useRemoteResource.ts. Install **@tanstack/react-table@9.3.1** and **@tanstack/react-store@0.11.2** as your application's direct dependencies; neither is a Contour runtime dependency. This recipe uses v9 useTable/tableFeatures/FlexRender and controlled application state, not the older v8 useReactTable API. [Official v9 state guide](https://tanstack.com/table/latest/docs/framework/react/guide/table-state), [migration guide](https://tanstack.com/table/latest/docs/framework/react/guide/migrating).
26
+
27
+ loadRecords(query, signal) must perform the requested filter, sorting and pagination remotely. Validate parsed JSON with parseRecordsPage and validate/whitelist query fields at the server; never interpolate arbitrary column IDs into SQL. Only name/owner columns exist in this example. Return rows, filtered total and unfilteredTotal consistently. Name/id/owner are demo record fields, not a prescribed business model.
28
+
29
+ The app controls query, resets the page when filter/sort changes, ignores obsolete responses, retains and **labels** the previous successful snapshot on loading/service failure, and hides old rows after permission failure. Headers describe the displayed snapshot; pending controls request new data rather than locally sorting old rows. A table caption, native headers, stable row/cell IDs and status text preserve semantics. Loading, empty database, no filter matches, missing page, denied/service error and retry are distinct. Pagination is disabled while the requested result is unresolved or failed. Changes to dataset totals may require “First page”; they do not masquerade as an empty database.
30
+
31
+ Selection/bulk actions, density, virtualization, pinned columns and enterprise grid behavior are explicitly unsupported in this bounded recipe. If required, define stable selection across pages, permissions, indeterminate/select-all scope, destructive bulk outcomes and keyboard behavior before enabling engine features. Use a mature grid for grid behavior; do not add role=grid to this table without its keyboard contract. Styling is not evidence of a complete enterprise grid.
32
+
33
+ ## Input and typography decisions
34
+
35
+ [InputCompositions.tsx](examples/recipes/InputCompositions.tsx) demonstrates existing TextField leadingIcon/trailing slots and native form identity. Decorative icons/units use aria-hidden; meaningful units belong in the label/hint. Interactive trailing content needs its own accessible name, button type and focus style; keep long content responsive. No new prefix/suffix API is needed for the demonstrated cases.
36
+
37
+ A native type=number field is sufficient for the bounded integer seat quantity. There is no recorded adopter requirement for a new locale-aware NumberField. Decimal/group separators, transient minus/decimal input, locale parsing/formatting, range/step, currency precision and serialization need a separate demand/contract gate. Financial amounts must not inherit a binary-floating point money model from a generic input. The conditional NumberField remains deferred.
38
+
39
+ The optional **password visibility recipe** keeps the same input mounted, name and current-password autocomplete stable, and a named aria-pressed toggle. Focus returns to the input after toggling; no value is copied, transformed or logged. Real password-manager/browser compatibility remains app/device verification. A standalone library PasswordInput is unnecessary without a stronger reusable requirement.
40
+
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
+
43
+ [Report Table/recipes 0.6.1](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&title=Table%20recipes%200.6.1%3A%20&component=Table%20recipes&version=0.6.1); [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.1 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,10 +9,10 @@ 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/generated styles and production size budgets, audits dependencies, and writes `verified-archive.json` with its SHA-256. Core consumers must have no Three.js or Lenis installed. 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
- 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. Do not substitute a local link or source copy for release validation.
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.
16
16
 
17
17
  The tag workflow is configured for a public repository on main. Configuration does not prove that its npm trusted-publisher relationship is active; check npm/GitHub settings before relying on it. Publication requires authorization even when CI passes.
18
18
 
@@ -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/SIZE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Package and application size
2
2
 
3
- A package archive, installed dependencies and a browser download are different costs. Contour does not claim to be zero-dependency or the lightest library. `scripts/measure-size.mjs` builds public-import Button, settings-form and table journeys in Vite and pinned Next App Router/webpack, loads fresh browser pages, and writes a JSON report. An additional Button-with-ArrowRight fixture measures the incremental selected-icon journey; it is not an isolated icon-function byte count.
3
+ A package archive, installed dependencies and a browser download are different costs. Contour does not claim to be zero-dependency or the lightest library. `scripts/measure-size.mjs` builds public-import Button, settings-form, table and Combobox journeys in Vite and pinned Next App Router/webpack, loads fresh browser pages, and writes a JSON report. An additional Button-with-ArrowRight fixture measures the incremental selected-icon journey; it is not an isolated icon-function byte count.
4
4
 
5
5
  ```sh
6
6
  npm run build
@@ -8,7 +8,7 @@ CONTOUR_SIZE_OUTPUT=/absolute/path/sizes.json npm run measure:size
8
8
  CONTOUR_SIZE_OUTPUT=/absolute/path/check.json npm run check:size
9
9
  ```
10
10
 
11
- Set `CONTOUR_ARCHIVE` to the already packed candidate to reuse it. Fixtures install React/React DOM 19.3.0; Next uses 16.4.0, and Vite/Chromium/Node versions are recorded from the running tools. The report names package/source commit/dirty state, archive checksum/files/compressed/unpacked bytes, the fresh dependency lock hash, resolved dependency versions, fixtures, exclusions, raw/gzip file sizes and actual Resource Timing transfers. These are reproducible fixtures, not latency or production-site benchmarks. No React/framework externals are removed from the application totals. Next shared JS is the intersection of actually fetched URLs across the three fresh routes; route-specific JS is listed separately. Server build output is excluded from client bytes.
11
+ Set `CONTOUR_ARCHIVE` to the already packed candidate to reuse it. Fixtures install React/React DOM 19.3.0; Next uses 16.4.0, and Vite/Chromium/Node versions are recorded from the running tools. The report names package/source commit/dirty state, archive checksum/files/compressed/unpacked bytes, the fresh dependency lock hash, resolved dependency versions, fixtures, exclusions, raw/gzip file sizes and actual Resource Timing transfers. These are reproducible fixtures, not latency or production-site benchmarks. No React/framework externals are removed from the application totals. Next shared JS is the intersection of actually fetched URLs across the measured fresh routes; route-specific JS is listed separately. Server build output is excluded from client bytes.
12
12
 
13
13
  Raw minified JS/CSS is reported per actual fetched file and by fixture. Gzip level 9 is reported **per file**, never summed and advertised as an application gzip total. Network transfer, encoded body and decoded body measurements are kept separately, including document/RSC resources. CSS/font requests, archive size and library dependency-closure installed file bytes are separate categories. Install counts exclude Next/Vite/development tooling and record React peers separately. Optional Three.js, Lenis and RHF are absent from core fixtures.
14
14
 
@@ -23,7 +23,7 @@ The 13 October Vite comparison used identical React 19.3.0 journeys against 0.4.
23
23
  | actions.css | Button/IconButton/DepthButton, SegmentedControl, Magnetic, ThemeToggle; required loading Spinner styles |
24
24
  | forms.css | Field/TextField/TextArea/SelectField, Checkbox/RadioGroup/Switch/Slider |
25
25
  | navigation.css | Tabs, Breadcrumbs, Pagination, Stepper |
26
- | data-display.css | Card/Avatar/Badge/Tag/Stat, DataTable/Timeline and value-display patterns |
26
+ | data-display.css | Card/Avatar/Badge/Tag/Stat, Table/DataTable/Timeline and value-display patterns |
27
27
  | feedback.css | Alert, ToastProvider, ProgressBar, Spinner, Skeleton, EmptyState |
28
28
  | overlays.css | Tooltip, Popover, DropdownMenu, Dialog/drawers |
29
29
  | effects.css | TiltCard/FlipCard/Marquee and CSS effects |
@@ -43,3 +43,9 @@ Three.js/Lenis stay optional peers behind their entries. Core imports do not ins
43
43
  ## Regression policy
44
44
 
45
45
  `scripts/size-baseline.json` records the actual measured baseline and budgets. The gate allows 10% plus 1,024 bytes on raw fetched JS/CSS totals for deliberate review and chunk/minifier drift, and requires zero font requests in system-font fixtures. Update a baseline only after reviewing a real report and explaining intentional growth; do not automatically ratchet it to pass. Source/package/dependency changes can alter results even with the same components. Release verification and CI use the same packed archive and run this gate. The library-only samples from earlier research are not substituted for these application measurements.
46
+
47
+ ## 0.6 Combobox measurement
48
+
49
+ On 14 October 2026, an initial 0.6.0 candidate used the same production fixtures to measure the new Combobox journey with React 19.3.0, Vite 8.3.2, Next 16.4.0/webpack, Node 26.10.0 and Chromium 153. A fresh Vite page fetched 365,549 raw JS bytes; selective forms/actions CSS fetched 24,729 bytes (aggregate 47,625). The Next Combobox route fetched 593,605 raw client JS bytes and 46,807 CSS bytes, including framework/shared assets. These are dated candidate measurements, not immutable final-archive byte counts. The release gate remeasures its exact archive. These whole-application fixtures are not an isolated component size or an upstream bundle-size badge. Per-file gzip and actual Resource Timing are retained in the report; independent gzip files are not advertised as an additive component total.
50
+
51
+ Every previous journey stays within its existing budget. Initial Combobox budgets are added separately under the same 10% plus 1,024-byte policy; old budgets are not reset to the new measurements. The root Button fixture remains 227,291 raw Vite JS bytes with zero font requests; importing one component does not require downloading the Combobox route's full client code. All runtime dependencies still install with the package. Base UI adds installed files and an unstyled interaction dependency; see FOUNDATION.md for the identical-host comparison and its limitations. Its optional date/time peers are absent from core consumers. TanStack Table/Store and RHF are recipe dependencies only.
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.1** (candidate until published). [Versioned source](https://github.com/abuzareal/contour-ui/tree/v0.6.1/src) and [emitted type inventory](PUBLIC-API.md) describe this contract; tag links resolve after release. [Report Styles 0.6.1](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&component=Styles&version=0.6.1), 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.1** (candidate until published). [Versioned source](https://github.com/abuzareal/contour-ui/tree/v0.6.1/src) and [emitted type inventory](PUBLIC-API.md) describe this contract; tag links resolve after release. [Report Support matrix 0.6.1](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&component=Support%20matrix&version=0.6.1), 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.1** (candidate until published). [Versioned source](https://github.com/abuzareal/contour-ui/tree/v0.6.1/src) and [emitted type inventory](PUBLIC-API.md) describe this contract; tag links resolve after release. [Report Three 0.6.1](https://github.com/abuzareal/contour-ui/issues/new?template=bug_report.yml&component=Three&version=0.6.1), using the [public minimal reproduction](examples/reproduction) and synthetic data.