Zudo Token Panel

Type to search...

to open search from anywhere

Panel CSS tokens

このページはまだ翻訳されていません。原文のまま表示しています。

--tokentweak-* private variables, the self-contained dark palette baked into panel-tokens.css, the modal data-attribute selector, and the paired stylesheet/host-adapter import obligations.

The panel ships its own bundled CSS — no Tailwind dependency in the consumer, and no reads against the host’s --color-* theme. This page pins the panel-private --tokentweak-* namespace, the self-contained dark palette the panel paints with, the bundled stylesheet’s modal-selector contract, and the panel-private override surface for hosts that want a different chrome theme.

Panel-private namespace

The bundled stylesheets declare every panel-chrome variable under a panel-private namespace, scoped to the panel shell + modal class prefix:

:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
  --tokentweak-pad-md:;
  --tokentweak-gap-sm:;
  --tokentweak-text-body:;
  --radius-tokentweak:;
  /* …every panel-chrome value lives here */
}

Naming rules

  • --tokentweak-* is the only allowed prefix for panel-private vars. No consumer-namespaced identifiers may appear in the panel chrome.
  • The chrome stylesheet (panel.css) MUST read only --tokentweak-* — it MUST NOT read host vars like --color-* or --font-mono directly.
  • The token sheet (panel-tokens.css) declares the --tokentweak-* values as concrete colors (no var(--color-*) reads) so host theme changes cannot bleed into the panel chrome. See the self-contained palette below.

Files

  • panel.css — chrome layout / typography / controls.
  • panel-tokens.css — the --tokentweak-* declarations.

Both ship from the package, combined into a single dist/zdtp.css by the Vite library build. Vite library mode strips the source import './styles/panel.css' from the emitted JS, so the consumer MUST import the combined stylesheet exactly once on their static module graph (typically next to where they mount <DesignTokenPanelHost>):

import '@takazudo/zdtp/styles';

The ./styles sub-export (alias ./styles.css) resolves to dist/zdtp.css. Skipping this import leaves the panel JS fully functional but every chrome rule missing — .tokenpanel-shell renders with the host page’s transparent background and default font, so the panel appears invisible.

⚠️ No Tailwind dependency

The package MUST build and run without Tailwind in the consumer. The panel JSX uses hand-authored CSS classes backed by --tokentweak-* vars exclusively.

PanelConfig.modalClassPrefix controls the BEM root for every modal the panel owns (export, import, apply). The host picks any string and the panel emits classes like ${modalClassPrefix}__overlay, ${modalClassPrefix}__panel, ${modalClassPrefix}__header, etc.

The bundled CSS keys on the data attribute, NOT on the class prefix. Every modal <dialog> element emits data-design-token-panel-modal="" (with data-design-token-panel-modal-variant set to "apply" / "export" / "import"). panel.css anchors all modal chrome rules on [data-design-token-panel-modal] and matches sub-elements via [class*='__title']-style attribute selectors.

This means a host that customises modalClassPrefix still inherits the bundled chrome — selecting on the literal class prefix would leave any non-default host with unstyled modals.

The class prefix remains useful as a higher-specificity hook for hosts that want to layer custom rules on top of the bundled chrome.

Self-contained panel chrome palette

The panel-chrome color tokens are declared in panel-tokens.css as concrete dark-palette values. The panel reads NOTHING from the host’s --color-* / --font-mono theme — host theme changes (including theme tweaks driven through this very panel in a demo) cannot bleed into the panel chrome:

:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
  --tokentweak-color-fg: #b8b8b8;
  --tokentweak-color-bg: #181818;
  --tokentweak-color-muted: #888888;
  --tokentweak-color-surface: #1c1c1c;
  --tokentweak-color-accent: #d69a66;
  --tokentweak-color-accent-hover: #a7c0e3;
  --tokentweak-color-code-bg: #383838;
  --tokentweak-color-code-fg: #e0e0e0;
  --tokentweak-color-success: #93bb77;
  --tokentweak-color-danger: #da6871;
  --tokentweak-color-warning: #dfbb77;
  --tokentweak-font-mono: Menlo, Monaco, Consolas, 'Liberation Mono',
    'Courier New', monospace;
}

The palette mirrors a terminal-style “Default Dark” scheme — low-saturation neutrals with a warm accent and a cool accent-hover — so the panel reads as a separate dark surface on top of any host backdrop.

Public surface

These are the panel-private variables a host MAY override on the same scope to retheme the panel chrome:

| Variable | Default | Role | | --- | --- | --- | | --tokentweak-color-fg | #b8b8b8 | Foreground text. | | --tokentweak-color-bg | #181818 | Panel background. | | --tokentweak-color-muted | #888888 | Muted text and dividers. | | --tokentweak-color-surface | #1c1c1c | Raised surfaces (cards, modals). | | --tokentweak-color-accent | #d69a66 | Primary actions and highlights. | | --tokentweak-color-accent-hover | #a7c0e3 | Hover state for accent surfaces. | | --tokentweak-color-code-bg | #383838 | Inline / block code background. | | --tokentweak-color-code-fg | #e0e0e0 | Inline / block code foreground. | | --tokentweak-color-success | #93bb77 | Success state colour. | | --tokentweak-color-danger | #da6871 | Danger / error state colour. | | --tokentweak-color-warning | #dfbb77 | Warning state colour. | | --tokentweak-font-mono | system monospace stack | Monospace font for code / values. |

Override surface for hosts

A host that wants a different chrome theme assigns directly to the --tokentweak-* names on .tokenpanel-shell, [data-design-token-panel-modal], or any ancestor (the panel scope uses :where() so specificity is 0):

:root {
  --tokentweak-color-bg: #102030;
  --tokentweak-color-fg: #eef;
  --tokentweak-color-accent: #ffb74d;
}

This is the entire host-override contract for panel chrome. --color-* and --font-mono are NOT part of the override surface — assigning to them on the host page has no effect on the panel.

Invariant — the panel package MUST NOT read host theme vars

Neither panel.css nor panel-tokens.css may reference --color-* or --font-mono. The package’s CI pins this with grep checks:

grep -n 'var(--color-' src/styles/panel.css        # → 0
grep -n 'var(--font-mono' src/styles/panel.css     # → 0
grep -n 'var(--color-' src/styles/panel-tokens.css # → 0
grep -n 'var(--font-mono' src/styles/panel-tokens.css # → 0

ℹ️ Why no host theme reads?

The panel is a developer tool that ships inside a host page. If the panel inherited the host’s --color-* tokens, any host theme change — including theme tweaks driven by the panel itself in a demo — would recolor the panel chrome along with the host. The dev tool would visually merge with the surface it is debugging, which is the opposite of what a dev tool should do. Keeping the palette self-contained makes the panel a stable visual anchor regardless of host theme state.

Host-adapter side-effect import (paired-unit obligation)

Alongside the ./styles import, the consumer MUST also own a side-effect import for the host-adapter, paired with <DesignTokenPanelHost>. The component AND a sibling <script> block loading @takazudo/zdtp/astro/host-adapter are a single unit — both lines are required, always together.

Required wiring shape:

<DesignTokenPanelHost config={myPanelConfig} />

<script>
  void import('@takazudo/zdtp/astro/host-adapter');
</script>

Why a dynamic void import('...')?

Both forms work — the package’s package.json lists dist/astro/host-adapter.js in sideEffects so Rollup preserves consumer-side imports of the host-adapter regardless of whether the result is used. The dynamic form is the recommended canonical wiring because it loads the host-adapter chunk off the critical page-load path (mirrors the existing color-presets lazy-loader pattern) and is robust to future packaging changes that could miss-configure sideEffects.

Why not a single page-level static import?

Browser caching makes the duplicated import() cheap (one network fetch per session), and the wrapper component is the single authoritative mount point so duplicating the import there is a non-issue.

What happens if you skip it?

Skipping this import leaves the JSON config payload from <DesignTokenPanelHost> on the page with no JS to read it, so calling window.<consoleNamespace>.showDesignPanel() throws ReferenceError. Symptom in deployed builds: silent failure, no panel chrome ever paints.

The ./astro/host-adapter sub-export points at the built dist/astro/host-adapter.js file plus its .d.ts types.

Consumer-controlled tokens

The tokens the panel writes to (the cssVar field on each TokenDef, plus the cluster’s paletteCssVarTemplate, base-role names, and semantic-CSS names) are entirely consumer-controlled. Hosts pick names like --myapp-spacing-hgap-md, --myapp-p0, --myapp-semantic-bg themselves; the panel just writes them through setProperty on :root.

The package contract is therefore:

  • Read: the panel never reads consumer CSS variables (it carries its own defaults via TokenDef.default).
  • Write: the panel only writes the consumer-supplied cssVar strings, one per overridden token, plus the cluster’s palette / base / semantic vars on apply.

Cross-references

Revision History