@chromvoid/headless-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/dist/a11y-contracts/index.d.ts +23 -0
  4. package/dist/a11y-contracts/index.js +1 -0
  5. package/dist/accordion/index.d.ts +78 -0
  6. package/dist/accordion/index.js +264 -0
  7. package/dist/adapters/index.d.ts +9 -0
  8. package/dist/adapters/index.js +1 -0
  9. package/dist/alert/index.d.ts +33 -0
  10. package/dist/alert/index.js +54 -0
  11. package/dist/alert-dialog/index.d.ts +69 -0
  12. package/dist/alert-dialog/index.js +94 -0
  13. package/dist/badge/index.d.ts +48 -0
  14. package/dist/badge/index.js +89 -0
  15. package/dist/breadcrumb/index.d.ts +55 -0
  16. package/dist/breadcrumb/index.js +77 -0
  17. package/dist/button/index.d.ts +46 -0
  18. package/dist/button/index.js +86 -0
  19. package/dist/callout/index.d.ts +41 -0
  20. package/dist/callout/index.js +63 -0
  21. package/dist/card/index.d.ts +54 -0
  22. package/dist/card/index.js +103 -0
  23. package/dist/carousel/index.d.ts +98 -0
  24. package/dist/carousel/index.js +243 -0
  25. package/dist/checkbox/index.d.ts +50 -0
  26. package/dist/checkbox/index.js +87 -0
  27. package/dist/combobox/index.d.ts +114 -0
  28. package/dist/combobox/index.js +431 -0
  29. package/dist/command-palette/index.d.ts +73 -0
  30. package/dist/command-palette/index.js +147 -0
  31. package/dist/context-menu/index.d.ts +111 -0
  32. package/dist/context-menu/index.js +372 -0
  33. package/dist/copy-button/index.d.ts +62 -0
  34. package/dist/copy-button/index.js +183 -0
  35. package/dist/core/index.d.ts +20 -0
  36. package/dist/core/index.js +2 -0
  37. package/dist/core/selection.d.ts +5 -0
  38. package/dist/core/selection.js +39 -0
  39. package/dist/core/value-range.d.ts +49 -0
  40. package/dist/core/value-range.js +134 -0
  41. package/dist/date-picker/index.d.ts +210 -0
  42. package/dist/date-picker/index.js +895 -0
  43. package/dist/dialog/index.d.ts +95 -0
  44. package/dist/dialog/index.js +153 -0
  45. package/dist/disclosure/index.d.ts +52 -0
  46. package/dist/disclosure/index.js +159 -0
  47. package/dist/drawer/index.d.ts +30 -0
  48. package/dist/drawer/index.js +39 -0
  49. package/dist/feed/index.d.ts +77 -0
  50. package/dist/feed/index.js +260 -0
  51. package/dist/grid/index.d.ts +103 -0
  52. package/dist/grid/index.js +415 -0
  53. package/dist/index.d.ts +51 -0
  54. package/dist/index.js +51 -0
  55. package/dist/input/index.d.ts +86 -0
  56. package/dist/input/index.js +156 -0
  57. package/dist/interactions/composite-navigation.d.ts +69 -0
  58. package/dist/interactions/composite-navigation.js +169 -0
  59. package/dist/interactions/index.d.ts +15 -0
  60. package/dist/interactions/index.js +4 -0
  61. package/dist/interactions/keyboard-intents.d.ts +16 -0
  62. package/dist/interactions/keyboard-intents.js +33 -0
  63. package/dist/interactions/overlay-focus.d.ts +40 -0
  64. package/dist/interactions/overlay-focus.js +93 -0
  65. package/dist/interactions/typeahead.d.ts +20 -0
  66. package/dist/interactions/typeahead.js +41 -0
  67. package/dist/landmarks/index.d.ts +39 -0
  68. package/dist/landmarks/index.js +58 -0
  69. package/dist/link/index.d.ts +34 -0
  70. package/dist/link/index.js +39 -0
  71. package/dist/listbox/index.d.ts +92 -0
  72. package/dist/listbox/index.js +337 -0
  73. package/dist/menu/index.d.ts +132 -0
  74. package/dist/menu/index.js +541 -0
  75. package/dist/menu-button/index.d.ts +71 -0
  76. package/dist/menu-button/index.js +121 -0
  77. package/dist/meter/index.d.ts +45 -0
  78. package/dist/meter/index.js +106 -0
  79. package/dist/number/index.d.ts +113 -0
  80. package/dist/number/index.js +252 -0
  81. package/dist/popover/index.d.ts +70 -0
  82. package/dist/popover/index.js +126 -0
  83. package/dist/progress/index.d.ts +49 -0
  84. package/dist/progress/index.js +79 -0
  85. package/dist/radio-group/index.d.ts +61 -0
  86. package/dist/radio-group/index.js +150 -0
  87. package/dist/select/index.d.ts +92 -0
  88. package/dist/select/index.js +239 -0
  89. package/dist/sidebar/index.d.ts +74 -0
  90. package/dist/sidebar/index.js +186 -0
  91. package/dist/slider/index.d.ts +61 -0
  92. package/dist/slider/index.js +150 -0
  93. package/dist/slider-multi-thumb/index.d.ts +70 -0
  94. package/dist/slider-multi-thumb/index.js +222 -0
  95. package/dist/spinbutton/index.d.ts +75 -0
  96. package/dist/spinbutton/index.js +214 -0
  97. package/dist/spinner/index.d.ts +1 -0
  98. package/dist/spinner/index.js +1 -0
  99. package/dist/spinner/spinner.d.ts +23 -0
  100. package/dist/spinner/spinner.js +25 -0
  101. package/dist/switch/index.d.ts +40 -0
  102. package/dist/switch/index.js +61 -0
  103. package/dist/table/index.d.ts +117 -0
  104. package/dist/table/index.js +377 -0
  105. package/dist/tabs/index.d.ts +63 -0
  106. package/dist/tabs/index.js +174 -0
  107. package/dist/textarea/index.d.ts +68 -0
  108. package/dist/textarea/index.js +137 -0
  109. package/dist/toast/index.d.ts +67 -0
  110. package/dist/toast/index.js +145 -0
  111. package/dist/toolbar/index.d.ts +59 -0
  112. package/dist/toolbar/index.js +139 -0
  113. package/dist/tooltip/index.d.ts +52 -0
  114. package/dist/tooltip/index.js +169 -0
  115. package/dist/treegrid/index.d.ts +101 -0
  116. package/dist/treegrid/index.js +463 -0
  117. package/dist/treeview/index.d.ts +68 -0
  118. package/dist/treeview/index.js +370 -0
  119. package/dist/window-splitter/index.d.ts +65 -0
  120. package/dist/window-splitter/index.js +204 -0
  121. package/package.json +92 -0
  122. package/specs/ADR-001-headless-architecture.md +461 -0
  123. package/specs/ADR-002-repo-release-model.md +108 -0
  124. package/specs/ADR-003-public-api-versioning.md +136 -0
  125. package/specs/ADR-004-focus-selection-policy.md +117 -0
  126. package/specs/IMPLEMENTATION-ROADMAP.md +237 -0
  127. package/specs/ISSUE-BACKLOG.md +681 -0
  128. package/specs/RELEASE-CANDIDATE.md +30 -0
  129. package/specs/components/accordion.md +130 -0
  130. package/specs/components/alert-dialog.md +72 -0
  131. package/specs/components/alert.md +65 -0
  132. package/specs/components/badge.md +220 -0
  133. package/specs/components/breadcrumb.md +74 -0
  134. package/specs/components/button.md +115 -0
  135. package/specs/components/callout.md +195 -0
  136. package/specs/components/card.md +280 -0
  137. package/specs/components/carousel.md +140 -0
  138. package/specs/components/checkbox.md +172 -0
  139. package/specs/components/combobox.md +423 -0
  140. package/specs/components/command-palette.md +92 -0
  141. package/specs/components/context-menu.md +556 -0
  142. package/specs/components/copy-button.md +293 -0
  143. package/specs/components/date-picker.md +400 -0
  144. package/specs/components/dialog.md +298 -0
  145. package/specs/components/disclosure.md +257 -0
  146. package/specs/components/drawer.md +353 -0
  147. package/specs/components/feed.md +265 -0
  148. package/specs/components/grid.md +186 -0
  149. package/specs/components/input.md +254 -0
  150. package/specs/components/landmarks.md +136 -0
  151. package/specs/components/link.md +134 -0
  152. package/specs/components/listbox.md +351 -0
  153. package/specs/components/menu-button.md +76 -0
  154. package/specs/components/menu.md +623 -0
  155. package/specs/components/meter.md +149 -0
  156. package/specs/components/number.md +393 -0
  157. package/specs/components/popover.md +252 -0
  158. package/specs/components/progress.md +188 -0
  159. package/specs/components/radio-group.md +151 -0
  160. package/specs/components/select.md +144 -0
  161. package/specs/components/sidebar.md +321 -0
  162. package/specs/components/slider-multi-thumb.md +78 -0
  163. package/specs/components/slider.md +84 -0
  164. package/specs/components/spinbutton.md +140 -0
  165. package/specs/components/spinner.md +132 -0
  166. package/specs/components/switch.md +175 -0
  167. package/specs/components/table.md +403 -0
  168. package/specs/components/tabs.md +265 -0
  169. package/specs/components/textarea.md +185 -0
  170. package/specs/components/toast.md +198 -0
  171. package/specs/components/toolbar.md +278 -0
  172. package/specs/components/tooltip.md +252 -0
  173. package/specs/components/treegrid.md +281 -0
  174. package/specs/components/treeview.md +91 -0
  175. package/specs/components/window-splitter.md +297 -0
  176. package/specs/ops/git-shard-sync.md +107 -0
  177. package/specs/ops/release-checklist.md +76 -0
  178. package/specs/release/GAP-TO-GREEN-ISSUES.md +88 -0
  179. package/specs/release/api-freeze-candidate.md +54 -0
  180. package/specs/release/changelog-automation.md +76 -0
  181. package/specs/release/changelog.generated.md +53 -0
  182. package/specs/release/changelog.patch.generated.md +46 -0
  183. package/specs/release/consumer-integration.md +53 -0
  184. package/specs/release/migration-notes-pre-v1.md +40 -0
  185. package/specs/release/mvp-changelog.md +57 -0
  186. package/specs/release/release-notes-template.md +61 -0
  187. package/specs/release/release-rehearsal.md +113 -0
  188. package/specs/release/semver-deprecation-dry-run.md +89 -0
  189. package/specs/release/shard-release-drill-report.md +50 -0
  190. package/specs/release/shard-release-follow-ups.md +31 -0
  191. package/specs/signals.md +208 -0
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@chromvoid/headless-ui",
3
+ "version": "0.1.0",
4
+ "description": "Headless interaction and accessibility contracts for future UI kit",
5
+ "keywords": [
6
+ "a11y",
7
+ "apg",
8
+ "headless",
9
+ "reatom"
10
+ ],
11
+ "homepage": "https://github.com/chromvoid/headless-ui#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/chromvoid/headless-ui/issues"
14
+ },
15
+ "license": "MIT",
16
+ "author": "ChromVoid Team",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/chromvoid/headless-ui.git"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "LICENSE",
24
+ "README.md",
25
+ "specs"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "main": "./dist/index.js",
30
+ "module": "./dist/index.js",
31
+ "types": "./dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js",
36
+ "default": "./dist/index.js"
37
+ },
38
+ "./*": {
39
+ "types": "./dist/*/index.d.ts",
40
+ "import": "./dist/*/index.js",
41
+ "default": "./dist/*/index.js"
42
+ },
43
+ "./core/*": {
44
+ "types": "./dist/core/*.d.ts",
45
+ "import": "./dist/core/*.js",
46
+ "default": "./dist/core/*.js"
47
+ },
48
+ "./interactions/*": {
49
+ "types": "./dist/interactions/*.d.ts",
50
+ "import": "./dist/interactions/*.js",
51
+ "default": "./dist/interactions/*.js"
52
+ },
53
+ "./package.json": "./package.json"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "scripts": {
59
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && node ./scripts/postbuild.mjs",
60
+ "check:bundle": "npm run build && node ./scripts/check-bundle-contract.mjs",
61
+ "check:exports": "npm run build && node ./scripts/check-package-exports.mjs",
62
+ "check:pack": "npm pack --dry-run",
63
+ "format": "oxfmt --write README.md package.json tsconfig.json tsconfig.build.json vitest.config.ts .oxlintrc.json .oxfmtrc.json src scripts specs",
64
+ "lint": "npm run lint:types && npm run lint:oxlint && npm run lint:format && npm run lint:boundaries",
65
+ "lint:boundaries": "node ./scripts/check-standalone-boundaries.mjs",
66
+ "lint:format": "oxfmt --check README.md package.json tsconfig.json tsconfig.build.json vitest.config.ts .oxlintrc.json .oxfmtrc.json src scripts specs",
67
+ "lint:oxlint": "oxlint --config ./.oxlintrc.json src scripts vitest.config.ts",
68
+ "lint:release-governance": "node ./scripts/check-release-governance.mjs",
69
+ "lint:types": "tsc --noEmit -p tsconfig.json",
70
+ "prepack": "npm run build",
71
+ "prepublishOnly": "npm run lint && npm run test && npm run check:pack",
72
+ "release:changelog": "node ./scripts/generate-changelog.mjs --mode full --out ./specs/release/changelog.generated.md && oxfmt --write ./specs/release/changelog.generated.md",
73
+ "release:changelog:patch": "node ./scripts/generate-changelog.mjs --mode patch --out ./specs/release/changelog.patch.generated.md && oxfmt --write ./specs/release/changelog.patch.generated.md",
74
+ "test": "npm run test:unit && npm run check:exports && npm run check:bundle",
75
+ "test:unit": "vitest run --config ./vitest.config.ts",
76
+ "test:watch": "vitest --config ./vitest.config.ts --watch"
77
+ },
78
+ "dependencies": {
79
+ "@reatom/core": "^1000.15.0"
80
+ },
81
+ "devDependencies": {
82
+ "@types/node": "^24.11.0",
83
+ "esbuild": "^0.27.4",
84
+ "oxfmt": "^0.41.0",
85
+ "oxlint": "^1.51.0",
86
+ "typescript": "^5.9.3",
87
+ "vitest": "^3.2.4"
88
+ },
89
+ "engines": {
90
+ "node": ">=20.0.0"
91
+ }
92
+ }
@@ -0,0 +1,461 @@
1
+ # ADR-001: Architecture of an Independent Headless Package
2
+
3
+ > **Status**: Accepted
4
+ > **Version**: 2026-02-08-r6
5
+ > **Date**: 2026-02-08
6
+ > **Authors**: Team ChromVoid
7
+ > **Related Documents**:
8
+ >
9
+ > - [packages/headless/README.md](../README.md) - package goal
10
+ > - [WAI-ARIA APG patterns](https://www.w3.org/WAI/ARIA/apg/patterns/) - accessibility behavior patterns
11
+ > - [WAI-ARIA APG keyboard interface](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/) - keyboard and focus rules
12
+ > - [Reatom docs](https://www.reatom.dev/) - state management model
13
+ > - [ADR-002-repo-release-model](./ADR-002-repo-release-model.md) - git-shard and release ownership
14
+ > - [ADR-003-public-api-versioning](./ADR-003-public-api-versioning.md) - SemVer and deprecation policy
15
+ > - [ADR-004-focus-selection-policy](./ADR-004-focus-selection-policy.md) - shared focus/selection policy
16
+ >
17
+ > **Note**: `packages/headless` in this monorepo is a development mirror.
18
+ > The canonical source, versioning, and publishing flow live in a separate public git-shard repository.
19
+
20
+ ## Context
21
+
22
+ We need a highly independent headless package for a future UI kit:
23
+
24
+ - no visual layer;
25
+ - Reatom v1000 as the state runtime;
26
+ - behavior contracts aligned with WAI-ARIA APG.
27
+
28
+ The package is developed in this monorepo for local integration speed,
29
+ but it must stay independent from internal architecture and internal modules.
30
+
31
+ ## Problem
32
+
33
+ If this package is treated as a regular internal monorepo module, we get:
34
+
35
+ - hidden dependencies on `@project/*`, `apps/*`, and internal scripts;
36
+ - low portability outside this repository;
37
+ - release and publishing ambiguity;
38
+ - API evolution coupled to one product architecture.
39
+
40
+ ## Goals
41
+
42
+ 1. Lock architectural independence as a hard requirement.
43
+ 2. Define module boundaries: `core -> interactions -> a11y-contracts -> adapters`.
44
+ 3. Define a stable public API shape (`createX`, `get*Props`, `actions/selectors`).
45
+ 4. Lock repository model: public git-shard is the canonical source.
46
+ 5. Define standalone build/test/release expectations.
47
+
48
+ ## Non-Goals
49
+
50
+ - Adapting architecture to current internal monorepo modules.
51
+ - Using internal dependencies such as `@project/*`.
52
+ - Migrating existing apps in this ADR.
53
+ - Implementing all UI widgets in this ADR.
54
+
55
+ ## Decision
56
+
57
+ ### 1. Repository Model and Ownership
58
+
59
+ 1. `packages/headless` in this monorepo is a development mirror.
60
+ 2. Canonical code history, tags, and releases are managed in a separate public git-shard repository.
61
+ 3. Publishing to package registries is done only from git-shard.
62
+
63
+ **MUST NOT**: use the monorepo as a release source of truth for this package.
64
+
65
+ ### 2. Independence Constraints (Hard)
66
+
67
+ The package **MUST**:
68
+
69
+ - build and test in an isolated checkout without this monorepo;
70
+ - use only public dependencies;
71
+ - have package-local scripts, specs, tests, and release flow.
72
+
73
+ The package **MUST NOT**:
74
+
75
+ - import `@project/*`, `apps/*`, or files outside package boundaries;
76
+ - rely on monorepo lifecycle scripts as required runtime/release steps;
77
+ - encode product-specific assumptions.
78
+
79
+ ### 3. Layered Architecture
80
+
81
+ The package follows one-way dependencies:
82
+
83
+ 1. `core/`
84
+
85
+ - state and invariants on Reatom;
86
+ - no DOM or framework imports.
87
+
88
+ 2. `interactions/`
89
+
90
+ - reusable keyboard/pointer intent logic;
91
+ - no rendering concerns.
92
+
93
+ 3. `a11y-contracts/`
94
+
95
+ - APG-oriented role and aria contracts;
96
+ - focus and selection semantics.
97
+
98
+ 4. `adapters/`
99
+
100
+ - thin mapping to presentation layers;
101
+ - no business logic.
102
+
103
+ `core` does not depend on `adapters`, concrete app code, or design system code.
104
+
105
+ ### 4. Public API
106
+
107
+ Stable API shape:
108
+
109
+ - `createX(options)`;
110
+ - `state` and `selectors`;
111
+ - `actions` and `api` (or `contracts` for grouped prop getters);
112
+ - `get*Props()`.
113
+
114
+ #### API Terminology Mapping
115
+
116
+ To ensure consistency across components, we use the following canonical mapping:
117
+
118
+ - **State**: Raw reactive signals (Reatom atoms).
119
+ - **Selectors**: Computed derivations of state (Reatom computed).
120
+ - **Actions**: Methods that mutate state or trigger side effects.
121
+ - **Contracts / API**: Grouped prop getters (`get*Props`) that return ARIA-compliant attribute sets.
122
+
123
+ #### Selectors Guidance
124
+
125
+ Selectors MUST be used for any derived state logic to ensure:
126
+
127
+ 1. Components only re-render when the specific derived value changes.
128
+ 2. Business logic is decoupled from the raw state structure.
129
+ 3. Complex calculations are memoized via Reatom's `computed`.
130
+
131
+ Example:
132
+
133
+ - `createListbox(options) -> { state, selectors, actions, getRootProps, getOptionProps }`.
134
+
135
+ ### 5. State Runtime Policy
136
+
137
+ - **MUST**: Reatom v1000.
138
+ - **MUST NOT**: `@statx/*` in headless core.
139
+
140
+ ### 6. Testing and Verification
141
+
142
+ Implementation strategy:
143
+
144
+ - TDD (red-green-refactor);
145
+ - unit tests for transitions, invariants, and contracts;
146
+ - integration tests for adapter behavior;
147
+ - agent-executed QA scenarios for keyboard and focus flows.
148
+
149
+ Additional rule:
150
+
151
+ - standalone test execution (outside monorepo coupling) is mandatory.
152
+
153
+ ### 7. Component Packaging Convention
154
+
155
+ For every headless component:
156
+
157
+ - use a dedicated directory: `src/<component>/`;
158
+ - expose a component entrypoint: `src/<component>/index.ts`;
159
+ - keep unit tests near component code: `src/<component>/<component>.test.ts`;
160
+ - add a component spec file: `specs/components/<component>.md`.
161
+
162
+ ## Alternatives
163
+
164
+ ### A. Keep the package fully internal in this monorepo
165
+
166
+ **Rejected**:
167
+
168
+ - conflicts with independent/public package goals;
169
+ - increases risk of hidden internal coupling.
170
+
171
+ ### B. Build as monorepo-only first, split later
172
+
173
+ **Rejected**:
174
+
175
+ - split migration is expensive and often breaks API;
176
+ - increases architecture debt.
177
+
178
+ ### C. Mix headless logic into current UI modules
179
+
180
+ **Rejected**:
181
+
182
+ - breaks package independence;
183
+ - reduces reuse outside current product boundaries.
184
+
185
+ ## Consequences
186
+
187
+ ### Positive
188
+
189
+ - portable package reusable outside this repository;
190
+ - release lifecycle independent from monorepo cadence;
191
+ - architecture decisions are not constrained by one internal system;
192
+ - better fit for public distribution.
193
+
194
+ ### Negative
195
+
196
+ - additional sync overhead between mirror and git-shard;
197
+ - separate CI/CD and release governance required;
198
+ - local development requires strict import-boundary discipline.
199
+
200
+ ## Comprehensive Implementation Roadmap
201
+
202
+ This section is the execution blueprint for component delivery, test hardening,
203
+ and release readiness. It is intentionally explicit to reduce architectural drift.
204
+
205
+ Issue-ready decomposition is maintained in:
206
+
207
+ - [ISSUE-BACKLOG.md](./ISSUE-BACKLOG.md)
208
+
209
+ ### Program-Level Principles
210
+
211
+ 1. Build in vertical slices (`state -> interactions -> a11y contracts -> tests -> docs`).
212
+ 2. Do not introduce shared abstractions before at least two components need them.
213
+ 3. Keep APG behavior contracts as first-class public API.
214
+ 4. Every behavior change requires test updates in the same change set.
215
+ 5. Release only from git-shard after all package gates pass.
216
+
217
+ ### Workstreams
218
+
219
+ - **Component Workstream**: component directories, component APIs, specs.
220
+ - **Testing Workstream**: unit/contract/integration tests and regression suites.
221
+ - **Tooling Workstream**: lint, boundary checks, CI jobs, release automation.
222
+ - **Documentation Workstream**: ADR updates, component specs, migration notes.
223
+
224
+ ### Delivery Waves
225
+
226
+ | Wave | Scope | Primary Output | Exit Criteria |
227
+ | ---- | ------------------- | ------------------------------------------------------------------ | -------------------------------------------------------- |
228
+ | 0 | Foundation Baseline | standalone package skeleton + guardrails | lint/test/boundary gates are green |
229
+ | 1 | Listbox Hardening | production-ready listbox contract | APG key behavior and advanced tests complete |
230
+ | 2 | Shared Primitives | reusable interaction helpers extracted from listbox/combobox needs | at least 2 consumers use each extracted primitive |
231
+ | 3 | Combobox | APG combobox headless contract | keyboard + filtering + active-descendant contract stable |
232
+ | 4 | Menu | menu button + menu contract | open/close/nav/dismiss behavior stable |
233
+ | 5 | Tabs | tabs + tabpanel contract | manual and automatic activation modes verified |
234
+ | 6 | Treeview | hierarchical navigation contract | expansion and structural ARIA invariants verified |
235
+ | 7 | Release Readiness | first public stable release line | SemVer/deprecation/release process validated end-to-end |
236
+
237
+ ### Wave 0: Foundation Baseline
238
+
239
+ **Status**: complete
240
+
241
+ Deliverables:
242
+
243
+ - package skeleton with layered directories
244
+ - package-local lint, format, boundary checks
245
+ - dedicated CI workflow for headless paths
246
+ - ADR-001..ADR-004 baseline architecture docs
247
+
248
+ Completion notes:
249
+
250
+ - git-shard mirror automation policy documented in `specs/ops/git-shard-sync.md`
251
+ - shard release checklist documented in `specs/ops/release-checklist.md`
252
+
253
+ ### Wave 1: Listbox Hardening
254
+
255
+ Deliverables:
256
+
257
+ - finalize `createListbox` behavior contract
258
+ - add missing APG-compliant interactions:
259
+ - typeahead (single char + buffered sequence)
260
+ - optional range selection (`Shift+Arrow`, `Shift+Space`) in multi-select mode
261
+ - orientation parity and edge-case handling
262
+ - finalize `specs/components/listbox.md`
263
+
264
+ Required test matrix additions:
265
+
266
+ - typeahead buffer lifecycle and matching order
267
+ - range selection semantics and invariant checks
268
+ - horizontal keyboard map parity
269
+ - disabled-option behavior for all interaction paths
270
+ - focus strategy parity (`roving-tabindex` vs `aria-activedescendant`)
271
+
272
+ Exit criteria:
273
+
274
+ - listbox test suite covers all APG-required core behavior for supported modes
275
+ - no TODO/FIXME placeholders in listbox contract docs
276
+
277
+ ### Wave 2: Shared Primitives Extraction
278
+
279
+ Scope:
280
+
281
+ - extract only proven shared logic from completed components
282
+ - no speculative utility modules
283
+
284
+ Candidate primitives:
285
+
286
+ - keyboard intent mapping
287
+ - typeahead engine
288
+ - roving index and active-descendant bookkeeping
289
+ - selection reducers (single/multi/range)
290
+
291
+ Exit criteria:
292
+
293
+ - each primitive has at least two component consumers
294
+ - each primitive has direct unit tests and contract-level tests via components
295
+
296
+ ### Wave 3: Combobox
297
+
298
+ Target files:
299
+
300
+ - `src/combobox/index.ts`
301
+ - `src/combobox/combobox.test.ts`
302
+ - `specs/components/combobox.md`
303
+
304
+ Core behaviors:
305
+
306
+ - controlled/uncontrolled input value contract
307
+ - popup open/close semantics
308
+ - active option tracking via `aria-activedescendant`
309
+ - option commit behavior (`Enter`, click, selection actions)
310
+
311
+ Tests:
312
+
313
+ - keyboard navigation across input and listbox states
314
+ - input filtering hooks contract
315
+ - aria linkage integrity (`aria-controls`, `aria-activedescendant`)
316
+ - disabled and empty-result states
317
+
318
+ Exit criteria:
319
+
320
+ - combobox behavior is APG-aligned for supported mode
321
+ - filtering and commit behavior are deterministic and documented
322
+
323
+ ### Wave 4: Menu
324
+
325
+ Target files:
326
+
327
+ - `src/menu/index.ts`
328
+ - `src/menu/menu.test.ts`
329
+ - `specs/components/menu.md`
330
+
331
+ Core behaviors:
332
+
333
+ - trigger-open-close model
334
+ - arrow navigation and wrapping policy
335
+ - dismissal semantics (`Escape`, outside interactions)
336
+
337
+ Tests:
338
+
339
+ - open source (keyboard vs pointer) behavior
340
+ - focus return policy on close
341
+ - disabled item and activation rules
342
+
343
+ Exit criteria:
344
+
345
+ - deterministic menu lifecycle and key contract across supported modes
346
+
347
+ ### Wave 5: Tabs
348
+
349
+ Target files:
350
+
351
+ - `src/tabs/index.ts`
352
+ - `src/tabs/tabs.test.ts`
353
+ - `specs/components/tabs.md`
354
+
355
+ Core behaviors:
356
+
357
+ - manual vs automatic activation modes
358
+ - orientation-aware key navigation
359
+ - tab/panel relationship contracts
360
+
361
+ Tests:
362
+
363
+ - activation mode deltas
364
+ - disabled tab traversal
365
+ - role/aria linkage contract assertions
366
+
367
+ Exit criteria:
368
+
369
+ - tabs behavior contract documented and stable for both activation modes
370
+
371
+ ### Wave 6: Treeview
372
+
373
+ Target files:
374
+
375
+ - `src/treeview/index.ts`
376
+ - `src/treeview/treeview.test.ts`
377
+ - `specs/components/treeview.md`
378
+
379
+ Core behaviors:
380
+
381
+ - hierarchical expansion/collapse semantics
382
+ - visible-node focus traversal
383
+ - optional multi-select behavior model
384
+
385
+ Tests:
386
+
387
+ - structural ARIA metadata (`aria-level`, `aria-posinset`, `aria-setsize`)
388
+ - expansion keyboard behavior (`ArrowLeft`, `ArrowRight`)
389
+ - selected/focused node invariants under collapse
390
+
391
+ Exit criteria:
392
+
393
+ - tree behavior is deterministic and APG-compliant for supported subset
394
+
395
+ ### Wave 7: Release Readiness and Stabilization
396
+
397
+ Scope:
398
+
399
+ - API freeze candidate and release candidate process
400
+ - SemVer and deprecation process dry-run
401
+ - shard-only release pipeline validation
402
+
403
+ Deliverables:
404
+
405
+ - release checklist in shard
406
+ - migration notes for any pre-1.0 breaking cleanup
407
+ - first stable tag candidate strategy
408
+
409
+ Exit criteria:
410
+
411
+ - full release drill succeeds from git-shard with no monorepo coupling
412
+
413
+ ### Testing Roadmap by Layer
414
+
415
+ 1. **State Tests**: transitions, invariants, reducer-like behavior.
416
+ 2. **Interaction Tests**: keyboard intent mapping and edge key sequences.
417
+ 3. **A11y Contract Tests**: exact role/aria/tabindex prop contracts.
418
+ 4. **Integration Tests**: component-level behavior with realistic option sets.
419
+ 5. **Regression Tests**: one test per fixed bug before closure.
420
+
421
+ ### Definition of Done (Per Component)
422
+
423
+ 1. Component code in `src/<component>/`.
424
+ 2. Component spec in `specs/components/<component>.md`.
425
+ 3. Export wired in `src/index.ts`.
426
+ 4. Full test matrix for supported behavior.
427
+ 5. `npm run lint` is green.
428
+ 6. `npm run test` is green.
429
+ 7. Boundary check remains green.
430
+
431
+ ### Prioritized Execution Order
432
+
433
+ 1. Listbox hardening
434
+ 2. Combobox
435
+ 3. Menu
436
+ 4. Tabs
437
+ 5. Treeview
438
+
439
+ This order maximizes reuse of interaction primitives while minimizing rework.
440
+
441
+ ### Risk Register and Mitigations
442
+
443
+ - **Risk**: over-abstraction too early.
444
+ - **Mitigation**: extract shared primitives only after two concrete consumers.
445
+ - **Risk**: APG drift between components.
446
+ - **Mitigation**: enforce ADR-004 invariants + contract tests.
447
+ - **Risk**: hidden monorepo coupling.
448
+ - **Mitigation**: keep boundary script mandatory in CI and release gates.
449
+ - **Risk**: behavior-breaking changes slip into minor releases.
450
+ - **Mitigation**: enforce ADR-003 release classification checklist.
451
+
452
+ ## Change History
453
+
454
+ | Date | Change |
455
+ | ---------- | ---------------------------------------------------------------------------------------------------- |
456
+ | 2026-02-08 | Initial draft created (r1) |
457
+ | 2026-02-08 | Reframed as standalone package with git-shard ownership (r2) |
458
+ | 2026-02-08 | Rewritten to full English and aligned with current conventions (r3) |
459
+ | 2026-02-08 | Expanded with a comprehensive multi-wave roadmap, test matrix, exit criteria, and risk register (r4) |
460
+ | 2026-02-08 | Added issue-ready backlog linkage and execution decomposition (r5) |
461
+ | 2026-02-08 | Marked ADR as accepted and synced Wave 0 completion details to current implementation state (r6) |
@@ -0,0 +1,108 @@
1
+ # ADR-002: Repository and Release Model for the Headless Package
2
+
3
+ > **Status**: Draft
4
+ > **Version**: 2026-02-08-r2
5
+ > **Date**: 2026-02-08
6
+ > **Authors**: Team ChromVoid
7
+ > **Related Documents**:
8
+ >
9
+ > - [ADR-001-headless-architecture](./ADR-001-headless-architecture.md) - architectural independence baseline
10
+
11
+ ## Context
12
+
13
+ `packages/headless` is developed in the monorepo for local integration convenience.
14
+ The package must still be published as an independent public package from a separate git-shard repository.
15
+
16
+ Without a clear model, mirror and shard will drift, and releases will become hard to reproduce.
17
+
18
+ ## Problem
19
+
20
+ We need a formal source-of-truth and release flow that answers:
21
+
22
+ - where canonical history lives;
23
+ - where npm publishing happens;
24
+ - how changes sync between mirror and shard;
25
+ - how to prevent accidental releases from monorepo.
26
+
27
+ ## Goals
28
+
29
+ 1. Set git-shard as the only canonical source.
30
+ 2. Define release flow from git-shard only.
31
+ 3. Define sync rules between monorepo mirror and shard.
32
+ 4. Reduce drift and accidental release risk.
33
+
34
+ ## Non-Goals
35
+
36
+ - Hosting-specific CI/CD details.
37
+ - Full sync automation in this ADR.
38
+ - Governance for unrelated monorepo packages.
39
+
40
+ ## Decision
41
+
42
+ ### 1. Source of Truth
43
+
44
+ 1. Public git-shard repository is the single canonical source for `headless`.
45
+ 2. `packages/headless` in monorepo is mirror-only development workspace.
46
+
47
+ ### 2. Release Ownership
48
+
49
+ 1. `npm publish` runs only from git-shard.
50
+ 2. Release tags (`vX.Y.Z`) are created only in git-shard.
51
+ 3. Monorepo release of this package is forbidden.
52
+
53
+ ### 3. Sync Model
54
+
55
+ - `monorepo -> shard`: allowed for feature work and integration-driven changes.
56
+ - `shard -> monorepo`: required after every release and architecture-level change.
57
+
58
+ MUST:
59
+
60
+ - keep public API equivalent between mirror and shard;
61
+ - sync ADR/spec updates in both directions;
62
+ - run boundary, lint, and test checks before sync.
63
+
64
+ ### 4. Minimal Release Gate (in git-shard)
65
+
66
+ Before release:
67
+
68
+ 1. run `lint` (types + oxlint + oxfmt + boundaries);
69
+ 2. run package tests;
70
+ 3. update changelog;
71
+ 4. bump version according to SemVer;
72
+ 5. create release tag and release notes.
73
+
74
+ ## Alternatives
75
+
76
+ ### A. Release directly from monorepo
77
+
78
+ **Rejected**:
79
+
80
+ - breaks independent package model;
81
+ - increases risk of leaking internal dependencies.
82
+
83
+ ### B. Keep only git-shard and remove monorepo mirror
84
+
85
+ **Rejected**:
86
+
87
+ - hurts local integration workflow;
88
+ - increases collaboration friction with product development.
89
+
90
+ ## Consequences
91
+
92
+ ### Positive
93
+
94
+ - clear release ownership;
95
+ - reproducible publication flow;
96
+ - lower risk of accidental monorepo coupling.
97
+
98
+ ### Negative
99
+
100
+ - ongoing sync overhead;
101
+ - additional operational governance for changelog, tagging, and release discipline.
102
+
103
+ ## Change History
104
+
105
+ | Date | Change |
106
+ | ---------- | ------------------------------------------------------ |
107
+ | 2026-02-08 | Initial draft created (r1) |
108
+ | 2026-02-08 | Rewritten to full English and terminology cleanup (r2) |