Zudo Token Panel

Type to search...

to open search from anywhere

Token tiers (tab manifest)

TabConfig, TierConfig, TierItem, TierValueKind, PillSpec, and ColorClusterExtras — the types that define every editable tab in the panel.

ℹ️ Concept overview

This page is the type-by-type pin-down of the tier model. If you want to understand the design rationale and the literal / reference tier relationship first, read The abstract token-tier model.

The panel renders its tab strip from a flat array of TabConfig objects passed as PanelConfig.tabs. Each tab owns one or more tiers of editable rows; a tier can hold literal values or references to another tier’s items. This page pins every public type in the tier model.

TierValueKind

Discriminated union that controls which editor widget appears for a row.

export type TierValueKind =
  | { kind: 'length'; step: number; unit: string }
  | { kind: 'number'; step: number }
  | { kind: 'select'; options: readonly string[] }
  | { kind: 'text' }
  | { kind: 'color' }
  | { kind: 'cursor' }
  | { kind: 'content' }
  | { kind: 'mask-image' };

| kind | Description | Editor | Extra required fields | | --- | --- | --- | --- | | 'length' | Dimension values with a unit | Text input with a unit suffix (e.g. rem, px) | step, unit | | 'number' | Unitless numeric values | Unconstrained text input | step | | 'select' | Predefined option sets | Dropdown | options (non-empty array of strings) | | 'text' | Free-form CSS expressions (easing curves, font families, raw strings) | Free-form text input | — | | 'color' | Color values — used for palette tiers in the Color tab | Color picker | — | | 'cursor' | cursor property values (keywords like pointer, crosshair, or url(...) <fallback>) | Free-form text input | — | | 'content' | content property values for pseudo-elements (quoted strings, none, normal, url(...), generated-content functions) | Free-form text input | — | | 'mask-image' | mask-image property values (none, url(...), gradient functions) | Free-form text input | — |

All items in a given TierConfig.items array MUST share the same kind. Mixing kinds inside a single tier is rejected at validation time.

PillSpec

Optional pill toggle that supplements the main input for a single TierItem.

export interface PillSpec {
  /** Sentinel value emitted when the pill is ON (e.g. `"9999px"` for border-radius-full). */
  value: string;
  /** Default CSS value used when the pill is OFF and no override is active. */
  customDefault: string;
}

When a TierItem carries a pill, the tier resolver interprets the override map as follows:

  • Override equals pill.value → emit the pill sentinel verbatim.
  • No override → use pill.customDefault as the baseline (not item.default).
  • item.default is only reached when neither an override nor a customDefault apply.

TierItem

One editable row inside a tier.

export interface TierItem {
  /** Stable id used as the key in persisted state. Rename = state loss. */
  id: string;
  /** CSS custom property written to `:root` (must start with `--`). */
  cssVar: string;
  /** Human-visible label rendered in the panel row. */
  label: string;
  /** Optional group id — used by some tab components for section headers. */
  group?: string;
  /** Default CSS string value — used when no override is active. */
  default: string;
  /** Discriminated union controlling the edit widget. */
  type: TierValueKind;
  /** Opt-in sentinel-value toggle. */
  pill?: PillSpec;
  /** Display-only flag — the row is rendered but not editable. */
  readonly?: true;
}

Field reference

| Field | Required | Notes | | --- | --- | --- | | id | yes | Stable key in the persisted override map. Renaming breaks existing user state unless legacyIdRenameMap is configured. | | cssVar | yes | The CSS custom property written to :root. Must start with -- and be non-empty after the prefix; validated by assertValidPanelConfig. | | label | yes | Display label inside the panel row. | | group | no | Section header grouping key. Some tab components render a heading for each unique group value. | | default | yes | Fallback CSS string emitted when no override is active. | | type | yes | Controls which editor renders for this row. | | pill | no | Adds an opt-in sentinel toggle alongside the main editor. | | readonly | no | When true, the row is shown but not editable and is skipped by the apply pipeline. |

TierConfig

A named group of TierItem entries within a tab.

export interface TierConfig {
  /** Stable id — must be unique within the parent `TabConfig`. */
  id: string;
  /** Human-visible label (e.g. "Raw values", "Semantic"). */
  label: string;
  /** The editable rows this tier owns. All items must share the same `kind`. */
  items: readonly TierItem[];
  /**
   * When set, this tier holds cross-tier references.
   * Each item's override value is interpreted as the id of an item in the
   * tier named by this field. The apply pipeline emits
   * `var(--that-tier-item-cssVar)` rather than the raw value string.
   */
  referencesTier?: string;
}

A tier with referencesTier is called a reference tier. Its items don’t hold direct CSS values — they hold the id of a source item in another (literal) tier. The referencesTier value must be the id of a tier that exists in the same TabConfig. The tier kinds must match (e.g. both 'color' or both 'length').

TabConfig

The top-level unit — one tab in the panel’s strip.

