Skip to content

Migrate from Stencil to Vue webcomponents - #244

Merged
villeerikssoncsc merged 109 commits into
mainfrom
vue-migration
Aug 13, 2026
Merged

Migrate from Stencil to Vue webcomponents#244
villeerikssoncsc merged 109 commits into
mainfrom
vue-migration

Conversation

@villeerikssoncsc

Copy link
Copy Markdown
Contributor

No description provided.

villeerikssoncscand others added 30 commits May 25, 2026 14:08
This commit continues the migration of UI components to Vue 3 by introducing:
- CIconButton
- CLink
- CLoader
- CProgressBar
- CRadio and CRadioGroup
- CSpinner
- CSwitch
- CTag and CTags
…onents to align with modern Vue 3.5 development best practices and a new Tailwind CSS styling architecture.
Key changes include:
- Migrating components to `tailwind-variants` for internal styling, replacing legacy CSS variables.
- Standardizing prop definitions (`defineProps()` with `withDefaults`), template refs (`useTemplateRef`), and unique IDs (`useId`).
- Shifting consumer customization to the `::part()` API, leading to the removal of the `override` prop and the extensive Tailwind safelist.
- Enhancing runtime performance by implementing `adoptedStyleSheets` for shared CSS, reducing redundant style payload.
- Introducing a shared `emitModelValue` helper for consistent `v-model` and `v-control` compatibility.
- Updating developer tooling with new ESLint, Prettier, and devcontainer configurations.
- Documenting all major architectural decisions and refactor plans through new ADRs and markdown files.
Introduces the new `c-menu`, `c-menu-item`, `c-menu-label`, and `c-divider` components for `csc-ui-next`.
This component family is a net-new, declarative, slot-based implementation of the WAI-ARIA menu-button pattern. It replaces the legacy Stencil `c-menu` (which was programmatic and mislabeled `role="listbox"`), distinguishing command menus from value-selection dropdowns (`c-dropdown`).
Key architectural decisions include:
- Leveraging the native Popover API for top-layer rendering and free light-dismiss features.
- Utilizing CSS anchor positioning for declarative placement relative to the trigger, with `position-try-fallbacks` for flip/shift behavior.
- Incorporating the OddBird polyfill for CSS anchor positioning, lazily loaded only when native support is absent (e.g., Firefox).
- Full WAI-ARIA support, including roving tabindex, type-ahead, and submenu handling.
The documentation site's hot module reloading for `csc-ui-next` components was intermittently unreliable, sometimes leading to stale or broken UI states during development.
This update addresses the issue by:
- Waiting for files to reach a stable size before triggering a reload, preventing re-fetching of half-written bundles.
- Listening for `add`, `change`, and `unlink` events to correctly handle content-hashed chunks that change filenames between builds.
- Debouncing rebuild notifications to coalesce multi-file writes into a single, comprehensive reload.
This commit also includes minor styling adjustments to `CLoginButton`'s `root` and `title` slots for improved rounding and layout consistency.
Previously, `c-select` would unconditionally return focus to its input after an option was selected, even if the value change came from a programmatic update (e.g., initial `v-model` value).
This could lead to unwanted focus stealing and page scrolling on load. Now, focus is only returned to the input when the user has actively interacted with the component, improving accessibility and user experience.
Introduces the new `c-autocomplete` component, implementing a filterable value-selection field with a dedicated in-panel search input.
This component is built on the native Popover API and CSS anchor positioning (similar to `c-menu`, ADR-0008), rather than `c-dropdown`. This architectural choice (documented in ADR-0009 and `CONTEXT.md`) enables a distinct UX with a persistent readonly value field and an in-panel search input, aligning with design requirements.
It adheres to the editable combobox WAI-ARIA pattern, keeping DOM focus in the search input and managing options virtually via `aria-activedescendant`.
This commit includes the core component, updated documentation examples, build configurations for TypeScript declarations (`dist-types`), and public types for consumers. Minor adjustments to `c-input`'s label alignment and `c-menu`'s internal item lookup are also included.
Record the dark-mode architecture for csc-ui-next: a mode-aware semantic-token
layer components author against (not palette-swap, not per-component dark:),
activated via data-theme + prefers-color-scheme. Adds ADR-0010, the glossary
terms (palette/semantic token, theme mode, surface ladder, on- token), and the
phased implementation plan.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Duplicate the style-dictionary token pipeline from @cscfi/csc-ui into
csc-ui-next so the package owns its --c-* palette ahead of the eventual Stencil
removal (ADR-0010). Trimmed to the single output needed today: the palette as
document-level custom properties, generated to src/styles/css/theme.css and
copied into dist/styles/css post-build (vite empties dist). Exposed via the
./css/* export. Output is byte-identical to csc-ui's theme.css.
Generator files are .cjs (csc-ui-next is type:module); copy-styles uses an
explicit copyFileSync walk (fs.cpSync produced broken files in this env).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…phase 1)
Add the mode-aware semantic-token layer (ADR-0010): light/dark role->palette-step
maps (tokens/semantic/{light,dark}.json) and a generator (createSemanticTheme)
that emits three CSS blocks — :root/[data-theme=light] default, [data-theme=dark]
forced, and a prefers-color-scheme:dark fallback for the unset case.
The css/theme platform becomes css/tokens, emitting a single document-level
tokens.css = palette + semantic layer (the consumer import). source is narrowed
to tokens/theme so style-dictionary doesn't parse the semantic maps as tokens.
Values are provisional (remap existing ramp steps, no new hexes) pending the
WCAG AA contrast pass. Utilities (bg-surface, bg-primary, ...) are wired in phase 2.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…phase 2)
Add the semantic-token -> utility map to src/tailwind.css so the role tokens
from tokens.css are exposed as per-role color utilities (background/text/border/
ring). inline substitutes the value directly, so a semantic utility compiles to
e.g. background-color:var(--c-surface) and resolves inside shadow roots via
inheritance from the document :root. Verified each role compiles correctly
(incl. border->border-color, ring->ring-color) and that unused roles emit
nothing (ADR-0006, no safelist).
Also scope Tailwind to the SFC sources with source(none): automatic content
detection was scanning sibling .cjs/.ts/.css comments and the previous build's
own bundle, emitting stray unused rules (and risking bundle self-growth). This
makes the implementation match ADR-0006's stated 'auto-detected from the @source
SFC glob' model. Confirmed only .vue files author utilities.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hase 3)
Re-author CButton's tailwind-variants config from palette-step utilities to
semantic tokens (ADR-0010). Verified light mode resolves to the identical
palette steps the original hardcoded (no visual change), and dark mode reads
correctly via headless screenshots of both themes.
The pilot surfaced two contract decisions (now applied to the whole token set):
- Explicit interaction/tint tokens per role: add <role>-hover and
<role>-subtle-hover; shift <role>-subtle 100->200. Preserves CSC's
lighten-on-hover in both modes.
- Mode-invariant 'inverse' family (invariant.json, emitted once under :root):
inverse-surface/on/primary/error keep inverted buttons looking the same in
both themes (they sit on a fixed brand/dark backdrop). createSemanticTheme
now takes a third invariant map.
@theme inline gains the new -hover/-subtle-hover and inverse-* utilities.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hase 3)
Amend ADR-0010 and the plan with the token set the pilot finalized: six tokens
per brand/status role (incl. -hover, -subtle-hover; subtle shifted 100->200) and
the mode-invariant inverse-* family for the inverted variants. Resolve the plan's
open questions on tokens.css shape (single file) and the sub-role list.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add scripts/check-palette-utilities.mjs (npm: lint:tokens), the CI guard for
ADR-0010's semantic-only rule. Flags colour utilities whose colour is a hue with
a numeric step (bg-primary-600) or white/black, while allowing the bare semantic
tokens and current/transparent. Strips comments first (newlines preserved) so
existing migration-note comments referencing palette steps don't false-positive.
Informational by default (exit 0) — it doubles as the phase-5 worklist; --strict
exits 1 on any violation and gets wired into CI once the batch migration lands.
Baseline: 191 palette-step utilities across 38 of 72 SFCs; CButton is clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… phase 5a)
Batch 5a — pure surface/layout containers: c-page, c-main, c-toolbar,
c-backdrop, c-divider, c-card, c-card-title. Establishes the surface-ladder
conventions: bg-white -> bg-surface-raised, page tint bg-primary-200 ->
bg-primary-subtle, divider bg-tertiary-300 -> bg-border, brand accents ->
bg-primary/text-primary.
Also convert the legacy var refs text-[var(--c-text-body)] -> text-on-surface
and text-[var(--c-text-system)] -> text-on-surface-muted (incl. CMain's
::slotted escape-hatch CSS) — these did not flip in dark and were latent bugs
the guard doesn't catch.
Add a mode-invariant scrim token (black) for c-backdrop's overlay
(bg-black/50 -> bg-scrim/50). Verified both modes via headless screenshots.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… 5b)
Re-author the menu, dropdown and list component families against the
ADR-0010 semantic token layer so they theme in dark mode:
- overlay surfaces (menu/submenu/dropdown lists): bg-white -> bg-surface-overlay
- item hover/active/selected: primary-200/600 -> primary-subtle / primary
- danger menu items: error-100/600 -> error-subtle / error
- body/system text: var(--c-text-body|system) -> on-surface / on-surface-muted
- dropdown disabled-row tint: tertiary-600/5 -> on-surface/5
- list-item hover/active/disabled & focus ring, c-list bordered borders,
and the data-active highlight in escape-hatch CSS remapped to semantic vars
Guard: 181 -> 166 palette-step utilities (31 -> 26 SFCs). Verified light +
dark via headless screenshots; light matches original, dark shows correct
surface-ladder elevation and item-state contrast.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(phase 5c)
Re-author the value-selection field components against the ADR-0010
semantic layer:
- panel/card + dropdown surface: bg-white -> bg-surface-overlay
- option rows (data-[active]): primary-200/600 -> primary-subtle / primary
- field + search input text: var(--c-text-body) -> on-surface
- placeholders & info text: tertiary-500 / var(--c-text-system) -> on-surface-muted
- no-results info icon: text-warning-600 -> text-warning
- search divider border: tertiary-300 -> border; caret-color, spinner colour
and the rich-selection overlay colour: primary-600 -> primary
- disabled-row tint: tertiary-600/5 -> on-surface/5
Guard: 166 -> 155 palette-step utilities (26 -> 24 SFCs). Overlay/item-state
token mappings are shared with the 5b popover family already verified in
light + dark; semantic tokens confirmed emitted in tokens.css.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ase 5d)
Re-author the status-coloured components against the ADR-0010 semantic
status roles + neutrals so they theme in dark mode:
- c-alert: accent text-{role}-600 -> text-{role}; content text rgba(0,0,0,.87)
(a hardcoded near-black that broke on dark) -> text-on-surface
- c-status pills: bg-{role}-200/text-{role}-800 -> bg-{role}-subtle / on-{role}-subtle
- c-badge: warning-600/white -> bg-warning / text-on-warning; ring-white -> ring-surface
(theme-aware cut-out instead of hardcoded white)
- c-message: text-error-600 -> text-error; system text -> on-surface-muted
- c-tag: primary-600/white/primary-400 -> primary / on-primary / primary-hover
across resting, active, badge ::before, hover and focus states
- c-progress-bar: track tertiary-200 -> surface-muted, fill primary-600 -> primary
(slots + the native <progress> pseudo-element CSS), negative -> text-error
- c-loader: bg-white/80 scrim -> bg-surface/80; spinner colour -> text-primary;
message text -> on-surface-muted
- c-toast: bg-white -> bg-surface-raised, system text -> on-surface-muted,
progress track -> surface-muted, type accents {role}-600 -> {role}
(border/icon/progress + the close-icon ACCENT_VAR map)
Guard: 155 -> 106 palette-step utilities (24 -> 16 SFCs). Verified light + dark
via headless screenshots; all status roles read correctly in both modes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…trong (phase 5e)
Add a new neutral semantic role `border-strong` (light tertiary-600 /
dark tertiary-500) for interactive form-control outlines: the existing
`border` role (tertiary-200) is too faint for field borders and would make
inputs look near-borderless. Wired through both semantic maps and the
@theme inline bridge.
Re-author the form components against the ADR-0010 semantic layer:
- c-input: fieldset resting border tertiary-600 -> border-strong; active
border + label primary-600 -> primary; error border/label/message -> error;
resting label tertiary-600 -> on-surface-muted; required asterisk -> error;
shadow-mode slot bg-white -> bg-surface; host inherited text colour
(typed value) var(--c-text-body) -> on-surface; caret + placeholder remapped
- c-text-field: value/textarea text -> on-surface, disabled -> on-surface-muted,
caret -> primary; password toggle hover primary-100 -> primary-subtle-hover,
focus outline -> primary
- c-otp-input: digit text -> on-surface, resting ring tertiary-500 -> border-strong,
focus ring -> primary, invalid ring -> error
- c-slider: thumb/track-fill/focus primary-600/500 -> primary; disabled
thumb + track + inactive ticks tertiary-400/500 -> border-strong; active tick
white -> on-primary; unfilled track -> surface-muted; hover halo -> color-mix
of primary; tooltip primary-900/white -> on-surface/surface (inverts per mode)
Guard: 106 -> 89 palette-step utilities (16 -> 12 SFCs). Verified light + dark
via headless screenshots; field borders read clearly in both modes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eholder
The guard only matched palette-step UTILITIES (bg-primary-600), missing two
forms that equally fail to theme: arbitrary-value utilities
(text-[var(--c-error-600)]) and escape-hatch <style> refs
(color: var(--c-primary-600), rgba(var(--c-primary-rgb),…)). Add a var-level
regex that matches var(--c-<hue>-<step>), var(--c-white|black) and the -rgb
channel vars, while never matching semantic tokens (a hue must be followed by a
digit or `rgb`, which role names never are). True remaining surface is now
184 refs across 23 SFCs (was under-reported as 89).
Also remap a c-text-field placeholder colour (tertiary-400 -> on-surface-muted)
that the old utility-only guard hadn't surfaced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
These authored colour via the arbitrary-value form (text-[var(--c-error-600)])
and sibling-driven escape-hatch CSS, both newly surfaced by the tightened guard:
- c-checkbox: box/check/ripple primary-600 -> primary, white check -> on-primary
(+ error-scoped on-error check), error states -> error, disabled greys ->
border-strong, hint/disabled text -> on-surface-muted, hover halo -> color-mix
- c-radio-group: ring/dot currentColor source primary-600 -> primary, error ->
error, disabled -> on-surface-muted, hover halo -> color-mix
- c-switch: off track/handle tertiary-600 -> border-strong, on track/border
primary-600 -> primary with handle white -> on-primary, disabled track/handle
-> border-strong / surface(-muted), focus outline -> primary
- c-spinner: default colour prop var(--c-primary-600) -> var(--c-primary)
Guard: 184 -> 134 palette-step references (23 -> 18 SFCs). Verified all states
(checked/error/disabled, radio selected, switch on/off/disabled) light + dark.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(5f)
Batch 5f of the dark-mode semantic-token migration (ADR-0010): the
nav/structure + table cluster now authors against semantic roles instead
of palette steps so it themes in dark mode.
- c-icon-button: mirror c-button's semantic palette across every
appearance × inverted × disabled compound (primary/on-primary,
inverse-* for inverted, error, surface-muted/on-surface-muted disabled);
badge -> bg-warning/text-on-warning/border-surface.
- c-accordion-item: header -> primary-subtle/text-primary; outlined ring
-> primary-subtle.
- c-link: move onto the dedicated `link` semantic role (was info-700 only
because no link token existed in csc-ui-next); hover -> link-subtle.
- c-login-button/-card/-card-title: bg-white -> surface, tertiary borders
-> border, text-system -> on-surface-muted, primary-600 -> primary.
- c-tab/-tabs/-tab-buttons: primary-600 -> primary, primary-100 track ->
primary-subtle-hover, tertiary -> border / border-strong / surface-muted.
- c-step/-steps: primary-600 -> primary, white check -> on-primary,
tertiary-500 ring/divider -> border-strong, bg-white -> surface.
- c-table: white -> surface, tertiary-200 -> border, text-body/-system ->
on-surface/-muted, primary-rgb alpha -> color-mix.
Verified light + dark via headless chromium. The side-navigation cluster
(c-side-navigation*, c-sub-navigation-item) is intentionally left for a
follow-up: it is a fixed brand backdrop whose dark treatment is a separate
design decision. c-swiper/-tab are skipped (slated for removal).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes batch 5f: the side-navigation family now adapts to the theme
instead of staying a fixed brand island (per design decision). Adds a small
themed `nav` token family (ADR-0010) — `nav-surface`, `nav-surface-hover`,
`on-nav` — that is the brand primary in light and a dark neutral panel in
dark; the accents reuse existing roles.
- tokens: add nav-surface / nav-surface-hover / on-nav to light.json (primary-
600 / primary-500 / white) and dark.json (tertiary-800 / tertiary-700 /
white); bridge them in tailwind.css.
- c-side-navigation: drawer + desktop host bg primary-600 -> nav-surface;
overlay rgba(black) -> color-mix over the scrim role.
- c-side-navigation-item: item text white -> on-nav; hover primary-500 ->
nav-surface-hover; active pill primary-200/primary-600 ->
primary-subtle/on-primary-subtle; sub-item box bg-white/primary-600 ->
surface-raised/primary; focus outline white -> on-nav.
- c-side-navigation-title: text + underline white -> on-nav.
- c-sub-navigation-item: text text-body -> on-primary-subtle; hover/before
primary-600 -> primary; active bg-white -> surface-raised; 3rd-level active
+ hover primary-100 -> primary-subtle-hover; focus outline -> primary.
Verified light + dark with a nested expandable-item + sub-items demo: light
mode is faithful to the original brand sidebar; dark mode is a legible dark
panel with primary-tinted active pills. Only c-swiper/-tab remain on palette
steps (slated for removal); the lint:tokens guard is otherwise clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
razorfeverand others added 24 commits July 9, 2026 13:33
Each example block gets an anchor id (shared exampleAnchor helper) and an
indented sub-link under Examples in the TOC, tracked by the scrollspy like
every other target. Anchor jumps now land below the sticky toolbar: the
example figures, section h2s, and API headings carry scroll-mt-20 (nothing
set a scroll offset before, so all anchors landed flush under the toolbar).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rail + scrollspy move from the component page into a shared TocRail
component (items: {id, label, kind} in document order); the component page
builds its heterogeneous list (usage, examples + sub-links, API sections)
and the three guides list their sections. Guide h2 anchors get the same
scroll-mt-20 treatment so rail jumps land below the sticky toolbar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When a long On-this-page rail overflows its own scrollport, it now
auto-scrolls (instantly, with 32px breathing room) to the active link —
but only when the active target changes, so it never fights a user
browsing the rail while the page stands still. Also corrects the rail's
max-height (100vh-7rem, was -3rem): with sticky top-24 the box extended
below the viewport, leaving tail links unreachable by its own scrollbar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mports in Vue examples
Convert the remaining value-bind + change-value examples to plain v-model
and import every Vue API explicitly instead of leaning on Nuxt
auto-imports, so the Vue-flavor examples are copy-pasteable outside Nuxt.
The example parity script now fails the build when a canon example calls
a Vue API or useXxx composable without importing it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…form label anatomy
c-button-group (ADR-0023) is the standalone labelable value control —
exclusive by default, cumulative with multiple — built from plain
c-button children driven via the new active prop (tabs mode is gone).
c-tab-buttons remains only as the tab-strip adapter inside c-tabs.
New-style components emit change/update:value plus a native input via
emitModelChange; the analyzer lints the event map for it.
Labelable form controls (ADR-0022) share one label anatomy through
shared/FormLabel.vue with two association modes: field label (for/id)
and group label (aria-labelledby) — adopted by c-checkbox, c-switch,
c-radio-group, c-slider, c-otp-input, c-tags and c-button-group.
Docs follow along: c-button-group examples and migration entry, label
examples for c-switch/c-tags, the flavor tabs in ExampleBlock moved to
c-button-group, CONTEXT.md vocabulary for the new concepts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pre-paint inline script read the stale 'csc-docs-theme' storage key
while useTheme writes 'csc-ui-docs-theme', so reloads silently fell back
to the OS preference. Point the script at the right key and make
initThemeFromStorage re-apply the attribute as a backup against drift.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bump on-nav to primary-100 and nav-active to primary-700, and ring the
active side-navigation item with primary instead of border so the
active state stays legible in dark mode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bind-mount a host-side history file and enable shared, deduplicated
history in zsh; re-enable pnpm install as the postCreateCommand.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the migration page
Mark the customization page and the v-model/explicit-imports example
work done, add newly found items, and small migration-page cleanups
(max-w utility, scoped eslint-disable for the Shiki v-html block).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ntrols
Rename the `validation` prop to `errorMessage` on c-input, c-text-field,
c-select, c-autocomplete, c-otp-input, c-radio-group, c-checkbox and
c-message. The 'Required field' default is dropped — there is no implicit
message — and an invalid control without an error message now keeps
showing its hint styled as a hint (error presentation only appears when a
message actually exists; new messageError tv variant). Remove the inert
validate / validate-on-blur props that were never wired to anything.
Update the c-message docs examples and the migration page, regenerate the
tag map / manifest, and record the hint / error-message vocabulary in the
CONTEXT.md glossary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…line
Drop the root border and paint the table outline as per-cell segments,
matching the Stencil original where the thead background covered the
inset outline: first/last-column body cells carry the left/right rails,
the last row (or tfoot) the bottom edge, and header cells none — so the
header has no top/left/right border and the outline starts at its bottom
edge. The structural rules are pinned to (0,0,3) specificity with
:where() so the selected/expanded/expansion state rings always win and
repaint their own edges.
Also reset the expansion state (and emit change:expanded) when autohide
reveals every column: without the expander column an expanded row kept
its ring and an empty panel with no way to close them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… work plan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ExampleBlock
The `html` prop is now optional and defaults to an empty object. This prevents
runtime errors when the prop is not explicitly passed to the component.
Removes explicit height and leading from the floating label as `text-base`
establishes the correct line box (24px) in Tailwind v4, preventing descender
clipping. Switches `overflow-hidden` to `overflow-x-clip` to maintain
horizontal ellipsis while allowing vertical ink overflow for tall-metric
fonts.
…l-open reveal
Introduces a robust pre-upgrade placeholder mechanism for all custom elements,
preventing a flash of unstyled content (FOUC) on server-rendered or static pages.
- Hides all `c-*` component tags until their JS registers, with a CSS-driven
fail-open reveal after 3 seconds to ensure content degrades to readable
unstyled form if the bundle never loads.
- The list of component tags is dynamically derived from `src/components`
directory names.
- Form-field shells retain their explicit geometry rules to prevent layout shift
upon upgrade.
- Defines related terminology ("pre-upgrade window/placeholder", "fail-open
reveal") in `CONTEXT.md`.
…0024)
Implements ADR-0024, changing TypeScript flavor examples from single imperative `.ts` modules to a markup fragment (`.html`) paired with an optional wiring script (`.ts`).
This rearchitecture significantly improves example readability by:
- Separating the example's HTML structure from its imperative wiring logic.
- Reducing verbosity and focusing the `.ts` file on actual script interactions.
Key changes include:
- A new ADR-0024 documenting the decision and its consequences.
- Updates to `CONTEXT.md` and `docs/adr/0020-docs-flavor-system.md` to reflect this amendment.
- Modifications to `ExampleBlock.vue` and `useExamples.ts` to parse and render multi-pane variants with "Template" and "Script" labels.
- Refactoring all existing TypeScript examples into `.html` and (optional) `.ts` files.
- Updates to `scripts/check-example-parity.mjs` to enforce the new file structure.
- Minor styling adjustments, including converting value read-out `` to `` for improved layout.
Removes the explicit `h-full` class from the vertical divider variant.
`self-stretch` only applies when the cross-size (height in this case) is `auto`. An explicit `h-full` class overrides `auto`, causing flexbox to fall back to `start` alignment and rendering `self-stretch` inert. Removing `h-full` allows `self-stretch` to function as intended, ensuring the divider occupies the available height.
Adjusts `primary`, `primary-hover`, and `ring` color tokens to lighter shades.
This refinement improves visual consistency and aligns with evolving design specifications within the dark theme.
Implements two key architectural decisions:
ADR-0025 "The sliding indicator is a tab-strip affordance" moves the visual sliding indicator from `c-button-group` to `c-tab-buttons`. This clarifies distinct roles: `c-button-group` acts as a pure value control where active buttons paint their own look, while `c-tab-buttons` owns the tab-strip visual affordance.
ADR-0026 "Component descriptions live in usage.md" formalizes `usage.md` as the single source of truth for component descriptions. The first paragraph of `usage.md` now serves as the component's description everywhere (docs, IDE hovers), and SFC docblocks are reserved for tags only. This includes creating `usage.md` files for components that previously stored descriptions in their SFC docblocks.
This commit also includes a broad cleanup of explicit ADR-XXXX references in comments across the codebase, as these architectural decisions are now considered foundational.
This commit completes the major rewrite of the component library, transitioning
the core from Stencil to Vue SFCs compiled to native custom elements. The
`@cscfi/csc-ui-next` package is now renamed to `@cscfi/csc-ui` and released
as version 4.0.0, establishing a new foundation for future development.
Key changes include:
- **Component Library Rewrite**: Complete replacement of the Stencil
implementation with Vue SFCs compiled to custom elements. This is a breaking
change, preserving all 73 component tags but with updated APIs, native Vue
`v-model`, CSS `::part()` for styling, and semantic design tokens with dark
mode.
- **Package Name Takeover (ADR-0027)**: The rewrite takes over the
`@cscfi/csc-ui` npm package name, releasing as 4.0.0. The React wrapper,
`@cscfi/csc-ui-react`, is now generated from the Custom Elements Manifest
onto `@lit/react` and is version-locked to the core package. Old
`@cscfi/csc-ui-vue` and `@cscfi/csc-ui-vue2` directive wrappers are retired.
- **Changeset-Driven Releases (ADR-0028)**: The release process is fully
rearchitected to use Changesets instead of commit-message-driven `release-please`.
This provides explicit version bumps, fixed package groups, a mandatory CI
check for changesets in PRs, and leverages npm trusted publishing (OIDC).
- **Documentation Overhaul**: The documentation site is completely refactored
to consume the new Vue-based `@cscfi/csc-ui` package and reflects the new
architecture, including updated examples and API references.
- **Codebase Cleanup**: The entire Stencil codebase and related tooling,
along with obsolete Vue 2/3 wrapper packages, have been removed.
The bulk -next rename left the guide telling readers to remove
@cscfi/csc-ui and reinstall the identical name. Rework it around the
real story (ADR-0027): same package, new major version. Version-based
before/after labels, pnpm add @cscfi/csc-ui@^4 instead of
remove-and-reinstall, and a corrected page header. Also point a
nuxt.config comment at the surviving root dev script.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Delete c-row, c-spacer, c-swiper and its composed child c-swiper-tab
from the library. Regenerate the manifest (68 components), tag map, IDE
data and the React wrapper. Drop the components' docs examples; the
c-toolbar example now pushes its trailing button with
margin-inline-start auto instead of c-spacer. The migration guide and
the 4.0.0 changeset list the removals with replacements.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The first releases after merging to main publish as 4.0.0-alpha.N under
the npm dist-tag "alpha" (latest stays 3.0.19) so the rewrite can be
tested in real projects. Graduating to the final 4.0.0 is
`pnpm changeset pre exit` plus a commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@netlify

netlifyBot commented Aug 13, 2026

Copy link
Copy Markdown

Deploy Preview for csc-design-system failed.

NameLink
🔨 Latest commit50c4e87
🔍 Latest deploy loghttps://app.netlify.com/projects/csc-design-system/deploys/6a7d5c5176a16f0008cd8cb3

@villeerikssoncsc
villeerikssoncsc merged commit 1f943e2 into mainAug 13, 2026
2 of 6 checks passed
@razorfever
razorfever deleted the vue-migration branch August 13, 2026 09:38
Sign up for freeto 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.

2 participants

@villeerikssoncsc@razorfever