@phcdevworks/spectre-ui 1.7.0 → 1.9.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,97 @@ reflects package releases published to npm.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.9.0] - 2026-06-10
10
+
11
+ Release Title: Component Recipe Expansion
12
+
13
+ Contract change type: additive
14
+
15
+ ### Added
16
+
17
+ - **Nav Recipe**: Added `getNavClasses`, `getNavLinksClasses`, and
18
+ `getNavLinkClasses` recipes plus `.sp-nav`, `.sp-nav__links`, and
19
+ `.sp-nav__link` CSS in `src/styles/components.css`. Consumes the new
20
+ `component.nav` tokens (`nav.bg`, `nav.text`, `nav.link`, `nav.linkHover`,
21
+ `nav.linkActive`, `nav.border`) published in
22
+ `@phcdevworks/spectre-tokens@2.9.0`. `getNavClasses` supports `bordered`,
23
+ `sticky`, and `fullWidth`; `getNavLinkClasses` supports `active`, `disabled`,
24
+ `hovered`, and `focused`. This is the first of the five Phase 4 component
25
+ recipes in `TODO.md`. Raised the `components.css` size budget in
26
+ `tests/css-entrypoints.test.ts` from 92000 to 96000 bytes.
27
+
28
+ - **Toast Recipe**: Added `getToastClasses` and `getToastIconClasses` recipes
29
+ plus `.sp-toast` and `.sp-toast__icon` CSS in `src/styles/components.css`.
30
+ Consumes the new `component.toast` tokens (`toast.{success,warning,danger,info}.{bg,text,border,icon}`)
31
+ published in `@phcdevworks/spectre-tokens@2.9.0`. `getToastClasses` supports
32
+ `info`, `success`, `warning`, and `danger` variants plus `dismissed` and
33
+ `fullWidth`; `getToastIconClasses` mirrors the same variants for icon color.
34
+ This is the second of the five Phase 4 component recipes in `TODO.md`.
35
+ Raised the `components.css` size budget in `tests/css-entrypoints.test.ts`
36
+ from 96000 to 100000 bytes.
37
+
38
+ - **Tooltip Recipe**: Added `getTooltipClasses` recipe plus `.sp-tooltip` CSS
39
+ in `src/styles/components.css`. Consumes the new `component.tooltip` tokens
40
+ (`tooltip.bg`, `tooltip.text`, `tooltip.border`) along with the existing
41
+ `--sp-opacity-tooltip` and `--sp-z-index-tooltip` primitives published in
42
+ `@phcdevworks/spectre-tokens@2.9.0`. `getTooltipClasses` supports `top`,
43
+ `bottom`, `left`, and `right` placements plus a `visible` flag. This is the
44
+ third of the five Phase 4 component recipes in `TODO.md`.
45
+
46
+ - **Dropdown Recipe**: Added `getDropdownClasses`, `getDropdownMenuClasses`,
47
+ and `getDropdownItemClasses` recipes plus `.sp-dropdown`,
48
+ `.sp-dropdown__menu`, and `.sp-dropdown__item` CSS in
49
+ `src/styles/components.css`. Consumes the new `component.dropdown` tokens
50
+ (`dropdown.bg`, `dropdown.border`, `dropdown.item.default`,
51
+ `dropdown.item.hover`, `dropdown.item.active`, `dropdown.item.text`)
52
+ published in `@phcdevworks/spectre-tokens@2.9.0`. `getDropdownClasses`
53
+ supports `fullWidth`; `getDropdownMenuClasses` supports `bottom-start`,
54
+ `bottom-end`, `top-start`, and `top-end` placements plus an `open` flag;
55
+ `getDropdownItemClasses` supports `active`, `disabled`, `hovered`, and
56
+ `focused`. This is the fourth of the five Phase 4 component recipes in
57
+ `TODO.md`. Raised the `components.css` size budget in
58
+ `tests/css-entrypoints.test.ts` from 100000 to 105000 bytes.
59
+
60
+ - **Modal Recipe**: Added `getModalClasses` and `getModalOverlayClasses`
61
+ recipes plus `.sp-modal` and `.sp-modal-overlay` CSS in
62
+ `src/styles/components.css`. Consumes the new `component.modal` tokens
63
+ (`modal.bg`, `modal.shadow`, `modal.border`, `modal.overlay`) along with the
64
+ existing `--sp-z-index-modal` primitive published in
65
+ `@phcdevworks/spectre-tokens@2.9.0`. `getModalClasses` supports `open` and
66
+ `fullWidth`; `getModalOverlayClasses` supports `open`. This is the fifth and
67
+ final of the five Phase 4 component recipes in `TODO.md`.
68
+
69
+ ### Changed
70
+
71
+ - **Token Alignment**: Updated `@phcdevworks/spectre-tokens` dependency to
72
+ `^2.9.0`. The published bundle now carries the five Phase 4 `component.*`
73
+ token groups (`nav`, `toast`, `tooltip`, `dropdown`, `modal`) for light and
74
+ dark modes, unblocking the matching recipe work in `TODO.md`. Raised the
75
+ `components.css` size budget in `tests/css-entrypoints.test.ts` from 88000 to
76
+ 92000 bytes to account for the additional bundled token variables.
77
+
78
+ ## [1.8.0] - 2026-06-07
79
+
80
+ Release Title: Spinner Contract and Token Focus Alignment
81
+
82
+ Contract change type: additive
83
+
84
+ ### Added
85
+
86
+ - **Spinner Component**: Added standard brand and status variants (`primary`,
87
+ `secondary`, `success`, `warning`, `danger`, `info`, `neutral`, `accent`,
88
+ `cta`) and states (`disabled`, `loading` with `[aria-busy="true"]` support).
89
+ - Added `@phcdevworks/spectre-manifest` as a devDependency. `spectre.manifest.json`
90
+ at the repo root declares this package's ecosystem role, layer, exports, and
91
+ allowed dependency targets. `check:ecosystem` validates it in the check pipeline.
92
+ - **Token Alignment**: Updated `@phcdevworks/spectre-tokens` dependency to
93
+ `^2.8.0`.
94
+ - **Button Focus Ring Parity**: Consumed `buttons.danger.focusVisible` and
95
+ `buttons.success.focusVisible` tokens newly published in `2.8.0`. Danger and
96
+ success button variants now render a semantically correct focus ring (red and
97
+ green alpha respectively) on `:focus-visible`, matching the parity already
98
+ present for primary, secondary, ghost, and accent variants.
99
+
9
100
  ## [1.7.0] - 2026-06-03
