Haifai-AI/baby-whale--packages-client-ui-theme ↗★ 1

@deepseek-ai/dsh-client-ui-theme

Theme plugin: Host bootstrap for the pre-plugin palette; DOM-free ThemeRuntime for light/dark/system state; --dsw-* token styles and Appearance settings row 适合需要系统级主题响应、自定义色彩标记和外观设置的用户。

パッケージ
@deepseek-ai/dsh-client-ui-theme
互換性
未検証
Harness ピア範囲
workspace:^
Cordis ピア範囲
workspace:^
バージョン
0.2.0-preview.1
ライセンス
MIT
最終更新
2026/09/17

同名パッケージの別リポジトリ

インストール

検証済み bundle がないか、互換性チェックに失敗しています。先にリポジトリの説明を読んでください。 README 全文を読む ↗

ドキュメント

README 全文を読む ↗

@deepseek-ai/dsh-client-ui-theme

English | 中文

Theme plugin: ThemeRuntime over the --dsw-* token base stylesheets (static scale + alias semantic layers). The service owns the live theme preference (light/dark/system), resolves system through prefers-color-scheme, and publishes immutable ThemeSnapshots on the theme/change event; it never touches the DOM — ui-layout's presenter applies the resolved snapshot (html { color-scheme }, body[data-ds-dark-theme], and inline alias tokens). A loopback browser provides the service immediately with system, then loads ui-theme.preference in the background and writes each built-in selection through the Host settings API, whose local provider stores it in $DSH_HOME/settings.yaml by default; pushed settings changes and reconnects refetch it, rapid selections are serialized in gesture order with namespace revisions, and a rejected latest write reloads the durable value. A remote browser cannot access the privileged settings API, so its selection remains process-local. Third-party registered theme ids remain an in-process extension and do not cross the built-in settings schema; removing one never overwrites the last durable built-in preference. The Host-backed preferences decision owns the persistence boundary.

When the host composition includes an HTTP server, the host half injects a synchronous bootstrap immediately after the opening `` tag. Each index response embeds the registered Host setting for ui-theme.preference, or system when no settings provider is present; the browser resolves system from the OS scheme, then sets color-scheme and body[data-ds-dark-theme] before the shell loading page renders. Compositions without an HTTP server remain unaffected, and ThemeRuntime and ui-layout remain authoritative for client state and subsequent DOM updates after the plugin tree activates.

src/styles/ holds six sheets imported in order by ui-theme's dynamic client entry: base.css, design-platform.css, scrollbar.css, surfaces.css, gradient-shadow-text.css, and shiki.css. The client bundle compiles and injects them as plugin-owned global styles, so unload and HMR remove them with ui-theme instead of leaving theme CSS in the static web shell. scrollbar.css is the sole consumer of the --dsw-alias-scrollbar-* tokens and must follow design-platform.css, which declares them.

design-platform.css is layered, and the layers are the contract. At the bottom sits the raw palette (--dsw-static-*, exported from the upstream Figma variable set); above it a closed neutral ramp (--dsw-gray-00 … --dsw-gray-95, declared per palette) and the accent/state inks (--dsw-accent*, --dsw-state-*); at the top the semantic aliases feature CSS consumes. Feature stylesheets read aliases only — a --dsw-static-* or --dsw-gray-* reference in a feature sheet is a surface that has not migrated yet. The light and dark blocks are independent palettes rather than inversions: dark places chrome above the canvas and re-picks its label steps for a dark ground.

base.css declares the fixed scales the alias layer and feature CSS share: the font stacks, the six-step corner scale (--dsw-radius-xs … -full), and the motion tokens (--ds-ease-out, --ds-ease-in-out, and the three durations). There is deliberately no overshoot or elastic curve. gradient-shadow-text.css owns the elevation ladder (--dsw-shadow-lv1/2/3, each a hairline plus a contact and an ambient shadow, with a dark override for all three), the two material fills, and the typography roles.

Two rules bind how the accent is spent, and both are enforced by review rather than by a gate. The accent appears at most once per column at rest — a sidebar shows one selected row, a settings panel one selected nav cell and one primary button, never both. And a selected item takes the accent as its fill with inverted ink, setting color: var(--dsw-alias-label-primary-foreground) so descendants drawing in currentColor invert with it.

surfaces.css themes the surfaces the browser draws rather than a component: ::selection, caret-color, accent-color for the UA-painted form controls, and the default keyboard-focus ring for :focus-visible. All of them resolve from the alias layer, so it too follows design-platform.css — a custom property substitutes against the cascade position of the rule that reads it, not sheet order alone. The focus ring's three values (--dsh-focus-ring-width, --dsh-focus-ring-offset, --dsh-focus-ring-color) are declared on body beside the ring rule and are the shared spelling for feature CSS that draws its own ring.

Scrollbar rebinding contract: scrollbar.css binds --dsh-scrollbar-thumb and --dsh-scrollbar-thumb-hover on body to the l1 (base-surface) tokens, and both rendering paths read that pair. An elevated surface (menu, popover, dialog) sets --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2) and --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2) on its own container; one rebind retints whichever path the engine took. The pair's other legal target is transparent, which draws no thumb at all — ui-sidebar rebinds its column that way while the pointer is elsewhere. A rebind to the l1 pair is not a rebind; it restates the base-surface default. --dsh-scrollbar-width mirrors the WebKit bar's layout width for surfaces that align themselves beside a space-consuming bar — ui-conversation reads it for the overlay composer seat's right offset — and the scrollbar-styles spec pairs it with the mirrored rule and the consumer.

The two paths are mutually exclusive by construction. scrollbar-width/scrollbar-color sit inside @supports not selector(::-webkit-scrollbar) because a non-auto value of either makes Chromium and Safari discard every ::-webkit-scrollbar* rule for that element, ::-webkit-scrollbar-thumb:hover included — declaring both unconditionally leaves --dsh-scrollbar-thumb-hover with no rendering anywhere. Firefox therefore takes the standard properties and WebKit-based engines take the pseudo-elements, so the hover token only ever renders through the pseudo-element path. Reasoning and the measured computed values: the scrollbar Agent Note.

Model Experience

None, as the theme service manages a browser preference; nothing here reaches a model request.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • Third-party themes are an extension point, not a product — registering one means overriding same-named alias variables; no validation exists that an override set is complete.
  • The token sheets are the sole color authority — a colour a feature sheet needs is added here as a ramp step plus a semantic alias in the same change, never written as a literal at the call site. The retina asset the sheets were originally exported from is no longer the source of truth; the ramp is.
  • The light palette cannot support a third label step above AA — on the sidebar's own fill a neutral must sit at or under ~112 to clear 4.5:1, so --dsw-alias-label-caption and -tertiary resolve to the same value in light and separate in dark. -quaternary, -dimmed, and --dsw-alias-separator-primary are decoration and must never be the only carrier of a meaning. Components that relied on caption and tertiary differing separate them by size or weight instead.
  • backdrop-filter is a layout decision as well as a visual one — it establishes a containing block for position: fixed descendants, and ui-primitives' Menu portal mode positions itself from an anchor's viewport rect. The blur therefore stays on leaf layers that host no portaled menu (the dialog scrim, the toast); a column or a card that contains a picker must not take one.
  • --dsw-static-* has no feature-CSS consumers left, but the palette remains declared — ansi.ts reads the raw blue steps for terminal colour, and the Office previews read the file-kind and document-surface aliases derived from it. Deleting the raw layer would turn any surviving reference into a silently invalid value rather than an error.