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
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": ["@tiny-design/docs", "@tiny-design/extract", "@tiny-design/pro"]
"ignore": ["@tiny-design/docs", "@tiny-design/extract"]
}
6 changes: 6 additions & 0 deletions .changeset/fix-scss-imports-and-popup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@tiny-design/react": patch
"@tiny-design/tokens": patch
---

Migrate component SCSS imports from @tiny-design/tokens to local style/variables and fix Popup positioning sync
8 changes: 0 additions & 8 deletions .github/workflows/deploy-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,6 @@ jobs:
- name: Copy 404.html for SPA routing
run: cp apps/docs/build/index.html apps/docs/build/404.html

- name: Build pro site
run: pnpm --filter @tiny-design/pro build
env:
NEXT_PUBLIC_BASE_PATH: /tiny-design/pro

- name: Merge pro into docs output
run: cp -r apps/pro/out/ apps/docs/build/pro/

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ es
lib
coverage
apps/docs/build
apps/docs/test-results
apps/docs/playwright-report

# Turbo
.turbo
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Tiny Design is a React component UI library (80+ components) published as `@tiny

```
packages/react/ → @tiny-design/react (main component library)
packages/tokens/ → @tiny-design/tokens (design tokens, SCSS variables)
packages/tokens/ → @tiny-design/tokens (v2 design tokens and theme runtime)
packages/icons/ → @tiny-design/icons (SVG icon components)
apps/docs/ → documentation site (Vite + MDX)
```
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ The package root barrel must also re-export those public component types from `p
- TypeScript strict mode is enabled
- Components use `React.forwardRef` for ref forwarding
- CSS class names follow the `ty-component-name` convention
- SCSS variables are in `packages/react/src/style/_variables.scss`
- Shared Sass helpers for React component styles live in `packages/react/src/style/`

## Running Tests

Expand Down
14 changes: 2 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,24 +104,14 @@ Every visual token is a `--ty-*` CSS custom property. Override any of them:
}
```

### SCSS variables

For compile-time control, override `!default` SCSS variables before importing:

```scss
$primary-color: #3b82f6;
$border-radius: 8px;
@use "@tiny-design/react/es/style/index" as *;
```

See the [Theming Guide](https://wangdicoder.github.io/tiny-design/theme/customise-theme) for the full list of tokens and variables.
See the [Theming Guide](https://wangdicoder.github.io/tiny-design/theme/customise-theme) for the full token list and Theme Studio workflow.

## Packages

| Package | Description |
| ------- | ----------- |
| [@tiny-design/react](./packages/react) | Core component library |
| [@tiny-design/tokens](./packages/tokens) | Design tokens and foundational styles |
| [@tiny-design/tokens](./packages/tokens) | V2 design tokens and theme runtime |
| [@tiny-design/icons](./packages/icons) | SVG icon components |
| [@tiny-design/cli](./packages/cli) | CLI for the Tiny Design component library |
| [@tiny-design/mcp](./packages/mcp) | MCP server for AI assistants to access the component library |
Expand Down
2 changes: 1 addition & 1 deletion _template/style/_index.scss
Original file line number Diff line number Diff line change
@@ -1 +1 @@
@use '@tiny-design/tokens/scss/variables' as *;
@use '../../style/variables' as *;
74 changes: 14 additions & 60 deletions apps/docs/guides/customise-theme.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# Customise Theme

Tiny UI now uses a v2 token system with one primary runtime model:
Tiny UI uses a token-driven runtime theme model:

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-studio) lets you visually customise design tokens in real time. You can:
Expand All @@ -20,7 +18,7 @@ The built-in [Theme Editor](/theme/theme-studio) 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`.
The editor exports the same 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

Expand Down Expand Up @@ -102,13 +100,13 @@ html[data-tiny-theme='dark'] {
| `--ty-color-text` | `rgba(0,0,0,0.85)` | Primary text colour |
| `--ty-color-text-secondary` | `rgba(0,0,0,0.65)` | Secondary text colour |
| `--ty-color-border` | `#d9d9d9` | Default border colour |
| `--ty-border-radius` | `2px` | Global border radius |
| `--ty-font-size-base` | `1rem` | Base font size |
| `--ty-border-radius` | `6px` | Global border radius |
| `--ty-font-size-base` | `14px` | Base font size |
| `--ty-height-sm` | `24px` | Small control height |
| `--ty-height-md` | `32px` | Medium control height |
| `--ty-height-lg` | `42px` | Large control height |
| `--ty-height-md` | `35px` | Medium control height |
| `--ty-height-lg` | `44px` | Large control height |

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:
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 token 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)

Expand Down Expand Up @@ -178,65 +176,21 @@ Use this when you want:
- 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

If you import Tiny UI's SCSS source instead of the pre-built CSS, you can override compile-time structural constants such as padding, transitions, and arrow sizes. These are values that don't need to change at runtime.

Every constant uses the `!default` flag, so your overrides take precedence.

### 1. Install Sass

```bash
$ npm install sass --save-dev
```