10
101
 
11
102
  Release Title: Tag Variant Expansion and Token Alignment
package/README.md CHANGED
@@ -27,25 +27,25 @@ belongs in adapter packages such as `@phcdevworks/spectre-ui-astro`).
27
27
  semantic meaning. `ui-contract.manifest.json` is the machine-readable contract
28
28
  authority for this package's public styling surface.
29
29
 
30
- | Layer | Path | Rule |
31
- |---|---|---|
32
- | Token authority | Published `@phcdevworks/spectre-tokens` package | Design values and semantic meaning start there |
33
- | UI contract authority | `ui-contract.manifest.json` | Governs public recipes, CSS entry points, and Tailwind exports |
34
- | Source CSS | `src/styles/` | Token-backed CSS classes and bundle entry points |
35
- | Source recipes | `src/recipes/` | Framework-agnostic class string APIs |
36
- | Tailwind helpers | `src/tailwind/` | Tailwind theme and preset integration |
37
- | Generated dist | `dist/` | **Never edit directly** — regenerated by `npm run build` |
30
+ | Layer | Path | Rule |
31
+ | --------------------- | ----------------------------------------------- | -------------------------------------------------------------- |
32
+ | Token authority | Published `@phcdevworks/spectre-tokens` package | Design values and semantic meaning start there |
33
+ | UI contract authority | `ui-contract.manifest.json` | Governs public recipes, CSS entry points, and Tailwind exports |
34
+ | Source CSS | `src/styles/` | Token-backed CSS classes and bundle entry points |
35
+ | Source recipes | `src/recipes/` | Framework-agnostic class string APIs |
36
+ | Tailwind helpers | `src/tailwind/` | Tailwind theme and preset integration |
37
+ | Generated dist | `dist/` | **Never edit directly** — regenerated by `npm run build` |
38
38
 
39
39
  After any contract-facing source change: run `npm run check` to validate the
40
40
  full UI contract.
41
41
 
42
42
  ## Architecture
43
43
 
44
- | Layer | Package or consumer | Responsibility | Relationship to this package |
45
- |---|---|---|---|
46
- | 1 | `@phcdevworks/spectre-tokens` | Defines design values and semantic token meaning | Upstream source of truth |
47
- | 2 | `@phcdevworks/spectre-ui` | Translates tokens into CSS bundles, Tailwind helpers, and class recipes | This package |
48
- | 3 | Adapters and apps, such as `@phcdevworks/spectre-ui-astro` | Deliver Spectre through framework-native ergonomics | Downstream consumers |
44
+ | Layer | Package or consumer | Responsibility | Relationship to this package |
45
+ | ----- | ---------------------------------------------------------- | ----------------------------------------------------------------------- | ---------------------------- |
46
+ | 1 | `@phcdevworks/spectre-tokens` | Defines design values and semantic token meaning | Upstream source of truth |
47
+ | 2 | `@phcdevworks/spectre-ui` | Translates tokens into CSS bundles, Tailwind helpers, and class recipes | This package |
48
+ | 3 | Adapters and apps, such as `@phcdevworks/spectre-ui-astro` | Deliver Spectre through framework-native ergonomics | Downstream consumers |
49
49
 
50
50
  `@phcdevworks/spectre-components` is a separate component package that can wrap
