Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/design-token-governance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@tiny-design/react": minor
"@tiny-design/tokens": minor
---

Add design token governance with JSON source registry, migrate all component SCSS to token variables, introduce CSS Grid layout system, and rebuild Theme Studio
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

<p align="center">
<a href="https://wangdicoder.github.io/tiny-design/"><strong>Documentation</strong></a> &nbsp;&bull;&nbsp;
<a href="https://wangdicoder.github.io/tiny-design/theme/theme-editor"><strong>Theme Editor</strong></a> &nbsp;&bull;&nbsp;
<a href="https://wangdicoder.github.io/tiny-design/theme/theme-studio"><strong>Theme Editor</strong></a> &nbsp;&bull;&nbsp;
<a href="https://wangdicoder.github.io/tiny-design/theme/customise-theme"><strong>Theming Guide</strong></a>
</p>

Expand Down Expand Up @@ -73,7 +73,7 @@ No separate CSS import needed — styles are bundled with each component and tre

### Visual Theme Editor

The built-in [Theme Editor](https://wangdicoder.github.io/tiny-design/theme/theme-editor) lets you pick from 20+ preset themes or fine-tune individual tokens — colours, typography, border radius, spacing — and see changes live on real components. Export as CSS or SCSS when you're done.
The built-in [Theme Editor](https://wangdicoder.github.io/tiny-design/theme/theme-studio) lets you pick from 20+ preset themes or fine-tune individual tokens — colours, typography, border radius, spacing — and see changes live on real components. Export as CSS or SCSS when you're done.

### Dark mode

Expand Down
111 changes: 101 additions & 10 deletions apps/docs/guides/customise-theme.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Customise Theme

Tiny UI provides three ways to customise the look and feel:
Tiny UI now uses a v2 token system with one primary runtime model:

1. **Theme Editor** — a visual, no-code tool for real-time theming (great for exploration and quick customisation).
2. **Design tokens** — CSS custom properties that power light and dark mode. These are the runtime values every component reads.
3. **SCSS constants** — compile-time structural constants (padding, transitions, arrow sizes, etc.) that can be overridden when you build your own stylesheet.
1. **CSS custom properties** for direct runtime overrides.
2. **ThemeDocument** for portable theme JSON.
3. **ConfigProvider `theme.tokens`** for React-scoped theming.

SCSS constants still exist, but they are only for compile-time structural overrides.

## Theme Editor

The built-in [Theme Editor](/theme/theme-editor) lets you visually customise design tokens in real time. You can:
The built-in [Theme Editor](/theme/theme-studio) lets you visually customise design tokens in real time. You can:

- Pick from **20+ preset themes** (e.g. Catppuccin, Mocha Mousse, Cyberpunk) or start from scratch.
- Adjust primary, success, warning, danger, and info colours, background, text, and border colours.
Expand All @@ -18,6 +20,8 @@ The built-in [Theme Editor](/theme/theme-editor) lets you visually customise des

Changes are applied instantly via CSS custom properties — no rebuild required.

The editor exports the same v2 token model used by the runtime, so the result can be applied as CSS variables, stored as a `ThemeDocument`, or passed into `ConfigProvider`.

## Dark mode

Tiny UI ships with built-in light and dark themes. Light mode is the default. To enable dark mode, set `data-tiny-theme` on the `<html>` element:
Expand Down Expand Up @@ -55,13 +59,17 @@ The hook returns:

## Design tokens (CSS custom properties)

Every colour, shadow, and visual state is exposed as a `--ty-*` CSS custom property on `:root`. This is the **primary way** to customise Tiny UI. You can override any token in your own stylesheet:
Every semantic token and component token is exposed as a `--ty-*` CSS custom property. This is the lowest-level runtime API and works in any stack.

You can override tokens directly in your own stylesheet:

```css
:root {
--ty-color-primary: #007bff;
--ty-color-primary-hover: #3d9bff;
--ty-color-primary-active: #0062d6;
--ty-button-radius: 999px;
--ty-card-header-padding: 20px;
}
```

Expand All @@ -72,9 +80,17 @@ html[data-tiny-theme='dark'] {
--ty-color-primary: #3d9bff;
--ty-color-primary-hover: #66b3ff;
--ty-color-primary-active: #007bff;
--ty-color-bg-container: #111827;
--ty-color-text: rgba(249, 250, 251, 0.92);
}
```

### Naming rules

- Semantic token keys use kebab-case, for example `color-primary`.
- Component token keys use dot paths, for example `button.radius` or `card.header-padding`.
- Runtime CSS variables are the same keys with dots converted to hyphens, for example `--ty-button-radius` and `--ty-card-header-padding`.

### Commonly used tokens

| Token | Light default | Description |
Expand All @@ -92,9 +108,77 @@ html[data-tiny-theme='dark'] {
| `--ty-height-md` | `32px` | Medium control height |
| `--ty-height-lg` | `42px` | Large control height |

Every component also has its own tokens for fine-grained control. For example, Button uses `--ty-btn-default-bg`, `--ty-btn-default-color`, etc. The full list of tokens can be found in the source:
- [Light theme tokens](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/scss/themes/_light.scss)
- [Dark theme tokens](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/scss/themes/_dark.scss)
Every component also has its own tokens for fine-grained control. For example, Button uses `--ty-button-bg-default`, `--ty-button-text-default`, and `--ty-button-radius`. The full list of supported tokens is generated from the v2 registry and component sources:
- [Token registry](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/dist/registry.json)
- [Component token sources](https://github.com/wangdicoder/tiny-design/tree/master/packages/tokens/source/components)

## ThemeDocument

`ThemeDocument` is the canonical JSON format for sharing, exporting, saving, and applying themes.

```json
{
"meta": {
"id": "brand-ocean",
"name": "Brand Ocean",
"schemaVersion": 1
},
"mode": "light",
"extends": "tiny-light",
"tokens": {
"semantic": {
"color-primary": "#0ea5e9",
"border-radius": "12px"
},
"components": {
"button.radius": "999px",
"card.header-padding": "20px"
}
}
}
```

Use `ThemeDocument` when you need:

- a serializable theme file
- import/export between tools
- community themes or preset themes
- mode-aware overrides built on top of `tiny-light` or `tiny-dark`

## React: ConfigProvider

In React apps, the recommended API is `ConfigProvider theme={{ tokens: ... }}`.

```tsx
import { ConfigProvider } from '@tiny-design/react';

<ConfigProvider
theme={{
mode: 'light',
extends: 'tiny-light',
tokens: {
semantic: {
'color-primary': '#0ea5e9',
'border-radius': '12px',
},
components: {
'button.radius': '999px',
'card.header-padding': '20px',
},
},
}}
>
<App />
</ConfigProvider>
```

Use this when you want:

- scoped theming for part of the React tree
- nested theme overrides
- popup / portal content to inherit the same token scope

`ConfigProvider` no longer uses the old `theme.token` or `theme.components` API. Use `theme.tokens.semantic` and `theme.tokens.components` only.

## SCSS constants

Expand Down Expand Up @@ -146,6 +230,13 @@ $card-body-padding: 16px !default;
$notification-width: 380px !default;
```

> **Note:** Colours, font sizes, border radii, shadows, and all other visual tokens should be customised via CSS custom properties (see above), not SCSS variables. SCSS constants are only for structural values like padding and sizing.
> **Note:** Colours, typography, radii, shadows, and all other visual tokens should be customised through v2 tokens, not SCSS variables. SCSS constants are only for compile-time structural values like padding and sizing.

## Recommended approach

- Use CSS variables when you want the simplest runtime override.
- Use `ThemeDocument` when you need a portable JSON theme format.
- Use `ConfigProvider` when you need scoped theming in React.
- Use SCSS constants only when a value must be decided at build time.

Please report an issue if the existing list of tokens or constants is not enough for you.
111 changes: 101 additions & 10 deletions apps/docs/guides/customise-theme.zh_CN.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# 自定义主题

Tiny UI 提供三种方式来定制外观
Tiny UI 现在使用 v2 token 系统,推荐的主题自定义方式收敛为一套主模型

1. **主题编辑器** — 一个可视化的实时主题工具,无需编写代码(非常适合探索和快速定制)。
2. **设计令牌(Design tokens)** — 驱动亮色/暗色模式的 CSS 自定义属性,所有组件在运行时读取这些值。
3. **SCSS 常量** — 编译时结构常量(内边距、过渡动画、箭头尺寸等),可在构建自定义样式表时覆盖。
1. **CSS 自定义属性**,用于直接做运行时覆盖。
2. **ThemeDocument**,用于可移植的主题 JSON。
3. **ConfigProvider `theme.tokens`**,用于 React 作用域主题。

SCSS 常量仍然保留,但它只用于编译期的结构性覆盖。

## 主题编辑器

内置的[主题编辑器](/theme/theme-editor)让你可以实时可视化定制设计令牌。你可以:
内置的[主题编辑器](/theme/theme-studio)让你可以实时可视化定制设计令牌。你可以:

- 从 **20+ 个预设主题**中选择(如 Catppuccin、摩卡慕斯、赛博朋克等),或从零开始。
- 调整主色、成功色、警告色、危险色和信息色,以及背景色、文本色和边框色。
Expand All @@ -18,6 +20,8 @@ Tiny UI 提供三种方式来定制外观:

更改通过 CSS 自定义属性即时生效 — 无需重新构建。

主题编辑器导出的也是同一套 v2 token 模型,因此结果既可以作为 CSS 变量使用,也可以保存为 `ThemeDocument`,或者传给 `ConfigProvider`。

## 暗色模式

Tiny UI 内置亮色和暗色主题。默认为亮色模式。要启用暗色模式,请在 `<html>` 元素上设置 `data-tiny-theme`:
Expand Down Expand Up @@ -55,13 +59,17 @@ const App = () => {

## 设计令牌(CSS 自定义属性)

所有颜色、阴影和视觉状态都以 `--ty-*` CSS 自定义属性的形式暴露在 `:root` 上。这是定制 Tiny UI 的**主要方式**。你可以在自己的样式表中覆盖任意令牌:
所有语义令牌和组件令牌都会以 `--ty-*` CSS 自定义属性的形式暴露出来。这是最底层、最通用的运行时接口。

你可以直接在自己的样式表里覆盖:

```css
:root {
--ty-color-primary: #007bff;
--ty-color-primary-hover: #3d9bff;
--ty-color-primary-active: #0062d6;
--ty-button-radius: 999px;
--ty-card-header-padding: 20px;
}
```

Expand All @@ -72,9 +80,17 @@ html[data-tiny-theme='dark'] {
--ty-color-primary: #3d9bff;
--ty-color-primary-hover: #66b3ff;
--ty-color-primary-active: #007bff;
--ty-color-bg-container: #111827;
--ty-color-text: rgba(249, 250, 251, 0.92);
}
```

### 命名规则

- semantic token 使用 kebab-case,例如 `color-primary`
- component token 使用点分路径,例如 `button.radius`、`card.header-padding`
- 运行时 CSS 变量就是把点替换成连字符,例如 `--ty-button-radius`、`--ty-card-header-padding`

### 常用令牌

| 令牌 | 亮色默认值 | 说明 |
Expand All @@ -92,9 +108,77 @@ html[data-tiny-theme='dark'] {
| `--ty-height-md` | `32px` | 中尺寸控件高度 |
| `--ty-height-lg` | `42px` | 大尺寸控件高度 |

每个组件也有自己的令牌,用于细粒度控制。例如,Button 使用 `--ty-btn-default-bg`、`--ty-btn-default-color` 等。完整的令牌列表请参考源码:
- [亮色主题令牌](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/scss/themes/_light.scss)
- [暗色主题令牌](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/scss/themes/_dark.scss)
每个组件也有自己的令牌,用于细粒度控制。例如,Button 使用 `--ty-button-bg-default`、`--ty-button-text-default`、`--ty-button-radius`。完整的受支持令牌列表来自 v2 registry 和组件 source:
- [Token registry](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/dist/registry.json)
- [组件 token 源文件](https://github.com/wangdicoder/tiny-design/tree/master/packages/tokens/source/components)

## ThemeDocument

`ThemeDocument` 是主题导出、导入、保存和分发时使用的标准 JSON 格式。

```json
{
"meta": {
"id": "brand-ocean",
"name": "Brand Ocean",
"schemaVersion": 1
},
"mode": "light",
"extends": "tiny-light",
"tokens": {
"semantic": {
"color-primary": "#0ea5e9",
"border-radius": "12px"
},
"components": {
"button.radius": "999px",
"card.header-padding": "20px"
}
}
}
```

适合用在这些场景:

- 主题文件持久化
- 工具之间导入导出
- 社区主题 / 预设主题
- 在 `tiny-light` 或 `tiny-dark` 之上做模式化覆盖

## React: ConfigProvider

在 React 应用里,推荐使用 `ConfigProvider theme={{ tokens: ... }}`。

```tsx
import { ConfigProvider } from '@tiny-design/react';

<ConfigProvider
theme={{
mode: 'light',
extends: 'tiny-light',
tokens: {
semantic: {
'color-primary': '#0ea5e9',
'border-radius': '12px',
},
components: {
'button.radius': '999px',
'card.header-padding': '20px',
},
},
}}
>
<App />
</ConfigProvider>
```

适合用在这些场景:

- 只对 React 树中的一部分做作用域主题
- 需要嵌套主题覆盖
- 需要让弹层 / portal 内容继承同一个 token 作用域

`ConfigProvider` 已经不再使用旧的 `theme.token` 或 `theme.components` API。现在只使用 `theme.tokens.semantic` 和 `theme.tokens.components`。

## SCSS 常量

Expand Down Expand Up @@ -146,6 +230,13 @@ $card-body-padding: 16px !default;
$notification-width: 380px !default;
```

> **注意:** 颜色、字号、圆角、阴影等所有视觉令牌应通过 CSS 自定义属性定制(见上方),而非 SCSS 变量。SCSS 常量仅用于内边距、尺寸等结构性值。
> **注意:** 颜色、排版、圆角、阴影等所有视觉令牌,都应该通过 v2 token 定制,而不是通过 SCSS 变量。SCSS 常量只适用于内边距、尺寸等编译期结构值。

## 推荐用法

- 想最快做运行时覆盖,用 CSS 变量
- 需要可移植的 JSON 主题格式,用 `ThemeDocument`
- 需要 React 局部主题,用 `ConfigProvider`
- 只有在值必须在构建期决定时,才使用 SCSS 常量

如果现有的令牌或常量列表无法满足你的需求,请提交 issue 反馈。
5 changes: 3 additions & 2 deletions apps/docs/src/components/header/header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@
&__version {
font-size: 11px;
font-weight: 600;
color: $docs-accent;
background: $docs-accent-subtle;
color: var(--ty-color-primary);
background: color-mix(in srgb, var(--ty-color-primary) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--ty-color-primary) 18%, transparent);
border-radius: 6px;
padding: 3px 10px;
letter-spacing: 0.02em;
Expand Down
1 change: 1 addition & 0 deletions apps/docs/src/containers/components/component-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const icons: Record<string, IconFn> = {
'aspect-ratio': () => <svg viewBox="0 0 24 24" fill="none"><rect x="3" y="5" width="18" height="14" rx="2" {...s} /><path d="M7 15l3-3 3 3" {...s} /></svg>,
divider: () => <svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" {...s} /><line x1="12" y1="5" x2="12" y2="9" {...s} /><line x1="12" y1="15" x2="12" y2="19" {...s} /></svg>,
flex: () => <svg viewBox="0 0 24 24" fill="none"><rect x="3" y="8" width="5" height="8" rx="1" {...s} /><rect x="10" y="5" width="5" height="14" rx="1" {...s} /><rect x="17" y="9" width="5" height="6" rx="1" {...s} /></svg>,
'grid-system': () => <svg viewBox="0 0 24 24" fill="none"><rect x="3" y="4" width="18" height="7" rx="1" {...s} /><rect x="3" y="13" width="5" height="7" rx="1" {...s} /><rect x="10" y="13" width="5" height="7" rx="1" {...s} /><rect x="17" y="13" width="4" height="7" rx="1" {...s} /></svg>,
grid: () => <svg viewBox="0 0 24 24" fill="none"><rect x="3" y="3" width="7" height="7" rx="1" {...s} /><rect x="14" y="3" width="7" height="7" rx="1" {...s} /><rect x="3" y="14" width="7" height="7" rx="1" {...s} /><rect x="14" y="14" width="7" height="7" rx="1" {...s} /></svg>,
layout: () => <svg viewBox="0 0 24 24" fill="none"><rect x="3" y="3" width="18" height="18" rx="2" {...s} /><line x1="3" y1="9" x2="21" y2="9" {...s} /><line x1="9" y1="9" x2="9" y2="21" {...s} /></svg>,
space: () => <svg viewBox="0 0 24 24" fill="none"><rect x="3" y="9" width="4" height="6" rx="1" {...s} /><rect x="10" y="9" width="4" height="6" rx="1" {...s} /><rect x="17" y="9" width="4" height="6" rx="1" {...s} /></svg>,
Expand Down
Loading
Loading