@gainsight-hub/design-tokens

中文文档
0.5.1发布于 2026/10/29UNLICENSEDTypeScriptES Module零依赖近 30 天下载 3257

Design tokens: CSS variables, JSON, TypeScript constants, and a Tailwind v4 theme.

原始使用文档
文档目录17 节
  1. Install
  2. Quick start
  3. CSS custom properties
  4. Base (light theme)
  5. All themes bundled
  6. Individual themes
  7. Theme switching at runtime
  8. Token naming
  9. TypeScript / JavaScript
  10. Tailwind v4
  11. Component tokens (CSS Modules)
  12. JSON
  13. Token catalog
  14. Runtime theme switching
  15. Available exports
  16. Package structure
  17. Building and publishing

@gainsight-hub/design-tokens

Design tokens for the Gainsight Community Hub — CSS custom properties, TypeScript constants, JSON, and a Tailwind v4 theme.

Install

npm install @gainsight-hub/design-tokens

This package has no runtime dependencies and works on its own: plain CSS apps and SCSS apps (for example a server-rendered Preact destination) install only this package and import styles.css and a theme. tailwindcss (>= 3) is an optional peer, needed only for the Tailwind preset. Install @gainsight-hub/design-system or @gainsight-hub/theme-editor only if you need React components or the theme editor UI; both peer-depend on this package, so the app that owns the tokens also owns their version.


Quick start

Import styles.css once at your app entry point. That's it for most apps.

// main.js / main.ts
import "@gainsight-hub/design-tokens/styles.css";

Then use tokens anywhere via CSS custom properties:

.button {
  background: var(--color-action-primary-default);
  color: var(--color-content-inverse);
  border-radius: var(--button-radius);
}

CSS custom properties

Base (light theme)

Defines all tokens as CSS custom properties on :root. This is the default light theme.

import "@gainsight-hub/design-tokens/styles.css";

All themes bundled

Includes the base tokens plus all theme overrides in a single file. Use this if you want to switch themes at runtime without loading additional stylesheets.

import "@gainsight-hub/design-tokens/themes.css";

Individual themes

Load only the theme you need on top of styles.css:

import "@gainsight-hub/design-tokens/styles.css";
import "@gainsight-hub/design-tokens/themes/ocean.css";