51
51
  this styling contract in Lit web components. This package owns Layer 2 only: it
@@ -71,8 +71,8 @@ does not deliver components and it does not define tokens.
71
71
  - Tailwind preset and theme helpers in `src/tailwind/`
72
72
  - Contract validation that keeps CSS, recipes, exports, and docs aligned
73
73
 
74
- This package is the correct place to define reusable styling structure on top
75
- of Spectre tokens.
74
+ This package is the correct place to define reusable styling structure on top of
75
+ Spectre tokens.
76
76
 
77
77
  ## What this package does not own
78
78
 
@@ -100,7 +100,10 @@ No framework needed. Import the CSS and use the `sp-*` classes directly:
100
100
  <!doctype html>
101
101
  <html>
102
102
  <head>
103
- <link rel="stylesheet" href="node_modules/@phcdevworks/spectre-ui/dist/index.css" />
103
+ <link
104
+ rel="stylesheet"
105
+ href="node_modules/@phcdevworks/spectre-ui/dist/index.css"
106
+ />
104
107
  </head>
105
108
  <body>
106
109
  <button class="sp-btn sp-btn--primary sp-btn--md">Save</button>
@@ -197,17 +200,17 @@ Do not use `@phcdevworks/spectre-ui` when you need to:
197
200
 
198
201
  ## What belongs here vs elsewhere
199
202
 
200
- | What | Where it lives |
201
- |---|---|
202
- | Semantic color values, spacing scale, type scale | `@phcdevworks/spectre-tokens` |
203
- | Token-to-CSS variable mapping | **here** — `src/styles/` |
204
- | Precompiled CSS bundles | **here** — built to `dist/*.css` |
205
- | Class recipe functions (input → class string) | **here** — `src/recipes/` |
206
- | Tailwind preset and theme helpers | **here** — `src/tailwind/` |
207
- | Astro, React, Vue, Lit, Svelte components | Adapter packages (e.g. `spectre-ui-astro`) |
208
- | WordPress shortcodes or PHP templates | A WordPress adapter package |
209
- | App-level layout, routing, or data fetching | Consuming apps |
210
- | New design decisions (new colors, new spacing) | `@phcdevworks/spectre-tokens` |
203
+ | What | Where it lives |
204
+ | ------------------------------------------------ | ------------------------------------------ |
205
+ | Semantic color values, spacing scale, type scale | `@phcdevworks/spectre-tokens` |
206
+ | Token-to-CSS variable mapping | **here** — `src/styles/` |
207
+ | Precompiled CSS bundles | **here** — built to `dist/*.css` |
208
+ | Class recipe functions (input → class string) | **here** — `src/recipes/` |
209
+ | Tailwind preset and theme helpers | **here** — `src/tailwind/` |
210
+ | Astro, React, Vue, Lit, Svelte components | Adapter packages (e.g. `spectre-ui-astro`) |
211
+ | WordPress shortcodes or PHP templates | A WordPress adapter package |
212
+ | App-level layout, routing, or data fetching | Consuming apps |
213
+ | New design decisions (new colors, new spacing) | `@phcdevworks/spectre-tokens` |
211
214
 
212
215
  Golden rule: this package consumes tokens and exposes class contracts. It does
213
216
  not define tokens and it does not deliver framework components.
@@ -219,21 +222,26 @@ not define tokens and it does not deliver framework components.
219
222
  All recipe functions accept a plain options object and return a class string.
220
223
  All options are optional and fall back to sensible defaults.
221
224
 
