Skip to content

Adds new UI components and updates tooling - #309

Merged
villeerikssoncsc merged 15 commits into
mainfrom
development
Oct 22, 2026
Merged

villeerikssoncsc merged 15 commits into
mainfrom
development

Conversation

@razorfever

Copy link
Copy Markdown
Contributor

This pull request introduces two major new UI components and significantly upgrades the project's development tooling.

New Components:

  • c-color-picker: Adds a versatile color picker, enabling users to type any CSS color or interact with a comprehensive panel featuring a color area, hue/alpha sliders, per-channel inputs, and customizable swatches (ADR-0069, ADR-0070). It supports different output notations (hex, rgb, oklch) and transparent colors, with an intuitive comparison feature in the panel and dedicated options for swatch-only selection.
  • c-file-upload: Implements a robust file upload component, allowing users to add files via drag-and-drop or file dialog (ADR-0071). It provides individual progress tracking, size/type/count validations, and configurable upload functions for handling server-side logic. Supports a compact display mode and lists rejected files with clear reasons.

Tooling & CI Enhancements:

  • Migration to Oxc Toolchain: Transitions the project's linting and formatting from ESLint/Prettier to the faster and more integrated oxlint and oxfmt tools (ADR-0068). ESLint is now specifically scoped to Vue template rules.
  • Improved Code Consistency: Enforces a unified code style, including Tailwind class sorting, and stricter linting rules across the codebase.
  • Enhanced Developer Experience: Updates VS Code and DevContainer configurations to leverage the new tooling, promoting automatic formatting and linting fixes on save.
  • Streamlined CI: Adjusts the CI pipeline to execute format and lint checks earlier, allowing for faster feedback loops. Mechanical formatting and autofix commits are now ignored in git blame.

Core Improvements & Fixes:

  • Page Typography Inheritance: Ensures all components consistently inherit the application's typography settings (font family, line height, font features) from the host page, resolving issues where slotted content would default to system fonts (ADR-0072). The --c-font-family token has been removed.
  • Autocomplete & Tree-Select Input Fix: Resolves a bug in c-autocomplete and c-tree-select where characters typed into a closed field could be lost during panel opening, ensuring accurate input.
  • c-button Refactor: Removes an unnecessary min-w-max utility, optimizing the component's styling.

razorfever and others added 15 commits October 6, 2026 10:33
…t for Vue templates