Available themes — each ships both a light block ([data-theme="{name}"]) and a dark block ([data-theme="{name}"].dark), except legacy, which is light-only (it's the pre-migration compat bridge — see below):

Import pathDescription
@gainsight-hub/design-tokens/themes/ocean.cssOcean — blue palette
@gainsight-hub/design-tokens/themes/ember.cssEmber — warm orange palette
@gainsight-hub/design-tokens/themes/meadow.cssMeadow — green palette
@gainsight-hub/design-tokens/themes/violet.cssViolet — indigo palette
@gainsight-hub/design-tokens/themes/slate.cssSlate — cool-gray palette
@gainsight-hub/design-tokens/themes/legacy.cssPre-migration tenant customization bridge (light-only)

The base theme's own dark mode needs no extra import — it's already in styles.css, as a :where(:root:not([data-theme])).dark block alongside the light :root defaults (:where() keeps it at the same specificity as the light block, so runtime overrides still win).

Theme switching at runtime

data-theme always holds the selected theme's id (or is absent for the default theme); .dark is an independent, additive class for dark mode — never a value data-theme itself takes. Both live on document.documentElement.

/* A named theme, dark mode: */
/* (written :where([data-theme="ocean"]).dark in the generated files) */
[data-theme="ocean"].dark { /* ... */ }

/* The default theme, dark mode (no data-theme attribute): */
:root.dark { /* ... (generated as :where(:root:not([data-theme])).dark) */ }

/* Scope to a tenant / white-label */
[data-tenant="acme"] {
  --color-action-primary-default: #e63946;
  --button-primary-background-color-default: #e63946;
}

Token naming

Names are the public contract: a rename is a breaking change for theme overrides and customer styles.

LayerPatternExample
Theme inputs--theme-{scale}-{step}--theme-brand-700
Colour primitives--color-{palette}-{step}--color-brand-700, --color-neutral-a100
Semantic colours--color-{role}-{purpose}[-{state}]--color-action-primary-hover
Scales--{category}-{step}--space-200, --radius-100, --font-size-300
Type styles--text-{style}-{font-size|font-weight|line-height}--text-heading-small-font-size
Component tokens--{component}-{variant}-{property}-{state}--button-primary-background-color-hover
Component geometry--{component}-{property}--button-radius, --sidebar-radius

Rules for component tokens:

  • Name the CSS property, state last. Colours say which colour: background-color, border-color, content-color (text and icons), title-color, subtitle-color, icon-color, and border-top-color / border-bottom-color for single sides. --button-primary-background-color-hover, --sidebar-border-color-default. The state (default, hover, pressed) is always the last word.
  • Why -color: a bare background or border can be a colour, an image or a width. --widget-hero-background-image is an image, --sidebar-border-width is a width, --sidebar-border-color-default is a colour.
  • Other properties keep their own word: border-width, radius, shadow, font-family, font-weight, text-transform, height. A property with a single value takes no state suffix (--sidebar-radius).
  • A variant is part of the name, not a state: --button-vote-selected-background-color-default is the "voted" variant of the vote button, with its own default, hover and pressed states.
  • Namespaces: sidebar is a content-area widget, sidenav is the application-shell side navigation, and navigation is the top bar and its dropdowns.

Scales worth knowing:

  • Alpha: --color-neutral-a100 to a500 are neutral 1000 at 4, 8, 16, 32 and 48% opacity.
  • Line height: --line-height-ratio-* is a unitless multiplier (headings use tight, body and code use relaxed); --line-height-grid-* is a fixed rem value on a 4px grid (labels, caption, menu, navigation, button).
  • --font-size-base is in px on purpose. It is the root size every rem step derives from, and the theme editor's text-size setting writes it.

Every token carries a description, in the CSS comments and in token-catalog.json.


TypeScript / JavaScript

Import typed token constants directly. All exports are fully typed via the bundled tokens.d.ts.

import {
  ColorActionPrimaryDefault,
  ColorSurfacePage,
  RadiusFull,
} from "@gainsight-hub/design-tokens";

// Use in JS logic — e.g. canvas drawing, charting libs
ctx.fillStyle = ColorActionPrimaryDefault; // "#0C66E4"

Tailwind v4

Tailwind v4 only. Import the variables first, then the theme file, in your CSS entry:

@import "tailwindcss";
@import "@gainsight-hub/design-tokens/styles.css";        /* defines the CSS custom properties */
@import "@gainsight-hub/design-tokens/tailwind-theme.css"; /* maps them to Tailwind utilities */

tailwind-theme.css is an @theme inline block in which every entry is a var(--token) reference, so no value is duplicated. Change a token at any scope (for example with a theme) and every utility that uses it updates, with no rebuild.

<!-- Colours: the full token name, including -default -->
<div class="bg-action-primary-default text-content-inverse">Primary</div>
<div class="bg-surface-default text-content-default border border-line-default">Card</div>

<!-- Spacing, radius, elevation -->
<div class="p-space-200 gap-space-100 rounded-100 shadow-elevation-1">Layout</div>

<!-- Type styles: one class sets size, line height and weight -->
<h2 class="text-heading-small">Heading</h2>
<p class="font-sans text-body-medium">Body text</p>
Tailwind classCSS variable
bg-action-primary-defaultvar(--color-action-primary-default)
bg-surface-pagevar(--color-surface-page)
text-content-subtlevar(--color-content-subtle)
border-line-defaultvar(--color-line-default)
text-heading-small--text-heading-small-font-size, -line-height and -font-weight
font-sansvar(--font-family-sans)
leading-grid-100var(--line-height-grid-100)
rounded-100var(--radius-100)

The stock scale utilities (rounded-md, text-sm, p-3, shadow-lg) are bound to tokens too, so a theme can change shape, density and elevation.


Component tokens (CSS Modules)

For component internals, use CSS Modules with var() directly:

/* Button.module.css */
.root {
  background: var(--button-primary-background-color-default);
  color: var(--button-primary-label-default);
  border-radius: var(--button-radius);
  padding: var(--space-100) var(--space-200);
}

.root:hover {
  background: var(--button-primary-background-color-hover);
}
// Button.tsx
import styles from "./Button.module.css";

export function Button({ children }: { children: React.ReactNode }) {
  return <button className={styles.root}>{children}</button>;
}

JSON

Raw token values as nested JSON. Useful for tooling, build scripts, or non-web targets (e.g. React Native, Figma plugins).

import tokens from "@gainsight-hub/design-tokens/tokens.json" with { type: "json" };

const primary = tokens.color.action.primary.default.value; // "#0C66E4"
const gutter = tokens.space.layout.gutter.value;            // "12px"

Token catalog

Structured catalog with resolved values, descriptions, alias chains, and legacy mappings. Used by the design portal and design tooling.

import catalog from "@gainsight-hub/design-tokens/token-catalog.json" with { type: "json" };

// 224 tokens with cssVar, path, type, value, description, references, legacyMapping
catalog.all.forEach(token => console.log(token.cssVar, token.value));

Runtime theme switching

applyThemeConfig(config, mode) applies a saved ThemeConfig (theme id + any per-mode overrides) to the current page — synchronous, no page reload. It sets data-theme to the real theme id (or removes it for the default theme) and toggles the .dark class independently for mode, then injects the theme's own variables plus any overrides as CSS custom properties.

Requires the theme's own CSS to already be loaded (e.g. themes.css, or the specific themes/{name}.css you need) — this function only manages data-theme/.dark and layers config-level overrides on top; it doesn't fetch stylesheets.

import "@gainsight-hub/design-tokens/themes.css"; // base + all themes
import { applyThemeConfig } from "@gainsight-hub/design-tokens";

// Switch to Ocean, light mode
applyThemeConfig({ themeId: "ocean", overrides: { light: {}, dark: {} } }, "light");

// Same theme, dark mode
applyThemeConfig({ themeId: "ocean", overrides: { light: {}, dark: {} } }, "dark");

// Default theme + a custom brand color override
applyThemeConfig(
  { themeId: "gainsight-light", overrides: { light: { "--theme-brand-700": "#FF6600" }, dark: {} } },
  "light",
);

Available theme IDs: gainsight-light (default), ocean, ember, meadow, violet, slate, legacy.


Available exports

ImportDescription
@gainsight-hub/design-tokensapplyThemeConfig + TypeScript/JS named constants
@gainsight-hub/design-tokens/styles.cssCSS custom properties — base light theme
@gainsight-hub/design-tokens/themes.cssCSS custom properties — all themes bundled
@gainsight-hub/design-tokens/themes/*Individual theme overrides (load on top of styles.css)
@gainsight-hub/design-tokens/tailwind-theme.cssTailwind v4 @theme inline mapping (import after styles.css)
@gainsight-hub/design-tokens/tokens.jsonNested JSON — raw token values
@gainsight-hub/design-tokens/token-catalog.jsonFull catalog with resolved values, descriptions, alias chains

Package structure

packages/design-tokens/
├── src/                   Token source files (Style Dictionary format)
│   ├── primitive/         Raw scales — color, space, radius, font, shadow
│   ├── semantic/          Semantic roles — action, surface, content, line, status
│   └── component/         Component tokens — button, card, feed, navigation, widget
├── config/                Style Dictionary config and custom formats
│   └── themes/            Theme override definitions
├── migration/             Legacy variable mapping tools
├── build.js               Build entry point
└── dist/                  Published output (generated, do not edit)
    ├── index.js            Root entry — applyThemeConfig + token constants
    ├── index.d.ts          TypeScript declarations for root entry
    ├── applyTheme.js       Runtime theme switcher (lazy CSS loading)
    ├── applyTheme.d.ts     TypeScript declarations for applyThemeConfig
    ├── tokens.js           JS named constants
    ├── tokens.d.ts         TypeScript declarations for token constants
    ├── styles.css          CSS custom properties (base light theme)
    ├── themes.css          All themes combined (styles.css + all theme overrides)
    ├── tokens.json         Nested JSON
    ├── token-catalog.json  Full token catalog
    ├── tailwind-theme.css    Tailwind v4 theme mapping
    └── themes/             Individual theme CSS files

Building and publishing

# Build from the monorepo root
turbo run build --filter=@gainsight-hub/design-tokens

# Publish
npm publish --access public -w packages/design-tokens

版本与发布记录

@gainsight-hub/design-tokens 共发布 16 个版本,首次发布于 2026/05/05;过去 12 个月发布了 16 个版本。

版本发布日期距今
0.5.1latest2026/10/2917 天前
0.5.02026/10/2224 天前
0.4.22026/10/2224 天前
0.4.12026/10/2026 天前
0.4.02026/10/151 个月前
0.2.72026/08/252 个月前

关于 @gainsight-hub/design-tokens 的常见问题

@gainsight-hub/design-tokens 是什么?

Design tokens: CSS variables, JSON, TypeScript constants, and a Tailwind v4 theme.

如何安装 @gainsight-hub/design-tokens?

在项目目录运行 npm install @gainsight-hub/design-tokens,或使用 pnpm add / yarn add / bun add。

@gainsight-hub/design-tokens 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@gainsight-hub/design-tokens 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@gainsight-hub/design-tokens 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@gainsight-hub/design-tokens 可以商用吗?

@gainsight-hub/design-tokens 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@gainsight-hub/design-tokens 的下载量有多少?

根据 npm 官方下载统计,@gainsight-hub/design-tokens 在 2026/10/16 – 2026/11/14 这 30 天内被下载 3,257 次,日均约 109 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@gainsight-hub/design-tokens 还在维护吗?

最新版本 0.5.1 发布于 2026/10/29(17 天前);至今共发布 16 个版本,其中过去 12 个月发布了 16 个;首次发布于 2026/05/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。