222
- | Recipe | Function | Variants | Sizes | Common boolean flags |
223
- |---|---|---|---|---|
224
- | Button | `getButtonClasses` | `primary` `secondary` `ghost` `danger` `success` `cta` `accent` | `sm` `md` `lg` | `disabled` `loading` `fullWidth` `pill` `iconOnly` |
225
- | Badge | `getBadgeClasses` | `primary` `secondary` `success` `warning` `danger` `neutral` `info` `ghost` `accent` `cta` | `sm` `md` `lg` | `interactive` `disabled` `loading` `fullWidth` |
226
- | Card | `getCardClasses` | `elevated` `flat` `outline` `ghost` | — | `interactive` `padded` `fullHeight` `disabled` `loading` |
227
- | Input | `getInputClasses` | — | `sm` `md` `lg` | `disabled` `loading` `fullWidth` `pill` |
228
- | Input state | `getInputClasses` | `state`: `default` `error` `success` `disabled` `loading` | — | — |
229
- | IconBox | `getIconBoxClasses` | `primary` `secondary` `success` `warning` `danger` `info` `neutral` `ghost` `accent` `cta` | `sm` `md` `lg` | `interactive` `disabled` `loading` `pill` `fullWidth` |
230
- | PricingCard | `getPricingCardClasses` | — | — | `featured` `interactive` `disabled` `loading` `fullHeight` |
231
- | Rating | `getRatingClasses` | — | `sm` `md` `lg` | `interactive` `disabled` `loading` `pill` `fullWidth` |
232
- | Testimonial | `getTestimonialClasses` | `elevated` `flat` `outline` `ghost` | — | `interactive` `disabled` `loading` `fullHeight` |
233
- | Alert | `getAlertClasses` | `info` `success` `warning` `danger` `neutral` | `sm` `md` `lg` | `dismissed` |
234
- | Avatar | `getAvatarClasses` | — | `sm` `md` `lg` `xl` | shape: `circle` `square` |
235
- | Tag | `getTagClasses` | `default` `primary` `secondary` `success` `warning` `danger` `info` `neutral` `accent` `cta` `outline` `ghost` | `sm` `md` `lg` | `dismissible` `selected` `disabled` `loading` `interactive` `fullWidth` |
236
- | Spinner | `getSpinnerClasses` | — | `sm` `md` `lg` | — |
225
+ | Recipe | Function | Variants | Sizes | Common boolean flags |
226
+ | ----------- | ----------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------------------- |
227
+ | Button | `getButtonClasses` | `primary` `secondary` `ghost` `danger` `success` `cta` `accent` | `sm` `md` `lg` | `disabled` `loading` `fullWidth` `pill` `iconOnly` |
228
+ | Badge | `getBadgeClasses` | `primary` `secondary` `success` `warning` `danger` `neutral` `info` `ghost` `accent` `cta` | `sm` `md` `lg` | `interactive` `disabled` `loading` `fullWidth` |
229
+ | Card | `getCardClasses` | `elevated` `flat` `outline` `ghost` | — | `interactive` `padded` `fullHeight` `disabled` `loading` |
230
+ | Input | `getInputClasses` | — | `sm` `md` `lg` | `disabled` `loading` `fullWidth` `pill` |
231
+ | Input state | `getInputClasses` | `state`: `default` `error` `success` `disabled` `loading` | — | — |
232
+ | IconBox | `getIconBoxClasses` | `primary` `secondary` `success` `warning` `danger` `info` `neutral` `ghost` `accent` `cta` | `sm` `md` `lg` | `interactive` `disabled` `loading` `pill` `fullWidth` |
233
+ | PricingCard | `getPricingCardClasses` | — | — | `featured` `interactive` `disabled` `loading` `fullHeight` |
234
+ | Rating | `getRatingClasses` | — | `sm` `md` `lg` | `interactive` `disabled` `loading` `pill` `fullWidth` |
235
+ | Testimonial | `getTestimonialClasses` | `elevated` `flat` `outline` `ghost` | — | `interactive` `disabled` `loading` `fullHeight` |
236
+ | Alert | `getAlertClasses` | `info` `success` `warning` `danger` `neutral` | `sm` `md` `lg` | `dismissed` |
237
+ | Avatar | `getAvatarClasses` | — | `sm` `md` `lg` `xl` | shape: `circle` `square` |
238
+ | Tag | `getTagClasses` | `default` `primary` `secondary` `success` `warning` `danger` `info` `neutral` `accent` `cta` `outline` `ghost` | `sm` `md` `lg` | `dismissible` `selected` `disabled` `loading` `interactive` `fullWidth` |
239
+ | Spinner | `getSpinnerClasses` | — | `sm` `md` `lg` | — |
240
+ | Nav | `getNavClasses` | — | — | `bordered` `sticky` `fullWidth` |
241
+ | Toast | `getToastClasses` | `info` `success` `warning` `danger` | — | `dismissed` `fullWidth` |
242
+ | Tooltip | `getTooltipClasses` | placement: `top` `bottom` `left` `right` | — | `visible` |
243
+ | Dropdown | `getDropdownClasses` | menu placement: `bottom-start` `bottom-end` `top-start` `top-end` | — | `fullWidth`, item: `active` `disabled` |
244
+ | Modal | `getModalClasses` | — | — | `open` `fullWidth` |
237
245
 
238
246
  Each recipe family also exports sub-element helpers for its structural parts
239
247
  (labels, wrappers, sub-containers, text elements). See the full list below.
@@ -258,20 +266,30 @@ Root recipe functions:
258
266
  - `getBadgeClasses`
259
267
  - `getButtonClasses`
260
268
  - `getCardClasses`
269
+ - `getDropdownClasses`
261
270
  - `getIconBoxClasses`
262
271
  - `getInputClasses`
272
+ - `getModalClasses`
273
+ - `getNavClasses`
263
274
  - `getPricingCardClasses`
264
275
  - `getRatingClasses`
265
276
  - `getSpinnerClasses`
266
277
  - `getTagClasses`
267
278
  - `getTestimonialClasses`
279
+ - `getToastClasses`
280
+ - `getTooltipClasses`
268
281
 
269
282
  Root recipe helper functions:
270
283
 