### 2. Create your overrides file

Create a file, e.g. `theme-overrides.scss`. Your overrides **must come before** the Tiny UI import:
Use `theme.tokens.semantic` and `theme.tokens.components` as the supported React theme shape.

```scss
// Override structural constants
$btn-padding-md: 0 20px;
$card-body-padding: 20px;
$tooltip-arrow-size: 6px;
## Sass source styles

// Import Tiny UI styles (applies your overrides via !default)
@use "@tiny-design/react/es/style/index" as *;
```

### 3. Import in your entry file

```js
import './theme-overrides.scss';
```

The full list of SCSS constants can be found in [_constants.scss](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/scss/_constants.scss).
Tiny UI still ships Sass source files for bundlers that compile library styles directly, but Sass variables are not a theme API. Treat `@tiny-design/react/es/style/*.scss` and component `style/*.scss` files as implementation source, not as supported customisation contracts.

Some commonly overridden constants:

```scss
// Button
$btn-padding-sm: 0 10px !default;
$btn-padding-md: 0 15px !default;
$btn-padding-lg: 0 28px !default;

// Card
$card-header-padding: 13px 16px !default;
$card-body-padding: 16px !default;

// Notification
$notification-width: 380px !default;
```
Use tokens for visual changes such as colour, typography, radii, shadows, spacing, sizing, and component states. If a value is not exposed as a token yet, prefer adding it to the token registry instead of adding a new public Sass variable.

> **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.
The full token list is generated from `packages/tokens/dist/registry.json`.

## 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.
- Avoid treating Sass variables as public theme configuration; add missing customisation points as tokens.

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

Tiny UI 现在使用 v2 token 系统,推荐的主题自定义方式收敛为一套主模型
Tiny UI 使用由 token 驱动的运行时主题模型

1. **CSS 自定义属性**,用于直接做运行时覆盖。
2. **ThemeDocument**,用于可移植的主题 JSON。
3. **ConfigProvider `theme.tokens`**,用于 React 作用域主题。

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

## 主题编辑器

内置的[主题编辑器](/theme/theme-studio)让你可以实时可视化定制设计令牌。你可以:
Expand All @@ -20,7 +18,7 @@ SCSS 常量仍然保留,但它只用于编译期的结构性覆盖。

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

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

## 暗色模式

Expand Down Expand Up @@ -102,13 +100,13 @@ html[data-tiny-theme='dark'] {
| `--ty-color-text` | `rgba(0,0,0,0.85)` | 主文本色 |
| `--ty-color-text-secondary` | `rgba(0,0,0,0.65)` | 次要文本色 |
| `--ty-color-border` | `#d9d9d9` | 默认边框色 |
| `--ty-border-radius` | `2px` | 全局圆角 |
| `--ty-font-size-base` | `1rem` | 基础字号 |
| `--ty-border-radius` | `6px` | 全局圆角 |
| `--ty-font-size-base` | `14px` | 基础字号 |
| `--ty-height-sm` | `24px` | 小尺寸控件高度 |
| `--ty-height-md` | `32px` | 中尺寸控件高度 |
| `--ty-height-lg` | `42px` | 大尺寸控件高度 |
| `--ty-height-md` | `35px` | 中尺寸控件高度 |
| `--ty-height-lg` | `44px` | 大尺寸控件高度 |

每个组件也有自己的令牌,用于细粒度控制。例如,Button 使用 `--ty-button-bg-default`、`--ty-button-text-default`、`--ty-button-radius`。完整的受支持令牌列表来自 v2 registry 和组件 source:
每个组件也有自己的令牌,用于细粒度控制。例如,Button 使用 `--ty-button-bg-default`、`--ty-button-text-default`、`--ty-button-radius`。完整的受支持令牌列表来自 token 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)

Expand Down Expand Up @@ -178,65 +176,21 @@ import { ConfigProvider } from '@tiny-design/react';
- 需要嵌套主题覆盖
- 需要让弹层 / portal 内容继承同一个 token 作用域

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

## SCSS 常量

如果你引入的是 Tiny UI 的 SCSS 源文件而非预编译的 CSS,可以覆盖编译时结构常量,如内边距、过渡动画和箭头尺寸。这些是不需要在运行时变化的值。

每个常量都使用了 `!default` 标志,因此你的覆盖值会优先生效。

### 1. 安装 Sass

```bash
$ npm install sass --save-dev
```

### 2. 创建覆盖文件

创建一个文件,例如 `theme-overrides.scss`。你的覆盖值**必须写在** Tiny UI 引入语句之前:
`theme.tokens.semantic` 和 `theme.tokens.components` 是受支持的 React 主题结构。

```scss
// 覆盖结构常量
$btn-padding-md: 0 20px;
$card-body-padding: 20px;
$tooltip-arrow-size: 6px;
## Sass 源码样式

// 引入 Tiny UI 样式(通过 !default 应用你的覆盖值)
@use "@tiny-design/react/es/style/index" as *;
```

### 3. 在入口文件中引入

```js
import './theme-overrides.scss';
```

