Skip to content

Commit c179e61

Browse files
committed
Add six interactive Spectre components
Introduces `sp-nav`, `sp-sidebar`, `sp-dropdown`, `sp-modal`, `sp-toast`, and `sp-tooltip` with Lit-based behavior aligned to existing `@phcdevworks/spectre-ui` recipes. The change wires each component into root/subpath exports, build entries, and component contracts, and adds new placement/variant form helpers. It also adds dedicated behavior/accessibility tests for all six components and updates README, TODO, and changelog coverage for the expanded API surface and Phase 6 parity progress.
1 parent cb49b5d commit c179e61

28 files changed

Lines changed: 2723 additions & 132 deletions

CHANGELOG.md

Lines changed: 91 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,47 @@ reflects package releases published to npm.
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- `sp-nav` - thin wrapper backed by `getNavClasses`. Supports `bordered`,
12+
`sticky`, and `full-width`.
13+
14+
- `sp-sidebar` - off-canvas sidebar backed by `getSidebarClasses`,
15+
`getSidebarBackdropClasses`, and `getSidebarToggleClasses`. Renders a toggle
16+
button and backdrop, and manages `open` state as native Lit element
17+
interactivity (click, backdrop click, `Esc`) instead of a ported script.
18+
Reflects open/closed state via `data-sidebar-open` on the host to match the
19+
Spectre CSS selector contract. Dispatches `sp-open` and `sp-close`.
20+
21+
- `sp-dropdown` - trigger + menu backed by `getDropdownClasses` and
22+
`getDropdownMenuClasses`. Supports `placement`
23+
(bottom-start/bottom-end/top-start/top-end, default `bottom-start`) and
24+
`full-width`. Projects `slot="trigger"` content into the trigger button and
25+
all other children into the menu. Closes on outside click or `Esc` and returns
26+
focus to the trigger. Dispatches `sp-open` and `sp-close`.
27+
28+
- `sp-modal` - overlay + dialog backed by `getModalClasses` and
29+
`getModalOverlayClasses`. Supports `open` and `full-width`. Implements
30+
focus-trap (`Tab`/`Shift+Tab`), `Esc`-to-close, backdrop-click-to-close,
31+
initial focus on open, and focus restoration on close. Dispatches `sp-close`.
32+
33+
- `sp-toast` - notification backed by `getToastClasses` and
34+
`getToastIconClasses`. Supports `variant` (info/success/warning/danger,
35+
default `info`), `dismissed`, `full-width`, and `auto-dismiss` (ms). Exposes
36+
imperative `show()`/`dismiss()` methods and dispatches `sp-show` and
37+
`sp-dismiss`. Projects `slot="icon"` content into an icon container only when
38+
present.
39+
40+
- `sp-tooltip` - hover/focus-triggered tooltip backed by `getTooltipClasses`.
41+
Supports `placement` (top/bottom/left/right, default `top`) and `visible`.
42+
Shows on trigger `mouseenter`/`focusin` and hides on `mouseleave`/`focusout`.
43+
Dispatches `sp-show` and `sp-hide`.
44+
45+
These six close the remaining component-coverage gap against
46+
`@phcdevworks/spectre-ui-astro`, using its `.astro` adapters as the reference
47+
for recipe options and markup structure, with interactivity implemented as
48+
native Lit element state rather than ported scripts.
49+
950
## [1.6.0] - 2026-07-01
1051

1152
**Release Title:** Phase 6 - Layout and Recipe Alignment
@@ -28,15 +69,15 @@ Contract change type: additive
2869

2970
- `sp-stack` - layout component backed by `getStackClasses`. Supports
3071
`direction` (vertical/horizontal, default `vertical`), `basis` (`sidebar`),
31-
and `align` (center/stretch, default `center`). Exports
32-
`spectreStackAligns`, `spectreStackBases`, `spectreStackDirections`,
33-
`SpectreStackAlign`, `SpectreStackBasis`, and `SpectreStackDirection`.
72+
and `align` (center/stretch, default `center`). Exports `spectreStackAligns`,
73+
`spectreStackBases`, `spectreStackDirections`, `SpectreStackAlign`,
74+
`SpectreStackBasis`, and `SpectreStackDirection`.
3475

3576
These four close part of the component-coverage gap against
36-
`@phcdevworks/spectre-ui-astro`, using its `.astro` adapters as the
37-
reference for recipe options and markup structure (interactivity, where
38-
applicable in later additions, is implemented as native Lit element state
39-
rather than ported scripts).
77+
`@phcdevworks/spectre-ui-astro`, using its `.astro` adapters as the reference
78+
for recipe options and markup structure (interactivity, where applicable in
79+
later additions, is implemented as native Lit element state rather than ported
80+
scripts).
4081