284
+ - `getDropdownItemClasses`
285
+ - `getDropdownMenuClasses`
271
286
  - `getInputErrorMessageClasses`
272
287
  - `getInputHelperTextClasses`
273
288
  - `getInputLabelClasses`
274
289
  - `getInputWrapperClasses`
290
+ - `getModalOverlayClasses`
291
+ - `getNavLinkClasses`
292
+ - `getNavLinksClasses`
275
293
  - `getPricingCardBadgeClasses`
276
294
  - `getPricingCardDescriptionClasses`
277
295
  - `getPricingCardPriceClasses`
@@ -284,6 +302,7 @@ Root recipe helper functions:
284
302
  - `getTestimonialAuthorNameClasses`
285
303
  - `getTestimonialAuthorTitleClasses`
286
304
  - `getTestimonialQuoteClasses`
305
+ - `getToastIconClasses`
287
306
 
288
307
  The root package also re-exports the related recipe option, variant, size, and
289
308
  state TypeScript types defined by those recipes.
@@ -344,8 +363,8 @@ Practical guidance:
344
363
 
345
364
  - additive recipes, variants, states, and helpers are intended to be safe for
346
365
  existing consumers
347
- - semantic shifts may keep the same class or option name but still affect
348
- visual output
366
+ - semantic shifts may keep the same class or option name but still affect visual
367
+ output
349
368
  - renames, removals, and behavior changes to existing classes or options are
350
369
  breaking
351
370
  - generated JS, TypeScript declarations, CSS bundles, Tailwind exports, README
@@ -363,11 +382,11 @@ Tailwind helper:
363
382
  Contract-affecting changes should be classified in `CHANGELOG.md [Unreleased]`
364
383
  before release.
365
384
 
366
- | Classification | When to use | Examples |
367
- |---|---|---|
368
- | `additive` | New public styling surface that does not break existing consumers | Adding a recipe helper, variant, state, or CSS entry point |
369
- | `semantic change` | Public name remains but behavior or visual meaning shifts | Adjusting an existing class or recipe option to map to different token intent |
370
- | `breaking` | Existing consumers may need code changes | Renaming or removing a class, option, export, or CSS entry point |
385
+ | Classification | When to use | Examples |
386
+ | ----------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------- |
387
+ | `additive` | New public styling surface that does not break existing consumers | Adding a recipe helper, variant, state, or CSS entry point |
388
+ | `semantic change` | Public name remains but behavior or visual meaning shifts | Adjusting an existing class or recipe option to map to different token intent |
389
+ | `breaking` | Existing consumers may need code changes | Renaming or removing a class, option, export, or CSS entry point |
371
390
 
372
391
  Renames and removals are always breaking regardless of perceived scope.
373
392
 
@@ -413,28 +432,28 @@ npm install
413
432
  npm run ci:verify