export interface TabConfig {
  /** Stable id. Reserved ids dispatch to built-in tab components. */
  id: string;
  /** Human-visible tab label. */
  label: string;
  /** Ordered tiers rendered inside the tab. */
  tiers: readonly TierConfig[];
  /**
   * Optional list of tier ids hidden behind the per-tab "Advanced" disclosure.
   * Any tier id listed here is rendered inside a collapsed `<details>` element.
   */
  advancedTiers?: readonly string[];
  /**
   * Color-tab metadata. Required for the reserved `'color'` and
   * `'color-secondary'` ids — ignored (and unnecessary) for all other ids.
   */
  colorExtras?: ColorClusterExtras;
}

Reserved tab ids

| id | Dispatches to | | --- | --- | | 'color' | Primary color tab — palette + base roles + semantic table. Requires colorExtras. | | 'color-secondary' | Secondary color tab. Requires colorExtras. | | 'font' | Typography tab. | | 'spacing' | Spacing tab. | | 'size' | Size tab. | | Any other string | GenericTab — renders the tab’s tiers using kind-appropriate editors. |

ColorClusterExtras

Non-tier metadata required by the Color tab. Sits on TabConfig.colorExtras for any tab with a reserved color id.

export interface ColorClusterExtras {
  /** Stable id forwarded to the internal ColorClusterDataConfig bridge. */
  id: string;
  /** Optional label for Color-tab section headings. Falls back to `id.toUpperCase()`. */
  label?: string;
  /** CSS custom-property names for base terminal roles. */
  baseRoles: Partial<Record<BaseRoleKey, string>>;
  /** Fallback palette indices when a scheme omits a base role. */
  baseDefaults: Partial<Record<BaseRoleKey, number>>;
  /** Fallback shikiTheme name when a scheme lacks one. */
  defaultShikiTheme: string;
  /** Bundled color-scheme registry keyed by display name. */
  colorSchemes: Record<string, ColorScheme>;
  /** Panel-level scheme settings (seed scheme, optional light/dark mode). */
  panelSettings: ClusterPanelSettings;
}

export type BaseRoleKey = 'background' | 'foreground' | 'cursor' | 'selectionBg' | 'selectionFg';

Example: single-tier spacing tab

A simple tab with one literal tier — every item is a length token:

import type { TabConfig } from '@takazudo/zdtp';

export const spacingTab: TabConfig = {
  id: 'spacing',
  label: 'Spacing',
  tiers: [
    {
      id: 'base',
      label: 'Base spacing',
      items: [
        { id: 'sp-xs', cssVar: '--myapp-spacing-xs', label: 'XS', default: '0.25rem', type: { kind: 'length', step: 0.125, unit: 'rem' } },
        { id: 'sp-sm', cssVar: '--myapp-spacing-sm', label: 'SM', default: '0.5rem',  type: { kind: 'length', step: 0.125, unit: 'rem' } },
        { id: 'sp-md', cssVar: '--myapp-spacing-md', label: 'MD', default: '1rem',    type: { kind: 'length', step: 0.25,  unit: 'rem' } },
      ],
    },
  ],
};

Example: two-tier easing tab (literal + reference)

A generic tab where a semantic tier references a raw tier. The panel emits var(--myapp-easing-ease-in) for a semantic item rather than a raw cubic-bezier string:

import type { TabConfig } from '@takazudo/zdtp';

export const easingTab: TabConfig = {
  id: 'easing',
  label: 'Easing',
  tiers: [
    {
      id: 'raw',
      label: 'Raw values',
      items: [
        { id: 'ease-in',    cssVar: '--myapp-easing-ease-in',    label: 'Ease in',    default: 'cubic-bezier(0.42, 0, 1, 1)', type: { kind: 'text' } },
        { id: 'ease-out',   cssVar: '--myapp-easing-ease-out',   label: 'Ease out',   default: 'cubic-bezier(0, 0, 0.58, 1)', type: { kind: 'text' } },
        { id: 'ease-inout', cssVar: '--myapp-easing-ease-inout', label: 'Ease in-out',default: 'cubic-bezier(0.42, 0, 0.58, 1)', type: { kind: 'text' } },
      ],
    },
    {
      id: 'semantic',
      label: 'Semantic aliases',
      // referencesTier causes the apply pipeline to emit var(--myapp-easing-*)
      // rather than the raw cubic-bezier string.
      referencesTier: 'raw',
      items: [
        { id: 'tab-open',  cssVar: '--myapp-transition-tab-open',  label: 'Tab open',  default: 'ease-in',    type: { kind: 'text' } },
        { id: 'tab-close', cssVar: '--myapp-transition-tab-close', label: 'Tab close', default: 'ease-out',   type: { kind: 'text' } },
        { id: 'modal',     cssVar: '--myapp-transition-modal',     label: 'Modal',     default: 'ease-inout', type: { kind: 'text' } },
      ],
    },
  ],
  advancedTiers: ['semantic'],
};

In this setup, overriding tab-open to 'ease-out' causes the apply pipeline to emit --myapp-transition-tab-open: var(--myapp-easing-ease-out) rather than the literal easing string.

Cross-references

  • <code>PanelConfig.tabs</code> — where TabConfig[] is plugged in.
  • Color cluster — how the Color tab derives a ColorClusterDataConfig from a TabConfig with colorExtras.
  • Apply pipeline — how the tier resolver turns overrides and cross-tier refs into CSS-var writes.
  • Grouped palette tab — worked example of a standalone Palette tab using multiple kind: 'color' tiers without colorExtras.

Revision History