4182
### Fixed
4283

@@ -45,20 +86,20 @@ Contract change type: additive
4586
element whenever an `aria-label` or `aria-labelledby` is forwarded. These
4687
components wrap a roleless `<div>`/`<span>`, and ARIA forbids `aria-label`/
4788
`aria-labelledby` on an element with no role - axe-core's
48-
`aria-prohibited-attr` rule flagged this as a violation. The role is
49-
omitted when no label is forwarded, so unlabeled instances are unaffected.
50-
Found while extending `tests/accessibility.test.ts` coverage (Phase 5 P1).
89+
`aria-prohibited-attr` rule flagged this as a violation. The role is omitted
90+
when no label is forwarded, so unlabeled instances are unaffected. Found while
91+
extending `tests/accessibility.test.ts` coverage (Phase 5 P1).
5192

5293
- `sp-checkbox` and `sp-radio` indicator spans now call `getCheckboxClasses`/
5394
`getRadioClasses` from `@phcdevworks/spectre-ui` instead of a hardcoded
54-
literal class string. Previously the `--checked`/`--disabled` modifier
55-
classes were never applied, so the indicator's visual state never changed
56-
on toggle or disable, regardless of the native `<input>`'s actual state.
95+
literal class string. Previously the `--checked`/`--disabled` modifier classes
96+
were never applied, so the indicator's visual state never changed on toggle or
97+
disable, regardless of the native `<input>`'s actual state.
5798

58-
- `sp-fieldset`'s root `<fieldset>` element now calls `getFieldsetClasses`
59-
from `@phcdevworks/spectre-ui`. Previously it rendered with no `class`
60-
attribute at all, so `@phcdevworks/spectre-ui`'s border/padding styling
61-
for `.sp-fieldset` never applied.
99+
- `sp-fieldset`'s root `<fieldset>` element now calls `getFieldsetClasses` from
100+
`@phcdevworks/spectre-ui`. Previously it rendered with no `class` attribute at
101+
all, so `@phcdevworks/spectre-ui`'s border/padding styling for `.sp-fieldset`
102+
never applied.
62103

63104
### Changed
64105

@@ -70,35 +111,35 @@ Contract change type: additive
70111

71112
- `sp-label` now calls `getLabelClasses` (`.sp-form-label`, themed via
72113
`--sp-label-*`) instead of `getInputLabelClasses` (`.sp-label`, themed via
73-
`--sp-component-input-role-text`) - the same kind of borrowed-recipe
74-
situation as `sp-fieldset`'s legend, now that a label-specific recipe
75-
exists. Added a `required` property, which `getLabelClasses` supports
76-
(renders `sp-form-label--required`) but the previous recipe did not.
114+
`--sp-component-input-role-text`) - the same kind of borrowed-recipe situation
115+
as `sp-fieldset`'s legend, now that a label-specific recipe exists. Added a
116+
`required` property, which `getLabelClasses` supports (renders
117+
`sp-form-label--required`) but the previous recipe did not.
77118

78119
**Rendered class name change**: any external CSS that happened to target
79120
`sp-fieldset`'s legend or `sp-label`'s native `<label>` via the `.sp-label`
80-
class will no longer match - neither was a supported public styling hook,
81-
but this is called out explicitly since the class name itself is visible
82-
in the DOM.
121+
class will no longer match - neither was a supported public styling hook, but
122+
this is called out explicitly since the class name itself is visible in the
123+
DOM.
83124

84125
- `sp-select` and `sp-textarea` now call the purpose-built
85126
`getSelectClasses`/`getTextareaClasses` recipes instead of borrowing
86127
`getInputClasses`, now that `@phcdevworks/spectre-tokens@3.3.1` and
87128
`@phcdevworks/spectre-ui@2.7.0` added `invalid`/`success`/`loading` state
88129
support to those recipes. `disabled` and `loading` are now forwarded as
89-
independent options instead of being collapsed into one `state` value, so
90-
each now renders its own modifier class.
130+
independent options instead of being collapsed into one `state` value, so each
131+
now renders its own modifier class.
91132