414
433
  ```
415
434
 
416
- This project requires Node.js `^22.13.0 || >=24.0.0` and npm `>=10.0.0`.
417
- The checked-in package manager is `npm@11.15.0`.
435
+ This project requires Node.js `^22.13.0 || >=24.0.0` and npm `>=10.0.0`. The
436
+ checked-in package manager is `npm@11.16.0`.
418
437
 
419
438
  ### Common commands
420
439
 
421
- | Command | What it does |
422
- |---|---|
423
- | `npm run check` | Full validation gate — run before every PR |
424
- | `npm run ci:verify` | Underlying verification sequence used by `npm run check` |
425
- | `npm test` | Build then run the contract and regression test suite |
426
- | `npm run build` | Emit TypeScript and CSS artifacts to `dist/` |
427
- | `npm run lint` | ESLint with TypeScript-aware config |
428
- | `npm run validate:exports` | Verify root export surface against snapshot |
429
- | `npm run validate:exports:update` | Update the export snapshot after adding a public export |
430
- | `npm run validate:tailwind` | Verify Tailwind exports and emitted subpath artifacts |
431
- | `npm run validate:tailwind:update` | Update the Tailwind export snapshot |
432
- | `npm run validate:tokens` | Check for token drift against latest published release |
440
+ | Command | What it does |
441
+ | ---------------------------------- | -------------------------------------------------------- |
442
+ | `npm run check` | Full validation gate — run before every PR |
443
+ | `npm run ci:verify` | Underlying verification sequence used by `npm run check` |
444
+ | `npm test` | Build then run the contract and regression test suite |
445
+ | `npm run build` | Emit TypeScript and CSS artifacts to `dist/` |
446
+ | `npm run lint` | ESLint with TypeScript-aware config |
447
+ | `npm run validate:exports` | Verify root export surface against snapshot |
448
+ | `npm run validate:exports:update` | Update the export snapshot after adding a public export |
449
+ | `npm run validate:tailwind` | Verify Tailwind exports and emitted subpath artifacts |
450
+ | `npm run validate:tailwind:update` | Update the Tailwind export snapshot |
451
+ | `npm run validate:tokens` | Check for token drift against latest published release |
433
452
 
434
453
  ### Troubleshooting
435
454
 
436
- **`validate:runtime` fails** — you are on the wrong Node version. Run
437
- `nvm use` to switch to the version in `.nvmrc`, or install Node 22 or 24.
455
+ **`validate:runtime` fails** — you are on the wrong Node version. Run `nvm use`
456
+ to switch to the version in `.nvmrc`, or install Node 22 or 24.
438
457
 
439
458
  **`validate:tokens` fails with a network error** — the check requires outbound
440
459
  npm registry access. In a restricted environment, run the other validators
@@ -445,8 +464,8 @@ automatically via the `pretest` hook. If you ran `vitest` directly, run
445
464
  `npm run build` first.
446
465
 
447
466
  **Lint fails locally but passes in CI** — confirm you are on the same Node
448
- version as CI (Node 22.x or 24.x). ESLint plugin resolution can differ
449
- across runtimes.
467
+ version as CI (Node 22.x or 24.x). ESLint plugin resolution can differ across
468
+ runtimes.
450
469
 
451
470
  **Export snapshot out of date** — run `npm run validate:exports:update` after
452
471
  adding a public export, then commit the updated `scripts/export-snapshot.json`.
@@ -462,6 +481,13 @@ adding a public export, then commit the updated `scripts/export-snapshot.json`.
462
481
  Planning artifacts for contract hardening live in [ROADMAP.md](ROADMAP.md) and
463
482
  [TODO.md](TODO.md).
464
483
 
484
+ The current roadmap focus is post-v1.7.0 expansion: consume newly published
485
+ Spectre token contracts for links, interactive surfaces, dividers, and common
486
+ application UI patterns before adding matching Layer 2 classes or recipes.
487
+ Planned upstream token work is tracked in
488
+ [`@phcdevworks/spectre-tokens`](https://github.com/phcdevworks/spectre-tokens),
489
+ but this package synchronizes only against published npm releases.
490
+
465
491
  ## Examples
466
492
 
467
493
  Use [`examples/examples.html`](examples/examples.html) as the visual index for
@@ -481,16 +507,16 @@ Run the full validation gate before any pull request:
481
507
  npm run check
482
508
  ```
483
509
 
484
- This runs: runtime check → lint → export validation → README validation →
485
- token drift check → build → Tailwind contract → CSS contract → tests. All
486
- steps must pass.
510
+ This runs: runtime check → lint → changelog validation → export validation →
511
+ README validation → token drift check → build → Tailwind contract → CSS contract
512
+ → tests. All steps must pass.
487
513
 
488
514
  ## AI and automation boundaries
489
515
 
490
516
  Claude Code (`claude-sonnet-4-6`) is the primary development agent for this
491
517
  repository. Codex handles releases and production stabilization. Jules handles
492
- small automated fixes and token sync passes. GitHub Copilot provides
493
- development support.
518
+ small automated fixes and token sync passes. GitHub Copilot provides development
519
+ support.
494
520
 
495
521
  Claude Code, Codex, and Copilot do not create git commits by default. Jules may
496
522
  commit only bounded automated maintenance when the `JULES.md` scope and
package/dist/base.css CHANGED
@@ -37,6 +37,41 @@
37
37
  --sp-icon-box-icon-success: #16a34a;
38
38
  --sp-icon-box-icon-warning: #d48806;
39
39
  --sp-icon-box-icon-danger: #dc2626;
40
+ --sp-nav-bg: #ffffff;
41
+ --sp-nav-text: #141b24;
42
+ --sp-nav-link: #374253;
43
+ --sp-nav-link-hover: #1f57db;
44
+ --sp-nav-link-active: #1946b4;
45
+ --sp-nav-border: #d9dfeb;
46
+ --sp-modal-bg: #ffffff;
47
+ --sp-modal-shadow: 0 20px 48px -12px rgba(0, 0, 0, 0.20);
48
+ --sp-modal-border: #d9dfeb;
49
+ --sp-modal-overlay: rgba(0, 0, 0, 0.6);
50
+ --sp-toast-success-bg: #f0fdf4;
51
+ --sp-toast-success-text: #166534;
52
+ --sp-toast-success-border: #bbf7d0;
53
+ --sp-toast-success-icon: #16a34a;
54
+ --sp-toast-warning-bg: #fffbea;
55
+ --sp-toast-warning-text: #8f5200;
56
+ --sp-toast-warning-border: #ffe08a;
57
+ --sp-toast-warning-icon: #d48806;
58
+ --sp-toast-danger-bg: #fef2f2;
59
+ --sp-toast-danger-text: #991b1b;
60
+ --sp-toast-danger-border: #fecaca;
61
+ --sp-toast-danger-icon: #dc2626;
62
+ --sp-toast-info-bg: #f0f9ff;
63
+ --sp-toast-info-text: #0c4a6e;
64
+ --sp-toast-info-border: #bae6fd;
65
+ --sp-toast-info-icon: #0369a1;
66
+ --sp-tooltip-bg: #141b24;
67
+ --sp-tooltip-text: #ffffff;
68
+ --sp-tooltip-border: #374253;
69
+ --sp-dropdown-bg: #ffffff;
70
+ --sp-dropdown-border: #d9dfeb;
71
+ --sp-dropdown-item-default: transparent;
72
+ --sp-dropdown-item-hover: #eef1f6;
73
+ --sp-dropdown-item-active: #f0f9ff;
74
+ --sp-dropdown-item-text: #141b24;
40
75
  --sp-color-brand-50: #eef4ff;
