Skip to content

feat(ui): shadcn-svelte primitives in shared/ui (issue #68)#80

Merged
fedorovvvv merged 10 commits into
developfrom
feature/issue-68-shadcn-components
May 7, 2026
Merged

feat(ui): shadcn-svelte primitives in shared/ui (issue #68)#80
fedorovvvv merged 10 commits into
developfrom
feature/issue-68-shadcn-components

Conversation

@fedorovvvv
Copy link
Copy Markdown
Collaborator

Summary

  • Adds 26 shadcn-svelte primitives to template/src/shared/ui/ via bits-ui wrappers + CSS-var styling (no Tailwind, no new runtime deps).
  • Catalogue + /playground showcase route for visual smoke and design review.
  • Backed by PRD-018 + RFC-016 + EVID-022 (R_eff = 1.00, grade A).

Why

Issue #68 — promote shared/ui from 5 ad-hoc primitives (Button, Code, Dialog, Modal, Select) to the full primitive set so future widgets compose from a single, consistent library. 7 of the previously-empty placeholder folders (badge/alert/separator/skeleton/spinner/progress/card/) are now real implementations.

What's in

26 primitives across 7 functional groups, each its own commit + sub-issue:

Group Sub-issue Primitives
1 #72 Badge / Separator / Skeleton / Spinner / Card / Alert / Progress
2 #73 Label / Input / Field / InputGroup
3 #74 Toggle / ToggleGroup / ButtonGroup / Switch / Checkbox / Slider
4 #75 Radio / RadioGroup
5 #76 Tabs / Collapsible / Accordion
6 #77 Tooltip / Popover / Toaster
7 #78 Command + Item family
8 #79 README catalogue + /playground route + Chrome smoke

+layout.svelte now wraps the app in TooltipProvider and mounts Toaster.

What's deferred

  • Replacing ad-hoc CSS in widgets/version-footer, widgets/mosaic, widgets/update-dialog with the new primitives (PRD-018 SC-2). Tracked as a follow-up issue.

Test plan

  • npm run check (svelte-check) — 0 errors / 0 warnings
  • Chrome smoke at http://127.0.0.1:5174/playground in data-theme=dark — 0 console errors, all 7 sections render
  • Chrome smoke at /playground in data-theme=light — body bg rgb(245,242,234) matches PRD-015 token, 0 console errors
  • Chrome smoke at / (home, force-directed graph) — 354 SVG nodes render; +layout.svelte change didn't break the existing app
  • Interactive checks: Popover bubble opens, Toaster Saved! appears bottom-right, Tabs/Accordion state, Command palette filters

Forgeplan trail

  • PRD-018 — shadcn-svelte primitives in shared/ui (Standard depth) — active
  • RFC-016 — bits-ui-based primitives with CSS-var styling — active, based_on PRD-018
  • EVID-022 — catalogue + Chrome smoke measurement — active, CL3 supports measurement, R_eff = 1.00 grade A

Closes #68.

Refs: PRD-018, RFC-016, EVID-022

fedorovvvv added 10 commits May 7, 2026 20:50
…ed/ui

Standard-depth artifacts backing GitHub issue #68. Adds 26 primitives
to template/src/shared/ui/ via bits-ui wrappers + CSS-var styling
(no Tailwind). PRD-018 lists groups 1-7 + integration; RFC-016 pins the
per-primitive shape and bits-ui touchpoints. Both pass `forgeplan validate`
with 0 MUST errors (SHOULD/COULD warnings tracked but out of scope here).
RFC-016 -> PRD-018 linked (based_on).

Refs: PRD-018, RFC-016, #68
…ard/Alert/Progress

Group 1 of 8 from issue #68 (PRD-018 / RFC-016). Seven pure-CSS visual atoms
under template/src/shared/ui/, styled by tokens from app.css (no Tailwind, no
new deps). Same shape as existing Button/Select.

- Badge: variant (primary/secondary/success/danger/ghost), size (sm/md)
- Separator: orientation (horizontal/vertical), decorative flag
- Skeleton: width/height/radius props, shimmer with reduced-motion fallback
- Spinner: size (sm/md/lg), aria-label, reduced-motion fallback
- Card: padding (none/sm/md/lg), variant (flat/outlined/elevated), header/footer snippets
- Alert: variant (info/success/warning/danger), Lucide icon defaults, role auto-toggle
- Progress: 0..max value or indeterminate, variant (primary/success/warning/danger)

Barrel `shared/ui/index.ts` now exports 12 named primitives (was 5).

Refs: PRD-018, RFC-016, #68, #72
Group 2 of 8 from issue #68 (PRD-018 / RFC-016). Four form atoms styled by
tokens from app.css. No bits-ui — Input is native <input> with token-driven
states; Field and InputGroup are composition primitives.

- Label: required/optional indicators, for-association, sm font-size
- Input: type forwarded; size (sm/md); invalid prop drives data-invalid +
  aria-invalid; focus-visible ring + accent border via tokens
- Field: pairs Label + control + helper/error; auto-generates id, ties
  describedBy/aria-invalid via render snippet props
- InputGroup: prefix/suffix snippets around an Input, focus-within ring on
  the wrapper; collapses inner Input border via :global

Barrel `shared/ui/index.ts` now exports 16 named primitives.

Refs: PRD-018, RFC-016, #68, #73
…heckbox/Slider

Group 3 of 8 from issue #68 (PRD-018 / RFC-016). Six toggle-style primitives,
five wrap bits-ui (Switch, Checkbox, Toggle, ToggleGroup, Slider) and ButtonGroup
is a pure-CSS composition wrapper.

- Toggle: pressed/onPressedChange, size (sm/md), variant (default/outline)
- ToggleGroup + ToggleGroupItem: single/multiple modes, horizontal/vertical
- ButtonGroup: orientation, attached vs spaced layout (collapses inner radii)
- Switch: bind:checked, accent track when on, theme-token thumb
- Checkbox: bind:checked + bind:indeterminate (bits-ui v2 separates them);
  Lucide check/minus icons via snippet
- Slider: multi-thumb support; horizontal/vertical; range fill via accent

Barrel `shared/ui/index.ts` now exports 22 named primitives.

Refs: PRD-018, RFC-016, #68, #74
Group 4 of 8 from issue #68 (PRD-018 / RFC-016). Wraps bits-ui RadioGroup;
RadioGroup carries value/onValueChange + form-submission name; Radio is the
standalone item rendered with an accent dot when checked.

Barrel `shared/ui/index.ts` now exports 24 named primitives.

Refs: PRD-018, RFC-016, #68, #75
Group 5 of 8 from issue #68 (PRD-018 / RFC-016). Three disclosure primitives,
all bits-ui wrappers. Each splits into Root + auxiliary parts (Tabs.List etc.)
and ships its own CSS via :global() rules keyed off bits-ui data-state.

- Tabs / TabsList / TabsTrigger / TabsContent — orientation, activationMode,
  underline trigger style; vertical mode uses right-border accent
- Collapsible / CollapsibleTrigger / CollapsibleContent — slide animation with
  reduced-motion fallback
- Accordion / AccordionItem / AccordionTrigger / AccordionContent — single
  + multiple modes; chevron rotates on open

Barrel `shared/ui/index.ts` now exports 31 named primitives (10 atoms + 21 from groups).

Refs: PRD-018, RFC-016, #68, #76
Group 6 of 8 from issue #68 (PRD-018 / RFC-016). Three overlay primitives:
two thin bits-ui wrappers (Tooltip, Popover) and an in-house Toaster store
(no new dep — Svelte 5 runes class with timer-driven dismissal).

- Tooltip + TooltipProvider: side/align/sideOffset, accent border via tokens.
  Provider mounted in `+layout.svelte` so any descendant can use Tooltip.
- Popover + PopoverTrigger + PopoverContent: portal-based, optional Arrow
- Toaster + toast() helper: queue with id-keyed dismissal, variant-driven
  left-border accent, 6 corner positions, reduced-motion fallback.
  toast() also exposes .info/.success/.warning/.danger/.dismiss/.clear.

Toaster mounted alongside ModalRoot in `+layout.svelte`. Renamed
toaster.svelte.ts -> toaster-store.svelte.ts to avoid macOS case-insensitive
filename collision with Toaster.svelte.

Barrel `shared/ui/index.ts` now exports 38 named primitives.

Refs: PRD-018, RFC-016, #68, #77
Group 7 of 8 from issue #68 (PRD-018 / RFC-016). bits-ui Command wrapped into
a self-contained palette: Root + Input + List + Empty + Group + Separator + Item.
The Item primitive (Item.svelte) is the per-row entry; onSelect, value, keywords,
and disabled are forwarded.

Sub-parts:
- Command: bind:value + shouldFilter + loop, accent-on-selected styling
- CommandInput: search icon + native input piped through Command.Input
- CommandList + CommandViewport: max-height + scroll
- CommandEmpty: shown when filter yields nothing
- CommandGroup: heading + items wrapper
- CommandSeparator: 1px line between groups

Barrel `shared/ui/index.ts` now exports 45 named primitives.

Refs: PRD-018, RFC-016, #68, #78
Group 8 of 8 from issue #68 (PRD-018 / RFC-016). Closes the primitive
build-out:

- shared/ui/README.md catalogues all 26 new primitives + 5 existing
  (Button/Code/Dialog/Modal/Select), grouped by family (Visual atoms /
  Form basics / Toggles / Radio / Disclosure / Overlays / Command).
- /playground +page.svelte renders every primitive in a single page —
  used as the visual smoke harness during PRs.

Smoke run (dev server on :5174, Chrome MCP):
- /playground renders all 7 sections with 0 console errors.
- /, /playground both clean across data-theme=light + data-theme=dark.
- Tooltip/Popover/Toaster mounted via root +layout.svelte all interact:
  click "Open popover" -> bubble appears; click "Success toast" -> "Saved!"
  toast in bottom-right with success accent and dismiss button.
- Light theme bg = rgb(245,242,234); dark theme = #050505 — both honour
  PRD-015/RFC-014 token contract.

Note: integrating new primitives into existing widgets/version-footer/
update-dialog is intentionally deferred to a follow-up PR — keeping the
diff for issue #68 focused on landing the catalogue. The /playground
route gives reviewers + downstream widget work a stable visual contract
to land against.

Refs: PRD-018, RFC-016, #68, #79
… / EVID-022

EVID-022 measures issue #68 Group 8 deliverables against PRD-018:
- SC-1 (catalogue completeness): 26/26 — pass
- SC-3 (visual smoke in Chrome): 0 console errors across light + dark — pass
- SC-4 (npm run check): 0 errors — pass
- NFR-003 (svelte-check): 0 errors — pass
- NFR-005 (dual-theme parity): verified — pass
- SC-2 (no ad-hoc copies in widgets/*): deferred to follow-up — flagged

Structured Fields: verdict=supports, congruence_level=3 (CL3 same-context),
evidence_type=measurement. R_eff = 1.00 (grade A) on both PRD-018 and RFC-016.

PRD-018, RFC-016, EVID-022 all activated (draft → active).

Refs: PRD-018, RFC-016, EVID-022, #68
@fedorovvvv fedorovvvv merged commit 6ddb829 into develop May 7, 2026
3 checks passed
@fedorovvvv fedorovvvv deleted the feature/issue-68-shadcn-components branch May 7, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant