feat(ui): shadcn-svelte primitives in shared/ui (issue #68)#80
Merged
Conversation
…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
This was referenced May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
template/src/shared/ui/viabits-uiwrappers + CSS-var styling (no Tailwind, no new runtime deps)./playgroundshowcase route for visual smoke and design review.Why
Issue #68 — promote
shared/uifrom 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:
/playgroundroute + Chrome smoke+layout.sveltenow wraps the app inTooltipProviderand mountsToaster.What's deferred
widgets/version-footer,widgets/mosaic,widgets/update-dialogwith the new primitives (PRD-018 SC-2). Tracked as a follow-up issue.Test plan
npm run check(svelte-check) — 0 errors / 0 warningshttp://127.0.0.1:5174/playgroundindata-theme=dark— 0 console errors, all 7 sections render/playgroundindata-theme=light— body bgrgb(245,242,234)matches PRD-015 token, 0 console errors/(home, force-directed graph) — 354 SVG nodes render;+layout.sveltechange didn't break the existing appSaved!appears bottom-right, Tabs/Accordion state, Command palette filtersForgeplan trail
activeactive,based_onPRD-018active, CL3 supports measurement, R_eff = 1.00 grade ACloses #68.
Refs: PRD-018, RFC-016, EVID-022