41
76
  --sp-color-brand-100: #d9e7ff;
42
77
  --sp-color-brand-200: #b9d2ff;
@@ -116,17 +151,24 @@
116
151
  --sp-color-white: #ffffff;
117
152
  --sp-color-black: #000000;
118
153
  --sp-space-0: 0rem;
154
+ --sp-space-1: 0.0625rem;
155
+ --sp-space-2: 0.125rem;
119
156
  --sp-space-4: 0.25rem;
157
+ --sp-space-6: 0.375rem;
120
158
  --sp-space-8: 0.5rem;
159
+ --sp-space-10: 0.625rem;
121
160
  --sp-space-12: 0.75rem;
161
+ --sp-space-14: 0.875rem;
122
162
  --sp-space-16: 1rem;
123
163
  --sp-space-20: 1.25rem;
124
164
  --sp-space-24: 1.5rem;
165
+ --sp-space-28: 1.75rem;
125
166
  --sp-space-32: 2rem;
126
167
  --sp-space-40: 2.5rem;
127
168
  --sp-space-48: 3rem;
128
169
  --sp-space-56: 3.5rem;
129
170
  --sp-space-64: 4rem;
171
+ --sp-space-72: 4.5rem;
130
172
  --sp-space-80: 5rem;
131
173
  --sp-space-96: 6rem;
132
174
  --sp-layout-section-padding-sm: 1.5rem;
@@ -142,16 +184,21 @@
142
184
  --sp-layout-container-padding-inline-md: 1.5rem;
143
185
  --sp-layout-container-padding-inline-lg: 2rem;
144
186
  --sp-layout-container-max-width: 72rem;
187
+ --sp-border-width-none: 0;
145
188
  --sp-border-width-base: 1px;
146
189
  --sp-border-width-thick: 2px;
147
190
  --sp-border-style-none: none;
148
191
  --sp-border-style-solid: solid;
192
+ --sp-border-style-dashed: dashed;
193
+ --sp-border-style-dotted: dotted;
149
194
  --sp-radius-none: 0;
150
195
  --sp-radius-sm: 2px;
151
196
  --sp-radius-md: 4px;
152
197
  --sp-radius-lg: 8px;
153
198
  --sp-radius-xl: 12px;
154
199
  --sp-radius-2xl: 16px;
200
+ --sp-radius-3xl: 24px;
201
+ --sp-radius-4xl: 32px;
155
202
  --sp-radius-pill: 999px;
156
203
  --sp-font-family-sans: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
157
204
  --sp-font-family-serif: 'Times New Roman', Times, serif;
@@ -216,6 +263,7 @@
216
263
  --sp-z-index-popover: 1500;
217
264
  --sp-z-index-tooltip: 1600;
218
265
  --sp-z-index-toast: 1700;
266
+ --sp-duration-reduced: 0.01ms;
219
267
  --sp-duration-instant: 75ms;
220
268
  --sp-duration-fast: 150ms;
221
269
  --sp-duration-base: 200ms;
@@ -243,6 +291,7 @@
243
291
  --sp-focus-ring-style: solid;
244
292
  --sp-min-touch-target: 44px;
245
293
  --sp-min-text-size: 16px;
294
+ --sp-reduced-motion: 0.01ms;
246
295
  --sp-button-primary-bg: #0369a1;
247
296
  --sp-button-primary-bghover: #075985;
248
297
  --sp-button-primary-bgactive: #0c4a6e;
@@ -276,6 +325,7 @@
276
325
  --sp-button-danger-text: #ffffff;
277
326
  --sp-button-danger-textdisabled: #8a96ad;
278
327
  --sp-button-danger-focusring: rgba(239, 68, 68, 0.4);
328
+ --sp-button-danger-focusvisible: rgba(239, 68, 68, 0.4);
279
329
  --sp-button-success-bg: #15803d;
280
330
  --sp-button-success-bghover: #166534;
281
331
  --sp-button-success-bgactive: #14532d;
@@ -283,6 +333,7 @@
283
333
  --sp-button-success-text: #ffffff;
284
334
  --sp-button-success-textdisabled: #8a96ad;
285
335
  --sp-button-success-focusring: rgba(34, 197, 94, 0.4);
