# tasks — enterprise-react-ui-theme-dracula ## 0. Pre-flight (non-negotiable) - [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each) - [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest. ## 1. Package scaffolding - [ ] 1.1 Create `packages/react/react-ui-theme-dracula/` directory. - [ ] 1.2 Author `package.json` at version `0.1.0` with peer-deps `@suaveplan/react-ui` and `@suaveplan/react-i18n` (both `workspace:^`), `tslib` from `catalog:build` as the only runtime dep, devDeps for the testing wrappers + biome + vitest from catalog refs. `"sideEffects": ["./src/translations/index.js", "./styles/dracula.css"]` so the side-effect import that registers translations and the CSS file are not tree-shaken away. - [ ] 1.3 Author `tsconfig.json` extending `@suaveplan/typescript-config/library-browser`. - [ ] 1.4 Author `vitest.config.ts` using `createTestConfig()` from `@suaveplan/testing/config`, istanbul provider, thresholds 100/100/100/100. - [ ] 1.5 Author the subpath `exports` map: `.`, `./theme/dracula`, `./tailwind-preset`, `./styles/dracula.css`, `./translations/` for each of the five locales. - [ ] 1.6 Confirm subpath count matches the §6 / §13 step-8 helper output. ## 2. Palette + ThemePlugin - [ ] 2.1 Create `src/theme/dracula.ts` with the canonical Dracula palette as `draculaCssVariables: ThemeTokenSet`. Inline-comment every foreground/background pair with its measured contrast ratio. - [ ] 2.2 Tune any pair below WCAG AA (4.5:1 normal text / 3:1 large + UI) and document the adjustment delta in the same comment. - [ ] 2.3 Construct `draculaTheme: ThemePlugin<'dracula'>` with `name`, `labelKey: 'react-ui-theme-dracula.label'`, `cssVariables`, `tailwindPreset`, `variantOverrides`, `motionTokens`, `colorScheme: 'dark'`, `fontStack` (Dracula's recommended JetBrains Mono / Inter pairing). - [ ] 2.4 Author `src/theme/dracula.md` with the six required sections (≥200 words excluding code blocks). ## 3. Variant overrides — both axes - [ ] 3.1 Create `src/theme/variant-overrides/button.ts` overriding `Button.variants.variant.default` with the Dracula purple shadow and adding `Button.variants.size.xl` (`h-14 px-10 text-xl`). - [ ] 3.2 Create `src/theme/variant-overrides/card.ts` overriding `Card.variants.variant.default` with Dracula border + foreground tokens (override-only path). - [ ] 3.3 Author sibling `.md` files for each. - [ ] 3.4 Author sibling `.test.ts` files; the Button test pins both the override merge AND the brand-new `size: 'xl'` resolution through a narrowed `useThemedVariants<'dracula', 'Button'>('Button')` call. ## 4. Motion tokens - [ ] 4.1 Create `src/theme/motion-tokens.ts` with `respectReducedMotion: 'soft'`, halved durations under reduced-motion, spring disabled, crossfade easings preserved. - [ ] 4.2 Author `motion-tokens.md`. - [ ] 4.3 Author `motion-tokens.test.ts` mocking `matchMedia('(prefers-reduced-motion: reduce)')` and asserting the soft branch resolves the documented values. ## 5. Tailwind preset + CSS file - [ ] 5.1 Create `src/tailwind-preset/tailwind-preset.ts` registering the Dracula colour scale (50–950) plus the brand-new `xl` size token. Plain object literal — no runtime tailwind import. - [ ] 5.2 Author `tailwind-preset.md`. - [ ] 5.3 Author `tailwind-preset.test.ts` asserting the preset shape. - [ ] 5.4 Create `src/styles/dracula.css` declaring the `[data-theme='dracula']` block under `@layer base` for non-Tailwind / SSR-fallback consumers. ## 6. Translations × 5 locales - [ ] 6.1 Create `src/translations/en-GB.json` with `{ "react-ui-theme-dracula.label": "Dracula" }`. (Source of truth; English keeps the brand name.) - [ ] 6.2 Create `src/translations/zh-CN.json` (`"德古拉"` — confirm with native reviewer in PR). - [ ] 6.3 Create `src/translations/ar-AE.json` (`"دراكولا"` — confirm with native reviewer in PR). - [ ] 6.4 Create `src/translations/cy-GB.json` (`"Dracula"` — proper noun stays untranslated). - [ ] 6.5 Create `src/translations/ru-RU.json` (`"Дракула"` — confirm with native reviewer in PR). - [ ] 6.6 Create `src/translations/augmentation.d.ts` augmenting `ContributedTranslationKeys` with `'react-ui-theme-dracula.label': true`. - [ ] 6.7 Create `src/translations/index.ts` exporting the runtime `register` / `unregister` helpers wired into `draculaTheme.onRegister` / `onUnregister`. Side-effect-imports `augmentation.d.ts`. - [ ] 6.8 Author `src/translations/index.md`. - [ ] 6.9 Author `src/translations/index.test.ts` covering register / unregister for all five locales + the type-level `expectTypeOf` assertion that `'react-ui-theme-dracula.label'` is assignable to `TranslationKey`. ## 7. Index + barrel - [ ] 7.1 Create `src/index.ts` with explicit named re-exports — `draculaTheme`, `draculaCssVariables`, `draculaTailwindPreset` — plus the side-effect import of `./translations/index.js`. No `export *` (CLAUDE.md §10). - [ ] 7.2 Verify zero `export *` matches inside `src//index.ts` with the §13 step-4a grep. ## 8. Contract tests - [ ] 8.1 Create `tests/contract.test.tsx`: render `
`, assert `data-theme='dracula'` on the root, assert `getComputedStyle` resolves `--background` to the dracula token, assert `useThemedVariants<'dracula', 'Button'>('Button')({ size: 'xl' })` returns a non-empty class string. - [ ] 8.2 Create `tests/no-radix-deps.test.ts`: parse `package.json`, assert no `@radix-ui/*` or `react-dom` key in any dep block. - [ ] 8.3 Create `tests/wcag-aa.test.ts`: iterate the documented foreground/background pairs, run them through a contrast-ratio helper, assert every pair clears AA. ## 9. Storybook integration in `react-ui` - [ ] 9.1 In `packages/react/react-ui/src/components/button/button.stories.tsx`, add a `WithTheme: dracula` story that wraps `