One root config per tool replaces the two package ESLint and Prettier
setups (ADR-0068). oxlint lints every script, running perfectionist and
@Stylistic as jsPlugins; ESLint keeps only the vue/* template rules oxlint
lacks; oxfmt formats packages/ and sorts Tailwind classes. Root `pnpm lint`
runs oxlint, ESLint, the guards (csc-ui's `lint` is now `lint:guards`) and
the docs example parity. A check-only pre-commit hook, CI steps and VS Code
and Zed settings enforce it.

Committed with --no-verify: the tree is reformatted and autofixed in the
next commits, before which the new hook rejects it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…scards

The root slot listed min-w-max before min-w-22; tailwind-merge keeps only
the last of two conflicting utilities, so min-w-22 has always won. Sorting
the classes (ADR-0068) would have put min-w-max last and made it win.

Committed with --no-verify: the file is reformatted in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mechanical (ADR-0068): `pnpm format`. Every changed string is a
permutation of its old tokens, tailwind-merge resolves each the same way
as before, and tailwind.css compiles to identical utilities. Templates are
unchanged apart from class order.

Committed with --no-verify: lint autofixes follow in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mechanical (ADR-0068): `oxlint --fix` until stable, `eslint --fix .`, then
`pnpm format`. Mostly perfectionist ordering (both packages, the docs
examples and their flavor variants), blank lines from @Stylistic, and
template attribute order. No Map, Set or switch order changed, and no
reordered object literal is iterated for its key order.

.oxlintrc.json lets consecutive require() lines stay together, which the
blank-line-before-const rule otherwise splits against sort-imports.

Committed with --no-verify: the remaining findings are fixed by hand in
the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Keep the five Set snapshots unicorn/no-useless-spread flags: each loop
  deletes from the set it walks, so the copy is deliberate (annotated).
- TypedField writes the refs of its useTypedField handle by design; scope
  vue/no-mutating-props off around those writers, as c-pagination does.
- Drop createTheme.cjs's unused setValue require, and import vite's Plugin
  type instead of an inline import() annotation in nuxt.config.ts.
- The framework-free TypeScript example variants keep a state variable the
  listener writes and the reader's app would read: no-unused-vars is off
  for them, so no directive shows in the docs code tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A user-level "[vue]" default formatter (Vue.volar) outranks the generic
workspace `editor.defaultFormatter`, so saving a .vue file ran the Vue
extension's formatter instead of oxfmt. Language-specific workspace
settings outrank language-specific user settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
VS Code merges a single-language block ("[vue]") after every
multi-language block ("[css][vue]") at any scope, so a user-level
"[vue]" formatter (Vue.volar) still beat the workspace's combined
block. A workspace "[vue]" merges with the user's and wins as the
narrower scope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`@stylistic/lines-around-comment` (beforeBlockComment), with the first
comment in a block, object, class, interface, type, enum or module
exempt. Autofix added 702 blank lines in 88 files, nearly all between a
typed member and the next member's doc comment.

Two spec files kept their file docblock between imports, which the new
rule and sort-imports' spacing then fought over: CBreadcrumb.spec.ts
(the 7526707 autofix sorted an import above it) and
monotonicClock.spec.ts. Both docblocks move to the top of the file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A value control for one colour, built on the typed-field shell the date
and time pickers use (ADR-0070). The field takes any CSS colour typed
into it and commits it re-spelled in the picker's notation; unparseable
text is bad input. The value is a string in `format` — `hex` (default),
`rgb` or `oklch` — and every colour it holds is 8-bit sRGB, each
notation spelling the same bytes at the fewest decimals that round-trip
(ADR-0069). A colour outside sRGB is mapped into it, not rejected, and
`alpha` opts into transparency.

The colour button or Alt+ArrowDown opens a panel: a saturation ×
brightness area that is one Tab stop with arrow keys on both axes, hue
and alpha sliders, a HEX | RGB | OKLCH switch that picks the channel
inputs shown (a view only, never the value), swatches, and a strip that
shows the original colour beside the new one. A discrete pick commits at
once and the panel stays open; a drag fires update:value and input on
each move and change once on release. On a narrow viewport the
fullscreen panel holds a pending value until Done.

`swatches` offers predefined colours, named for assistive technology;
`swatches-only` makes the field a readonly, select-like one whose panel
is the swatch grid, and a pick there commits and closes.

The typed-field shell now runs without a mask, and emitModelInput and
emitModelSettled join emitModelChange for the drag's split emissions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ogress

A value control holding a list of file entries: files the user drops on
it or chooses through its drop zone, and server files the consumer
supplies (ADR-0071). Each entry has an id, a name, a size, a type, the
browser File when there is one, and a status — local, queued,
uploading, done or error. The value is always a list; `multiple` lets a
pick add files instead of replacing the one entry.

The field never sends a byte itself. `upload` is the consumer's
function, called once per file with an abort signal and a progress
callback; the field runs at most three at once and shows each file's
size, progress and outcome, with cancel, retry and remove on its row.
Without one the field only holds the files, and a `manual` field holds
them until `startUploads()` starts them. The value events fire on an
add, a removal, a retry, a start, and once when each upload settles —
never on progress.

`accept`, `max-size` and `max-files` limit what the field takes, and a
file it already holds is refused. A refused file shows as a rejected row
with its reason until the list next changes, is announced, and is
reported by the `reject` event. The whole component takes a drop, so a
near miss never opens the file in the tab, and `:state(drag-over)`
shows the drag. `compact` turns the drop zone into a row at the control
height. Rows carry one of eight outline file-type icons, and sizes are
decimal units in the page's language.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… closed field

A printable key on the closed value field opened the panel and seeded the
search input a frame later, while the query open-reset ran in the queued
`toggle` task. Whichever ran last won, so `finland` could search `inland`,
and keys typed before the deferred focus landed on the readonly field and
were dropped.

The open-reset now runs in a new `useAnchoredPanel` `onOpening` hook,
right before `showPopover()`, and the keydown moves focus to the search
input synchronously so the browser types the key — and every key after it —
into it natively. A typed open highlights the first match, as typing into
the open panel does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every host took Tailwind preflight's `html, :host` rule: the system font
stack, a 1.5 line height and reset font features. Every host also carried
Tailwind's theme variables from `:root, :host`. Slotted content inherits
through the flat tree, so text in `c-main` and other components ignored the
app's font. Nested hosts such as `c-select`'s option list were out of the
page's reach, and an app's own Tailwind `font-sans` or `p-4` inside a
component read csc-ui's values.

The shared `:host` rule now passes the page typography through. Tailwind's
theme is imported inline, so no theme variable is declared on a host, and
the library's control height, toolbar height and easing live on private
`--_c-` properties. The `--c-font-family` token is removed (ADR-0072). A new
all-components conformance check holds every host to the page's
typography. The test page now sets the stack and line height the hosts used
to force, so only one baseline moves: c-autocomplete's marked row, whose
nested option host now takes the row's own leading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The VS Code theme's activity bar and tab backgrounds are darkened, with adjusted tab borders and dividers for a more consistent dark mode appearance.

The main content area in the documentation application now has an increased maximum width. Redundant home icons have also been removed from the breadcrumb folding example.
Components inherit the page typography since ADR-0072, and csc-ui's
harness page took over the font stack and 1.5 line height the hosts
used to force. The docs example smoke kept its own copy of that page
rule without them. Its canons fell back to the browser's normal
leading, and c-card, c-radio-group, c-switch and c-tabs no longer
matched their baselines in CI.

The smoke now loads csc-ui's harness.css instead of the copy, so the
two test pages cannot drift apart again. That matches the docs demo
pane, which renders at 1.5. Six canons print a light-DOM "Value:"
line outside their components, which the old baselines captured at
normal leading. Their baselines are refreshed: c-checkbox,
c-data-table, c-select, c-switch, c-text-field and c-tree-select.
The components render unchanged; only that line moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@villeerikssoncsc
villeerikssoncsc merged commit fe6c4c8 into main Oct 22, 2026
3 checks passed
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.

2 participants