@phcdevworks/spectre-ui 1.4.0 → 1.6.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/README.md CHANGED
@@ -1,21 +1,77 @@
1
1
  # @phcdevworks/spectre-ui
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@phcdevworks/spectre-ui)](https://www.npmjs.com/package/@phcdevworks/spectre-ui)
4
+ [![CI](https://github.com/phcdevworks/spectre-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/phcdevworks/spectre-ui/actions/workflows/ci.yml)
3
5
  [![GitHub issues](https://img.shields.io/github/issues/phcdevworks/spectre-ui)](https://github.com/phcdevworks/spectre-ui/issues)
4
- [![GitHub pull requests](https://img.shields.io/github/issues-pr/phcdevworks/spectre-ui)](https://github.com/phcdevworks/spectre-ui/pulls)
5
6
  [![License](https://img.shields.io/github/license/phcdevworks/spectre-ui)](LICENSE)
6
7
 
7
- `@phcdevworks/spectre-ui` is the implementation layer between
8
+ `@phcdevworks/spectre-ui` is **Layer 2 of the Spectre design suite**. It turns
8
9
  [`@phcdevworks/spectre-tokens`](https://github.com/phcdevworks/spectre-tokens)
9
- and downstream adapters or apps.
10
+ into reusable CSS bundles, Tailwind tooling, and type-safe class recipes for
11
+ downstream adapters and apps.
10
12
 
11
- Maintained by PHCDevworks, it turns Spectre tokens into reusable CSS bundles,
12
- Tailwind tooling, and type-safe class recipes. It is framework-agnostic,
13
- token-driven, and follows a strict zero-hex policy so visual values do not drift
14
- locally.
13
+ **For:** adapter authors and app developers who need a stable, token-driven
14
+ styling contract without re-implementing class logic themselves.
15
+
16
+ **Not for:** authoring design tokens (that belongs in
17
+ `@phcdevworks/spectre-tokens`) or building framework-specific components (that
18
+ belongs in adapter packages such as `@phcdevworks/spectre-ui-astro`).
15
19
 
16
20
  [Contributing](CONTRIBUTING.md) | [Changelog](CHANGELOG.md) |
17
21
  [Security Policy](SECURITY.md)
18
22
 
23
+ ## Source of truth
24
+
25
+ `@phcdevworks/spectre-tokens` is the source of truth for visual values and
26
+ semantic meaning. `ui-contract.manifest.json` is the machine-readable contract
27
+ authority for this package's public styling surface.
28
+
29
+ | Layer | Path | Rule |
30
+ |---|---|---|
31
+ | Token authority | Published `@phcdevworks/spectre-tokens` package | Design values and semantic meaning start there |
32
+ | UI contract authority | `ui-contract.manifest.json` | Governs public recipes, CSS entry points, and Tailwind exports |
33
+ | Source CSS | `src/styles/` | Token-backed CSS classes and bundle entry points |
34
+ | Source recipes | `src/recipes/` | Framework-agnostic class string APIs |
35
+ | Tailwind helpers | `src/tailwind/` | Tailwind theme and preset integration |
36
+ | Generated dist | `dist/` | **Never edit directly** — regenerated by `npm run build` |
37
+
38
+ After any contract-facing source change: run `npm run check` to validate the
39
+ full UI contract.
40
+
41
+ ## Architecture
42
+
43
+ ```
44
+ ┌─────────────────────────────┐
45
+ │ @phcdevworks/spectre-tokens │ Layer 1 — design values, semantic tokens
46
+ │ (design source of truth) │
47
+ └──────────────┬──────────────┘
48
+ │ consumed by
49
+
50
+ ┌─────────────────────────────┐
51
+ │ @phcdevworks/spectre-ui │ Layer 2 — THIS PACKAGE
52
+ │ CSS bundles, recipes, │ translates tokens into structure
53
+ │ Tailwind helpers │
54
+ └──────────────┬──────────────┘
55
+ │ consumed by
56
+
57
+ ┌─────────────────────────────┐
58
+ │ @phcdevworks/spectre- │ Layer 3 — canonical Lit web components
59
+ │ components │ wraps CSS classes and recipes as
60
+ │ │ framework-agnostic custom elements
61
+ └──────────────┬──────────────┘
62
+ │ alongside / consumed by
63
+
64
+ ┌─────────────────────────────┐
65
+ │ Adapters and apps │ Layer 4 — framework-specific delivery
66
+ │ spectre-ui-astro, React, │ binds Spectre contracts to native
67
+ │ Vue, WordPress, etc. │ framework ergonomics
68
+ └─────────────────────────────┘
69
+ ```
70
+
71
+ This package owns Layer 2 only. It does not deliver components and it does not
72
+ define tokens. It translates tokens into a stable contract that adapters and
73
+ apps consume.
74
+
19
75
  ## Key capabilities
20
76
 
21
77
  - Ships precompiled CSS: `index.css`, `base.css`, `components.css`, and
@@ -28,6 +84,27 @@ locally.
28
84
  - Enforces a zero-hex approach so visual values stay tied to
29
85
  `@phcdevworks/spectre-tokens`
30
86
 
87
+ ## What this package owns
88
+
89
+ - Token-backed CSS class contracts in `src/styles/`
90
+ - Precompiled CSS bundles for root, base, components, and utilities
91
+ - Framework-agnostic class recipe functions in `src/recipes/`
92
+ - Tailwind preset and theme helpers in `src/tailwind/`
93
+ - Contract validation that keeps CSS, recipes, exports, and docs aligned
94
+
95
+ This package is the correct place to define reusable styling structure on top
96
+ of Spectre tokens.
97
+
98
+ ## What this package does not own
99
+
100
+ - Design token values or semantic visual meaning. Those belong in
101
+ [`@phcdevworks/spectre-tokens`](https://github.com/phcdevworks/spectre-tokens).
102
+ - Framework components, templates, hooks, or runtime behavior. Those belong in
103
+ adapter packages.
104
+ - App-level layout, routing, data fetching, or product-specific composition.
105
+ - Local redefinition of token meaning. Downstream consumers should consume the
106
+ token contract rather than recreate it.
107
+
31
108
  ## Installation
32
109
 
33
110
  ```bash
@@ -36,7 +113,34 @@ npm install @phcdevworks/spectre-ui
36
113
 
37
114
  ## Quick start
38
115
 
39
- ### CSS import
116
+ ### Vanilla HTML — CSS classes only
117
+
118
+ No framework needed. Import the CSS and use the `sp-*` classes directly:
119
+
120
+ ```html
121
+ <!doctype html>
122
+ <html>
123
+ <head>
124
+ <link rel="stylesheet" href="node_modules/@phcdevworks/spectre-ui/dist/index.css" />
125
+ </head>
126
+ <body>
127
+ <button class="sp-btn sp-btn--primary sp-btn--md">Save</button>
128
+ <button class="sp-btn sp-btn--ghost sp-btn--md">Cancel</button>
129
+ <span class="sp-badge sp-badge--success sp-badge--sm">Published</span>
130
+
131
+ <div class="sp-card sp-card--elevated">
132
+ <p>Card content</p>
133
+ </div>
134
+
135
+ <div class="sp-input-wrapper">
136
+ <label class="sp-label">Email</label>
137
+ <input class="sp-input sp-input--md" type="email" />
138
+ </div>
139
+ </body>
140
+ </html>
141
+ ```
142
+
143
+ ### CSS import (bundler or framework)
40
144
 
41
145
  Import the full stylesheet:
42
146
 
@@ -87,31 +191,74 @@ const badge = getBadgeClasses({ variant: 'success', size: 'sm' })
87
191
  const pricingCard = getPricingCardClasses({ featured: true })
88
192
  ```
89
193
 
90
- ## What this package owns
194
+ ## When to use this package
91
195
 
92
- - Token-driven CSS implementation
93
- - Precompiled CSS bundles and utility classes
94
- - Tailwind helpers and preset generation
95
- - Type-safe class recipes for shared UI contracts
96
- - Stable styling behavior consumed by downstream adapters and apps
196
+ Use `@phcdevworks/spectre-ui` when you need:
97
197
 
98
- Golden rule: consume tokens, do not redefine them.
198
+ - precompiled, token-backed CSS ready to drop into any framework
199
+ - a Tailwind preset or theme helper built from Spectre tokens
200
+ - stable, type-safe class recipes for shared UI patterns (buttons, badges,
201
+ cards, inputs, etc.) that you want to remain consistent across frameworks
202
+ - a styling contract that is enforced through tests and CI rather than
203
+ conventions alone
99
204
 
100
- ## What this package does not own
205
+ ## When not to use this package
206
+
207
+ Do not use `@phcdevworks/spectre-ui` when you need to:
208
+
209
+ - **Define new design values** — add them to
210
+ [`@phcdevworks/spectre-tokens`](https://github.com/phcdevworks/spectre-tokens)
211
+ instead.
212
+ - **Deliver framework components** — use an adapter package such as
213
+ `@phcdevworks/spectre-ui-astro` that wraps this package in framework-native
214
+ components.
215
+ - **Use raw Tailwind utilities without a shared recipe contract** — import
216
+ Tailwind directly and use the Spectre preset; you do not need this package's
217
+ recipe layer if you are building one-off UI with utility classes.
101
218
 
102
- - Design values or semantic meaning That belongs to
103
- `@phcdevworks/spectre-tokens`.
104
- - Framework-specific component delivery Adapters and apps consume
105
- `@phcdevworks/spectre-ui`; they do not recreate its styling logic.
106
- - Local visual values outside the token contract Hardcoded hex, spacing, or
107
- shadow values are drift unless clearly intentional and documented.
219
+ ## What belongs here vs elsewhere
220
+
221
+ | What | Where it lives |
222
+ |---|---|
223
+ | Semantic color values, spacing scale, type scale | `@phcdevworks/spectre-tokens` |
224
+ | Token-to-CSS variable mapping | **here** `src/styles/` |
225
+ | Precompiled CSS bundles | **here** — built to `dist/*.css` |
226
+ | Class recipe functions (input → class string) | **here** — `src/recipes/` |
227
+ | Tailwind preset and theme helpers | **here** — `src/tailwind/` |
228
+ | Astro, React, Vue, Lit, Svelte components | Adapter packages (e.g. `spectre-ui-astro`) |
229
+ | WordPress shortcodes or PHP templates | A WordPress adapter package |
230
+ | App-level layout, routing, or data fetching | Consuming apps |
231
+ | New design decisions (new colors, new spacing) | `@phcdevworks/spectre-tokens` |
232
+
233
+ Golden rule: this package consumes tokens and exposes class contracts. It does
234
+ not define tokens and it does not deliver framework components.
108
235
 
109
236
  ## Package exports / API surface
110
237
 
238
+ ### Recipe quick reference
239
+
240
+ All recipe functions accept a plain options object and return a class string.
241
+ All options are optional and fall back to sensible defaults.
242
+
243
+ | Recipe | Function | Variants | Sizes | Common boolean flags |
244
+ |---|---|---|---|---|
245
+ | Button | `getButtonClasses` | `primary` `secondary` `ghost` `danger` `success` `cta` `accent` | `sm` `md` `lg` | `disabled` `loading` `fullWidth` `pill` `iconOnly` |
246
+ | Badge | `getBadgeClasses` | `primary` `secondary` `success` `warning` `danger` `neutral` `info` `ghost` `accent` `cta` | `sm` `md` `lg` | `interactive` `disabled` `loading` `fullWidth` |
247
+ | Card | `getCardClasses` | `elevated` `flat` `outline` `ghost` | — | `interactive` `padded` `fullHeight` `disabled` `loading` |
248
+ | Input | `getInputClasses` | — | `sm` `md` `lg` | `disabled` `loading` `fullWidth` `pill` |
249
+ | Input state | `getInputClasses` | `state`: `default` `error` `success` `disabled` `loading` | — | — |
250
+ | IconBox | `getIconBoxClasses` | `primary` `secondary` `success` `warning` `danger` `info` `neutral` `ghost` `accent` `cta` | `sm` `md` `lg` | `interactive` `disabled` `loading` `pill` `fullWidth` |
251
+ | PricingCard | `getPricingCardClasses` | — | — | `featured` `interactive` `disabled` `loading` `fullHeight` |
252
+ | Rating | `getRatingClasses` | — | `sm` `md` `lg` | `interactive` `disabled` `loading` `pill` `fullWidth` |
253
+ | Testimonial | `getTestimonialClasses` | `elevated` `flat` `outline` `ghost` | — | `interactive` `disabled` `loading` `fullHeight` |
254
+
255
+ Each recipe family also exports sub-element helpers for its structural parts
256
+ (labels, wrappers, sub-containers, text elements). See the full list below.
257
+
111
258
  ### Root package
112
259
 
113
- The root package exports CSS path constants plus the recipe functions re-exported
114
- from `src/recipes/index.ts`.
260
+ The root package exports CSS path constants plus the recipe functions
261
+ re-exported from `src/recipes/index.ts`.
115
262
 
116
263
  Root constants:
117
264
 
@@ -134,6 +281,10 @@ Root recipe functions:
134
281
 
135
282
  Root recipe helper functions:
136
283
 
284
+ - `getInputErrorMessageClasses`
285
+ - `getInputHelperTextClasses`
286
+ - `getInputLabelClasses`
287
+ - `getInputWrapperClasses`
137
288
  - `getPricingCardBadgeClasses`
138
289
  - `getPricingCardDescriptionClasses`
139
290
  - `getPricingCardPriceClasses`
@@ -164,6 +315,75 @@ state TypeScript types defined by those recipes.
164
315
  - `@phcdevworks/spectre-ui/components.css`
165
316
  - `@phcdevworks/spectre-ui/utilities.css`
166
317
 
318
+ ## Public contract guarantees
319
+
320
+ `ui-contract.manifest.json` defines the public styling contract for this
321
+ package.
322
+
323
+ It covers:
324
+
325
+ - CSS entry points
326
+ - root package constants and recipe function exports
327
+ - Tailwind subpath exports
328
+ - recipe families, variants, sizes, and public states
329
+
330
+ Every contract-facing surface must match that manifest. Validation fails when
331
+ README documentation omits manifest-declared exports, when export snapshots
332
+ drift, when Tailwind artifacts drift, or when CSS contract coverage no longer
333
+ matches the declared surface.
334
+
335
+ ## Downstream boundaries
336
+
337
+ Downstream packages should never redefine locally:
338
+
339
+ - Spectre design token meaning
340
+ - CSS class semantics already provided by this package
341
+ - recipe option names, variants, sizes, or states
342
+ - package CSS entry point behavior
343
+ - Tailwind helper export names
344
+
345
+ Downstream packages may:
346
+
347
+ - compose application UI with the exported classes
348
+ - wrap recipe functions in framework-specific adapters
349
+ - import CSS entry points directly in applications or adapter packages
350
+ - extend app-specific layout around Spectre contracts
351
+
352
+ ## Upgrade expectations for consumers
353
+
354
+ Consumers should treat this package as a SemVer-governed styling contract.
355
+
356
+ Practical guidance:
357
+
358
+ - additive recipes, variants, states, and helpers are intended to be safe for
359
+ existing consumers
360
+ - semantic shifts may keep the same class or option name but still affect
361
+ visual output
362
+ - renames, removals, and behavior changes to existing classes or options are
363
+ breaking
364
+ - generated JS, TypeScript declarations, CSS bundles, Tailwind exports, README
365
+ docs, and `ui-contract.manifest.json` are expected to stay aligned
366
+
367
+ If a downstream package depends on a class, recipe option, CSS entry point, or
368
+ Tailwind helper:
369
+
370
+ - read `CHANGELOG.md` for contract change classification
371
+ - prefer documented public exports over internal paths
372
+ - run consuming app validation after package upgrades
373
+
374
+ ### Change classification
375
+
376
+ Contract-affecting changes should be classified in `CHANGELOG.md [Unreleased]`
377
+ before release.
378
+
379
+ | Classification | When to use | Examples |
380
+ |---|---|---|
381
+ | `additive` | New public styling surface that does not break existing consumers | Adding a recipe helper, variant, state, or CSS entry point |
382
+ | `semantic change` | Public name remains but behavior or visual meaning shifts | Adjusting an existing class or recipe option to map to different token intent |
383
+ | `breaking` | Existing consumers may need code changes | Renaming or removing a class, option, export, or CSS entry point |
384
+
385
+ Renames and removals are always breaking regardless of perceived scope.
386
+
167
387
  ## Relationship to the rest of Spectre
168
388
 
169
389
  Spectre keeps responsibilities separate:
@@ -172,24 +392,79 @@ Spectre keeps responsibilities separate:
172
392
  defines design values and semantic meaning
173
393
  - `@phcdevworks/spectre-ui` turns those tokens into reusable CSS, Tailwind
174
394
  tooling, and type-safe class recipes
395
+ - `@phcdevworks/spectre-components` turns those styling contracts into
396
+ framework-agnostic Lit web components
175
397
  - Adapters and apps consume `@phcdevworks/spectre-ui` instead of re-implementing
176
- its styling layer
398
+ its styling layer, or wrap Spectre component contracts for a specific runtime
177
399
 
178
400
  That separation keeps recipe behavior consistent across frameworks and reduces
179
401
  implementation drift.
180
402
 
403
+ ## Consumer checklist
404
+
405
+ For downstream packages and compatible apps:
406
+
407
+ - import `@phcdevworks/spectre-ui/index.css` for the full styling contract
408
+ - import split CSS entry points only when the consumer needs bundle-level
409
+ control
410
+ - use recipe functions when framework adapters need stable class strings
411
+ - use `@phcdevworks/spectre-ui/tailwind` for Tailwind theme integration
412
+ - consume tokens from `@phcdevworks/spectre-tokens` instead of inventing visual
413
+ values locally
414
+ - treat `dist/` as generated package output, not an authoring surface
415
+ - do not add framework runtime logic to this package
416
+
181
417
  ## Development
182
418
 
183
- Install dependencies, then run the package verification flow:
419
+ ### Local setup
420
+
421
+ ```bash
422
+ git clone https://github.com/phcdevworks/spectre-ui.git
423
+ cd spectre-ui
424
+ nvm use # picks up .nvmrc (Node 22.22.2)
425
+ npm install
426
+ npm run ci:verify
427
+ ```
428
+
429
+ This project requires Node.js `^22.13.0 || >=24.0.0` and npm `>=10.0.0`.
430
+ The checked-in package manager is `npm@11.15.0`.
431
+
432
+ ### Common commands
433
+
434
+ | Command | What it does |
435
+ |---|---|
436
+ | `npm run check` | Full validation gate — run before every PR |
437
+ | `npm run ci:verify` | Underlying verification sequence used by `npm run check` |
438
+ | `npm test` | Build then run the contract and regression test suite |
439
+ | `npm run build` | Emit TypeScript and CSS artifacts to `dist/` |
440
+ | `npm run lint` | ESLint with TypeScript-aware config |
441
+ | `npm run validate:exports` | Verify root export surface against snapshot |
442
+ | `npm run validate:exports:update` | Update the export snapshot after adding a public export |
443
+ | `npm run validate:tailwind` | Verify Tailwind exports and emitted subpath artifacts |
444
+ | `npm run validate:tailwind:update` | Update the Tailwind export snapshot |
445
+ | `npm run validate:tokens` | Check for token drift against latest published release |
446
+
447
+ ### Troubleshooting
184
448
 
185
- npm run ci:verify
449
+ **`validate:runtime` fails** — you are on the wrong Node version. Run
450
+ `nvm use` to switch to the version in `.nvmrc`, or install Node 22 or 24.
186
451
 
187
- Planning artifacts for contract hardening live in:
452
+ **`validate:tokens` fails with a network error** — the check requires outbound
453
+ npm registry access. In a restricted environment, run the other validators
454
+ individually; this step is the only network-dependent one in `ci:verify`.
188
455
 
189
- - [`ROADMAP.md`](ROADMAP.md)
190
- - [`TODO.md`](TODO.md)
456
+ **Tests pass but the build shows stale output** — `npm test` rebuilds
457
+ automatically via the `pretest` hook. If you ran `vitest` directly, run
458
+ `npm run build` first.
191
459
 
192
- Key source areas:
460
+ **Lint fails locally but passes in CI** — confirm you are on the same Node
461
+ version as CI (Node 22.x or 24.x). ESLint plugin resolution can differ
462
+ across runtimes.
463
+
464
+ **Export snapshot out of date** — run `npm run validate:exports:update` after
465
+ adding a public export, then commit the updated `scripts/export-snapshot.json`.
466
+
467
+ ### Key source areas
193
468
 
194
469
  - `src/styles/` for source CSS
195
470
  - `src/recipes/` for class recipes
@@ -197,6 +472,9 @@ Key source areas:
197
472
  - `tests/` for contract and regression coverage
198
473
  - `examples/` for visual demos and verification fixtures
199
474
 
475
+ Planning artifacts for contract hardening live in [ROADMAP.md](ROADMAP.md) and
476
+ [TODO.md](TODO.md).
477
+
200
478
  ## Examples
201
479
 
202
480
  Use [`examples/examples.html`](examples/examples.html) as the visual index for
@@ -208,6 +486,34 @@ Available examples include:
208
486
  - `showroom.html` for a richer marketing-style composition
209
487
  - `verification.html` and focused verification fixtures for regression checks
210
488
 
489
+ ## Validation
490
+
491
+ Run the full validation gate before any pull request:
492
+
493
+ ```bash
494
+ npm run check
495
+ ```
496
+
497
+ This runs: runtime check → lint → export validation → README validation →
498
+ token drift check → build → Tailwind contract → CSS contract → tests. All
499
+ steps must pass.
500
+
501
+ ## AI and automation boundaries
502
+
503
+ Claude Code (`claude-sonnet-4-6`) is the primary development agent for this
504
+ repository. Codex handles releases and production stabilization. Jules handles
505
+ small automated fixes and token sync passes. GitHub Copilot provides
506
+ development support.
507
+
508
+ Claude Code, Codex, and Copilot do not create git commits by default. Jules may
509
+ commit only bounded automated maintenance when the `JULES.md` scope and
510
+ validation gates pass. Release decisions, tags, and publishing remain with
511
+ Bradley Potts.
512
+
513
+ **Protected from automated change:** CSS contracts, recipe public API surface,
514
+ and the zero-hex policy (no hardcoded color/spacing values). See
515
+ [AGENTS.md](AGENTS.md) for full agent governance and boundary rules.
516
+
211
517
  ## Contributing
212
518
 
213
519
  PHCDevworks maintains this package as part of the Spectre suite.
@@ -217,7 +523,7 @@ When contributing:
217
523
  - keep styling token-driven
218
524
  - keep recipe APIs and CSS classes in sync
219
525
  - avoid local visual values unless clearly intentional
220
- - run npm run ci:verify before opening a pull request
526
+ - run `npm run check` before opening a pull request
221
527
 
222
528
  See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow.
223
529
 
package/dist/base.css CHANGED
@@ -2,7 +2,7 @@
2
2
  --sp-surface-page: #f7f8fb;
3
3
  --sp-surface-card: #ffffff;
4
4
  --sp-surface-input: #ffffff;
5
- --sp-surface-overlay: rgba(20, 27, 36, 0.6);
5
+ --sp-surface-overlay: rgba(0, 0, 0, 0.6);
6
6
  --sp-surface-alternate: #eef1f6;
7
7
  --sp-surface-hero: linear-gradient(135deg, #5b6ee1 0%, #6f3fd7 100%);
8
8
  --sp-text-on-page-default: #141b24;
@@ -294,9 +294,9 @@
294
294
  --sp-button-cta-textdisabled: #8a96ad;
295
295
  --sp-button-cta-shadow: 0 4px 14px 0 rgba(51, 109, 244, 0.39);
296
296
  --sp-button-cta-focusring: rgba(51, 109, 244, 0.4);
297
- --sp-button-accent-bg: #7135dd;
298
- --sp-button-accent-bghover: #5d28b8;
299
- --sp-button-accent-bgactive: #4d2393;
297
+ --sp-button-accent-bg: #5d28b8;
298
+ --sp-button-accent-bghover: #4d2393;
299
+ --sp-button-accent-bgactive: #401f75;
300
300
  --sp-button-accent-bgdisabled: #ddccff;
301
301
  --sp-button-accent-text: #ffffff;
302
302
  --sp-button-accent-textdisabled: #8a96ad;