336
+ --sp-button-success-focusvisible: rgba(34, 197, 94, 0.4);
286
337
  --sp-button-cta-bg: #1f57db;
287
338
  --sp-button-cta-bghover: #1946b4;
288
339
  --sp-button-cta-bgactive: #173b8f;
@@ -341,6 +392,30 @@
341
392
  --sp-animation-pulse-duration: 1200ms;
342
393
  --sp-animation-pulse-easing: cubic-bezier(0.4, 0, 0.2, 1);
343
394
  --sp-animation-pulse-keyframes: pulse;
395
+ --sp-animation-reduced-motion-fadein-duration: 0.01ms;
396
+ --sp-animation-reduced-motion-fadein-easing: linear;
397
+ --sp-animation-reduced-motion-fadein-keyframes: fade-in;
398
+ --sp-animation-reduced-motion-fadeout-duration: 0.01ms;
399
+ --sp-animation-reduced-motion-fadeout-easing: linear;
400
+ --sp-animation-reduced-motion-fadeout-keyframes: fade-out;
401
+ --sp-animation-reduced-motion-slideup-duration: 0.01ms;
402
+ --sp-animation-reduced-motion-slideup-easing: linear;
403
+ --sp-animation-reduced-motion-slideup-keyframes: slide-up;
404
+ --sp-animation-reduced-motion-slidedown-duration: 0.01ms;
405
+ --sp-animation-reduced-motion-slidedown-easing: linear;
406
+ --sp-animation-reduced-motion-slidedown-keyframes: slide-down;
407
+ --sp-animation-reduced-motion-scalein-duration: 0.01ms;
408
+ --sp-animation-reduced-motion-scalein-easing: linear;
409
+ --sp-animation-reduced-motion-scalein-keyframes: scale-in;
410
+ --sp-animation-reduced-motion-bounce-duration: 0.01ms;
411
+ --sp-animation-reduced-motion-bounce-easing: linear;
412
+ --sp-animation-reduced-motion-bounce-keyframes: bounce;
413
+ --sp-animation-reduced-motion-shake-duration: 0.01ms;
414
+ --sp-animation-reduced-motion-shake-easing: linear;
415
+ --sp-animation-reduced-motion-shake-keyframes: shake;
416
+ --sp-animation-reduced-motion-pulse-duration: 0.01ms;
417
+ --sp-animation-reduced-motion-pulse-easing: linear;
418
+ --sp-animation-reduced-motion-pulse-keyframes: pulse;
344
419
  }
345
420
  :root[data-spectre-theme="dark"] {
346
421
  --sp-surface-page: #141b24;
@@ -381,6 +456,41 @@
381
456
  --sp-icon-box-icon-success: #4ade80;
382
457
  --sp-icon-box-icon-warning: #ffc21a;
383
458
  --sp-icon-box-icon-danger: #f87171;
459
+ --sp-nav-bg: #141b24;
460
+ --sp-nav-text: #f7f8fb;
461
+ --sp-nav-link: #b7c1d4;
462
+ --sp-nav-link-hover: #5a92ff;
463
+ --sp-nav-link-active: #8ab6ff;
464
+ --sp-nav-border: #374253;
465
+ --sp-modal-bg: #222b38;
466
+ --sp-modal-shadow: 0 20px 48px -12px rgba(0, 0, 0, 0.20);
467
+ --sp-modal-border: #374253;
468
+ --sp-modal-overlay: rgba(0, 0, 0, 0.6);
469
+ --sp-toast-success-bg: #14532d;
470
+ --sp-toast-success-text: #dcfce7;
471
+ --sp-toast-success-border: #15803d;
472
+ --sp-toast-success-icon: #4ade80;
473
+ --sp-toast-warning-bg: #734000;
474
+ --sp-toast-warning-text: #fff1c2;
475
+ --sp-toast-warning-border: #ad6800;
476
+ --sp-toast-warning-icon: #ffc21a;
477
+ --sp-toast-danger-bg: #7f1d1d;
478
+ --sp-toast-danger-text: #fee2e2;
479
+ --sp-toast-danger-border: #b91c1c;
480
+ --sp-toast-danger-icon: #f87171;
481
+ --sp-toast-info-bg: #082f49;
482
+ --sp-toast-info-text: #e0f2fe;
483
+ --sp-toast-info-border: #075985;
484
+ --sp-toast-info-icon: #38bdf8;
485
+ --sp-tooltip-bg: #f7f8fb;
486
+ --sp-tooltip-text: #141b24;
487
+ --sp-tooltip-border: #b7c1d4;
488
+ --sp-dropdown-bg: #222b38;
489
+ --sp-dropdown-border: #374253;
490
+ --sp-dropdown-item-default: transparent;
491
+ --sp-dropdown-item-hover: #374253;
492
+ --sp-dropdown-item-active: #082f49;
493
+ --sp-dropdown-item-text: #eef1f6;
384
494
  }
385
495
  @layer base {
386
496