92-
**Rendered class name change**: `sp-select`/`sp-textarea` previously
93-
rendered `sp-input--*` modifier classes (e.g. `sp-input--lg`,
94-
`sp-input--error`); they now render `sp-select--*`/`sp-textarea--*` (e.g.
95-
`sp-select--lg`, `sp-select--invalid`). `sp-input--*` was never a supported
96-
public styling hook on these elements, but this is called out explicitly
97-
since the class names are visible in the DOM.
133+
**Rendered class name change**: `sp-select`/`sp-textarea` previously rendered
134+
`sp-input--*` modifier classes (e.g. `sp-input--lg`, `sp-input--error`); they
135+
now render `sp-select--*`/`sp-textarea--*` (e.g. `sp-select--lg`,
136+
`sp-select--invalid`). `sp-input--*` was never a supported public styling hook
137+
on these elements, but this is called out explicitly since the class names are
138+
visible in the DOM.
98139

99-
- Bumped `@phcdevworks/spectre-tokens` to `^3.3.1` and
100-
`@phcdevworks/spectre-ui` to `^2.7.0`, closing dependency drift against the
101-
current published `project-design` versions.
140+
- Bumped `@phcdevworks/spectre-tokens` to `^3.3.1` and `@phcdevworks/spectre-ui`
141+
to `^2.7.0`, closing dependency drift against the current published
142+
`project-design` versions.
102143

103144
### Testing
104145

@@ -112,25 +153,24 @@ Contract change type: additive
112153
- Form-association audit for `sp-input`, `sp-textarea`, `sp-select`,
113154
`sp-checkbox`, and `sp-radio` confirmed native form participation
114155
(`FormData`, `checkValidity()`, ancestor `form.checkValidity()`) works
115-
correctly without `ElementInternals`/`formAssociated`, since each
116-
component renders a real native form control as a light-DOM descendant.
117-
Added end-to-end tests submitting through an ancestor `<form>`.
156+
correctly without `ElementInternals`/`formAssociated`, since each component
157+
renders a real native form control as a light-DOM descendant. Added
158+
end-to-end tests submitting through an ancestor `<form>`.
118159
- Extended `tests/accessibility.test.ts` with axe-core scenarios covering
119160
populated, empty, and slot-projection states for `sp-badge`, `sp-card`,
120161
`sp-icon-box`, `sp-rating`, and `sp-testimonial` - this surfaced the
121162
`role="group"` fix above.
122163
- Audited `sp-card` and `sp-testimonial` for slotted-content edge cases
123-
(whitespace-only text, empty slotted elements, nested interactive
124-
elements, long-text overflow). Confirmed `hasMeaningfulContent()` and
164+
(whitespace-only text, empty slotted elements, nested interactive elements,
165+
long-text overflow). Confirmed `hasMeaningfulContent()` and
125166
`SpectreProjectableElement` already handle all four correctly; added
126167
regression tests locking in the behavior.
127168
- Added Playwright-based visual regression coverage
128169
(`visual-tests/components.visual.spec.ts`) snapshotting all 21 components
129-
via the existing `verification_app.ts` page. Run with
130-
`npm run test:visual`; regenerate baselines with
131-
`npm run test:visual:update`. Local opt-in only - not wired into
132-
`npm run check` or CI, since cross-runner font/rendering differences make
133-
CI-gated pixel diffs a separate decision.
170+
via the existing `verification_app.ts` page. Run with `npm run test:visual`;
171+
regenerate baselines with `npm run test:visual:update`. Local opt-in only -
172+
not wired into `npm run check` or CI, since cross-runner font/rendering
173+
differences make CI-gated pixel diffs a separate decision.
134174

135175
## [1.5.0] - 2026-06-11
136176

@@ -169,13 +209,14 @@ Contract change type: additive
169209
`SpectreTagSize`, and `SpectreTagProps`.
170210

171211
- `sp-pricing-card` - display container backed by `getPricingCardClasses`.
172-
Supports `featured`, `interactive`, `disabled`, `loading`, and
173-
`full-height`. Reflects the `loading` state to `aria-busy`. Exports
212+
Supports `featured`, `interactive`, `disabled`, `loading`, and `full-height`.
213+
Reflects the `loading` state to `aria-busy`. Exports
174214
`SpectrePricingCardProps`.
175215

176216
## [1.4.0] - 2026-06-07
177217

178-
**Release Title:** Phase 4 - Display Component Expansion and Ecosystem Manifest Gate
218+
**Release Title:** Phase 4 - Display Component Expansion and Ecosystem Manifest
219+
Gate
179220

180221
Contract change type: additive
181222

@@ -329,7 +370,8 @@ Contract change type: additive
329370

330371
## [1.1.0] - 2026-05-05
331372

332-
**Release Title:** Phase 1 - Foundation API Tightening and Component Documentation
373+
**Release Title:** Phase 1 - Foundation API Tightening and Component
374+
Documentation
333375

334376
Contract change type: additive
335377

0 commit comments

Comments
 (0)