Initial Commit
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# Tasks — extend-react-ui-runtime-theme-mutation
|
||||
|
||||
## 1. Foundation
|
||||
|
||||
- [ ] Add `INVALID_EXTENSION_TOKEN_NAME` to `REACT_UI_CODES` registry; update the registry doc-comment.
|
||||
- [ ] Update `src/errors/error-codes.test.ts` to pin the new code.
|
||||
|
||||
## 2. Layer stack (module-level)
|
||||
|
||||
- [ ] Create `src/theme/layer-stack/layer-stack.types.ts` with `MutationLayer`, `LayerOrigin`, `LayerStackListener`.
|
||||
- [ ] Create `src/theme/layer-stack/layer-stack.ts` exporting `pushLayer`, `removeLayer`, `updateLayer`, `getMergedResolved`, `subscribe`. Tracks the `Set<string>` of every CSS-var name ever touched; on every change re-applies merged state to the bound root element and removes any tracked name not present in the merged set.
|
||||
- [ ] Co-locate `.md` (≥200 words; basic + advanced examples).
|
||||
- [ ] `layer-stack.test.ts` — runner-agnostic, covers push/pop/update/merge order; tracked-name cleanup on removeLayer.
|
||||
- [ ] `layer-stack/index.ts` — explicit named re-exports only.
|
||||
|
||||
## 3. Provider integration
|
||||
|
||||
- [ ] Modify `theme-provider.tsx` to push a `MutationLayer` for the active plugin on mount and update it on `setTheme(...)` / theme change. Unmount removes the layer. Maintain `providerId` (uuid). Reduced-motion + font-stack writes also go through the layer (so they participate in the unmount cleanup).
|
||||
- [ ] Extend `ThemeContextValue` with a `mutators` field carrying `{ providerId, push, update, remove }` private hooks for `useThemeMutator` consumption. Keep all existing fields and types unchanged.
|
||||
- [ ] Extended `theme-provider.test.tsx` tests:
|
||||
- [ ] "applying the active plugin writes all 19 chassis tokens"
|
||||
- [ ] "switching themes re-applies merged result with mutators still on top"
|
||||
- [ ] "unmounting the provider clears all 19 chassis tokens"
|
||||
|
||||
## 4. `useThemeMutator`
|
||||
|
||||
- [ ] `src/theme/use-theme-mutator/use-theme-mutator.types.ts` — `ThemeMutatorHandle`.
|
||||
- [ ] `src/theme/use-theme-mutator/use-theme-mutator.ts` — implementation. `useRef` + `useEffect` lifecycle. Validates extension keys; throws `ReactUiError(REACT_UI.INVALID_EXTENSION_TOKEN_NAME)`. Calls `clear` on unmount.
|
||||
- [ ] Co-located `.md` (basic = static prop; advanced = runtime fetch + apply).
|
||||
- [ ] `.test.tsx` — at least:
|
||||
- [ ] "setChassisOverrides writes Partial<ThemeTokenSet> on document.documentElement"
|
||||
- [ ] "setExtensionTokens writes arbitrary -- properties on document.documentElement"
|
||||
- [ ] "extension token without -- prefix throws INVALID_EXTENSION_TOKEN_NAME"
|
||||
- [ ] "clear() removes all of this mutator's contributions"
|
||||
- [ ] "unmount removes all of this mutator's contributions"
|
||||
- [ ] "nested mutators stack innermost-wins per key"
|
||||
- [ ] "nested mutator unmount restores outer mutator's value"
|
||||
- [ ] "extension tokens are namespace-orthogonal to chassis tokens"
|
||||
- [ ] "setExtensionTokens replaces previous extension tokens (removed keys are cleared)"
|
||||
- [ ] "throws REACT_UI.NO_PROVIDER outside a ThemeProvider"
|
||||
- [ ] `index.ts` — explicit named re-exports.
|
||||
|
||||
## 5. `useResolvedThemeTokens`
|
||||
|
||||
- [ ] `src/theme/use-resolved-theme-tokens/use-resolved-theme-tokens.ts` — subscribes to layer-stack notifier via `useSyncExternalStore`.
|
||||
- [ ] Co-located `.md`.
|
||||
- [ ] `.test.tsx`:
|
||||
- [ ] "returns the active plugin's tokens when no mutators present"
|
||||
- [ ] "reflects mutator overrides in chassis"
|
||||
- [ ] "reflects mutator extension tokens"
|
||||
- [ ] "throws REACT_UI.NO_PROVIDER outside a ThemeProvider"
|
||||
- [ ] `index.ts`.
|
||||
|
||||
## 6. Subpath exports + barrel
|
||||
|
||||
- [ ] Add `./theme/use-theme-mutator` and `./theme/use-resolved-theme-tokens` to `package.json` exports.
|
||||
- [ ] Re-export new hooks + types from `src/theme/index.ts` (explicit named).
|
||||
- [ ] Re-export from `src/index.ts` (top-level barrel) if precedent is set for `useTheme` / `useThemeTokens`.
|
||||
|
||||
## 7. Story
|
||||
|
||||
- [ ] `theme-provider.stories.tsx` — add a story showing live runtime token-override input (text fields → calls `setExtensionTokens`).
|
||||
|
||||
## 8. Spec reconciliation + gates
|
||||
|
||||
- [ ] Verify every `### Requirement` in `specs/react-ui/spec.md` has a matching `**Verified by:**` `it(...)` title that exists in the codebase.
|
||||
- [ ] `bun run check` (biome).
|
||||
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/react-ui --force`.
|
||||
- [ ] `bunx turbo test:coverage --filter=@suaveplan/react-ui` — no regression on per-metric coverage.
|
||||
- [ ] `bun scripts/openspec-conformance.ts @suaveplan/react-ui` — 0 errors.
|
||||
- [ ] `bunx turbo build --filter=@suaveplan/react-ui --force`.
|
||||
- [ ] `bun scripts/lint/check-test-runner-imports.ts` — 0 violations.
|
||||
|
||||
## 9. Archival
|
||||
|
||||
- [ ] Fold `specs/react-ui/spec.md` delta into canonical `openspec/specs/react-ui/spec.md` (capability is being instantiated for the first time alongside this change; if a prior unarchived change already established the canonical file, merge instead of overwrite).
|
||||
- [ ] Move `openspec/changes/extend-react-ui-runtime-theme-mutation/` → `openspec/archive/2026-05-19-extend-react-ui-runtime-theme-mutation/`.
|
||||
Reference in New Issue
Block a user