完整的 SCSS 常量列表请参考 [_constants.scss](https://github.com/wangdicoder/tiny-design/blob/master/packages/tokens/scss/_constants.scss)。
Tiny UI 仍然发布 Sass 源文件,方便需要直接编译库样式的构建工具使用;但 Sass 变量不再是主题 API。请把 `@tiny-design/react/es/style/*.scss` 和组件 `style/*.scss` 当作实现源码,而不是受支持的主题定制契约。

以下是一些常用的可覆盖常量:

```scss
// 按钮
$btn-padding-sm: 0 10px !default;
$btn-padding-md: 0 15px !default;
$btn-padding-lg: 0 28px !default;

// 卡片
$card-header-padding: 13px 16px !default;
$card-body-padding: 16px !default;

// 通知
$notification-width: 380px !default;
```
颜色、排版、圆角、阴影、间距、尺寸和组件状态等视觉定制都应该通过 token 完成。如果某个值还没有对应 token,优先把它补进 token registry,而不是新增公开 Sass 变量。

> **注意:** 颜色、排版、圆角、阴影等所有视觉令牌,都应该通过 v2 token 定制,而不是通过 SCSS 变量。SCSS 常量只适用于内边距、尺寸等编译期结构值
完整 token 列表由 `packages/tokens/dist/registry.json` 生成

## 推荐用法

- 想最快做运行时覆盖,用 CSS 变量
- 需要可移植的 JSON 主题格式,用 `ThemeDocument`
- 需要 React 局部主题,用 `ConfigProvider`
- 只有在值必须在构建期决定时,才使用 SCSS 常量
- 不要把 Sass 变量当作公开主题配置;缺失的定制点应该补成 token

如果现有的令牌或常量列表无法满足你的需求,请提交 issue 反馈。
如果现有的令牌列表无法满足你的需求,请提交 issue 反馈。
2 changes: 1 addition & 1 deletion apps/docs/guides/mcp-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The Model Context Protocol (MCP) is an open standard that lets AI assistants con
| `list_components` | List all 80+ components. Filter by category: Foundation, Layout, Navigation, Data Display, Form, Feedback, Miscellany. |
| `get_component_props` | Get the full props interface for a component — types, required flags, descriptions. |
| `get_component_example` | Get usage examples (demo code) for a component. |
| `get_design_tokens` | Get design tokens (SCSS variables) — colors, typography, spacing, breakpoints, shadows. |
| `get_design_tokens` | Get v2 design tokens from the token registry — colors, typography, spacing, breakpoints, shadows. |
| `list_icons` | List all 240+ icon names. Filter by search term. |
| `get_icon` | Get details and usage example for a specific icon. |

Expand Down
34 changes: 34 additions & 0 deletions apps/docs/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
testDir: './tests/visual',
outputDir: './test-results',
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? [['html'], ['list']] : 'list',
expect: {
toHaveScreenshot: {
maxDiffPixels: 100,
},
},
webServer: {
command: 'pnpm exec vite serve --host 127.0.0.1 --port 3004',
url: 'http://127.0.0.1:3004',
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
use: {
...devices['Desktop Chrome'],
baseURL: 'http://127.0.0.1:3004',
channel: 'chrome',
colorScheme: 'light',
deviceScaleFactor: 1,
locale: 'en-US',
timezoneId: 'UTC',
viewport: { width: 1280, height: 900 },
screenshot: 'only-on-failure',
trace: 'retain-on-failure',
},
});
2 changes: 1 addition & 1 deletion apps/docs/src/_variables.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@forward "../../../packages/tokens/scss/variables";
@forward "../../../packages/react/src/style/variables";

$main-color: #0D9488;
$header-height: 64px;
Expand Down
13 changes: 10 additions & 3 deletions apps/docs/src/containers/theme-studio/editor-draft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,20 @@ export function loadInitialDraft(): ThemeEditorDraft {
const pendingTheme = loadPendingThemeDocument();
if (pendingTheme) {
clearPendingThemeDocument();
return buildDraftFromThemeDocument(pendingTheme);
try {
return buildDraftFromThemeDocument(pendingTheme);
} catch {
// Ignore invalid cached documents and continue with the next source.
}
}

const storedTheme = loadStoredThemeDocument();
if (storedTheme) {
return buildDraftFromThemeDocument(storedTheme);
try {
return buildDraftFromThemeDocument(storedTheme);
} catch {
// Ignore invalid cached documents and fall back to the editor draft/default.
}
}

try {
Expand All @@ -78,7 +86,6 @@ export function buildPreviewVars(fields: ThemeEditorFields): React.CSSProperties
'--ty-font-family-monospace': fields.fontMono,
'--ty-font-size-base': fields.fontSizeBase,
'--ty-line-height-base': fields.lineHeightBase,
'--ty-letter-spacing': fields.letterSpacing,
'--ty-h1-font-size': fields.h1Size,
'--ty-h2-font-size': fields.h2Size,
'--editor-primary': fields.primary,
Expand Down
Loading
Loading