@ptengine/design-components 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,17 @@
1
1
  # PT-AI-Components
2
2
 
3
- > **npm 安装名(对外)**:`@ptengine/design-components`
4
- > **仓内包名**:`@ptengine/pt-ai-components` —— monorepo 里的 import / alias / `workspace:*`
5
- > 全用这个。改名只发生在发布产物上(见 [RELEASING.md](./RELEASING.md)),两个名字是同一个库。
3
+ > **包名**:`@ptengine/design-components` —— 仓内、npm 上、消费方 import,三处同名。
4
+ > **源码**:GitLab `PtmindDev/ptx/design-components`(本仓,唯一真值源)
5
+ > **分发**:npm 公共 registry · [包页面](https://www.npmjs.com/package/@ptengine/design-components)
6
6
 
7
- 基于 [shadcn/ui](https://ui.shadcn.com/) 的 PTEngine React 组件库。组件源码拷入本库、按 PTEngine 需要改样式/交互,供 monorepo 内 `apps/` 子项目直接使用。
7
+ 基于 [shadcn/ui](https://ui.shadcn.com/) 的 PTEngine React 组件库。组件源码拷入本库、
8
+ 按 PTEngine 需要改样式/交互,经 npm 供各产品使用。
8
9
 
9
10
  ## 特点
10
11
 
11
- - **源码优先**:消费方通过 vite alias 指向 `src`,直接编译源码,无需先 build。
12
+ - **源码随包分发**:`files` 含全量 `src`,消费方的 Tailwind 扫的是源码而非压缩产物
13
+ (压缩会改写 class 字符串,扫 `dist` 会漏类)。开发期还可用本地覆盖开关直连源码,
14
+ 见下方「在 apps/x 里联调本组件库」。
12
15
  - **Token 唯一数据源**:`src/styles/tokens.css` 定义所有 CSS 变量——三层嵌套架构(③ shadcn 别名 → ② PTEngine 语义层 → ① 原语层纯通道三元组),透明度只在语义层以 `var(--pt-x) / a` 表达,明暗差异只在语义层覆盖;`tailwind.preset.js` 定义 Token → Tailwind 颜色键映射(实色套 `<alpha-value>`,自带透明度的只包 `rgb()`)。详见 tokens.css 文件头注释。
13
16
  - 保留可选 `pnpm build`(vite lib + d.ts),供独立发布。
14
17
 
@@ -28,38 +31,46 @@
28
31
  新增组件或调整 variant 时先对照这三条:一个改动如果让界面「变吵」了
29
32
  (多了一种装饰性颜色、多了一层非浮层阴影、层级靠色块而非字阶),方向就是错的。
30
33
 
31
- ## 消费方接入(以 apps/x 为例)
34
+ ## 接入(所有消费方一致)
32
35
 
33
- 1. **vite alias** `vite.config.ts`
34
- ```ts
35
- '@ptengine/pt-ai-components': resolve(__dirname, '../../packages/pt-ai-components/src')
36
- ```
37
- 2. **Tailwind preset + 扫描包源码** — `tailwind.config.js`
36
+ 从公共 npm 装(scope `@ptengine`,`access: public`,无需 token)。**apps/x 与外部项目
37
+ 走的是同一条路径**——本库对谁都是普通 npm 依赖,没有「内部特殊通道」。
38
+
39
+ ```bash
40
+ pnpm add @ptengine/design-components
41
+ ```
42
+
43
+ 1. **Tailwind preset + 扫描包源码** — `tailwind.config.js`
38
44
  ```js
39
- import shadcnPreset from '../../packages/pt-ai-components/tailwind.preset.js';
45
+ import preset from '@ptengine/design-components/tailwind-preset';
40
46
  export default {
41
- presets: [shadcnPreset],
47
+ presets: [preset],
42
48
  content: [
43
- './src/**/*.{js,ts,jsx,tsx}',
44
- '../../packages/pt-ai-components/src/**/*.{js,ts,jsx,tsx}'
49
+ './src/**/*.{ts,tsx}',
50
+ './node_modules/@ptengine/design-components/src/**/*.{js,ts,jsx,tsx}'
45
51
  ]
46
- // ...app 专属扩展
47
52
  };
48
53
  ```
49
- 3. **引入 token 并挂作用域类** 入口(如 `main.tsx`)
54
+ > `src` 而不是 `dist`:`dist` 是压缩后的产物,class 字符串可能被改写,
55
+ > Tailwind 扫不全 —— 现象是组件渲染出来但部分样式缺失,且零报错。
56
+ > `files` 里带 `src` 就是为了这个。
57
+
58
+ 2. **入口引 token 并挂作用域类**
50
59
  ```ts
51
- import '@ptengine/pt-ai-components/styles/tokens.css';
60
+ import '@ptengine/design-components/styles/tokens.css';
52
61
  document.documentElement.classList.add('pt-ui'); // 或 <html class="pt-ui">
53
62
  ```
54
63
  库**不写任何 `:root`/html 级样式**:全部变量为 `--pt-` 前缀、声明在 `.pt-ui`
55
64
  作用域类下——挂在任何宿主上都零撞名。推荐挂 `<html>`(Dialog/Popover 等
56
65
  portal 到 body 的浮层才能取到变量);只包子树亦可,但浮层需另行处理。
57
66
  暗色切换:在同一元素上加/去 `.dark` 类。
58
- 4. **package.json**
59
- ```json
60
- "@ptengine/pt-ai-components": "workspace:*"
67
+
68
+ 3. **组件从包根引**
69
+ ```ts
70
+ import { Button, Dialog, Tabs } from '@ptengine/design-components';
61
71
  ```
62
- 5. **浮层 z-index 对齐**(宿主已有全局层级体系时):库浮层不写死 `z-50`,
72
+
73
+ 4. **浮层 z-index 对齐**(宿主已有全局层级体系时):库浮层不写死 `z-50`,
63
74
  而是走三个可覆写变量——`--pt-z-overlay`(dialog / alert-dialog / sheet /
64
75
  drawer)< `--pt-z-popup`(popover / select / dropdown-menu / context-menu /
65
76
  menubar / hover-card)< `--pt-z-tooltip`(tooltip),未设置时回退 `50`。
@@ -68,49 +79,47 @@
68
79
  这三个变量是「使用规约 4:不覆盖 CSS 变量」的**唯一豁免**——它们是布局
69
80
  集成钩子,不是观感 token,本就设计为由宿主赋值。
70
81
 
71
- ## 外部项目接入(npm 安装)
82
+ > **包里没有编译好的 CSS**:观感全靠消费方自己的 Tailwind 编译 + `tokens.css` 变量。
83
+ > 第 1、2 步少任何一步,组件都会渲染成无样式的裸 DOM——这不是 bug。
84
+ > `react` / `react-dom`(≥18)是 peerDependency,需宿主自行安装。
85
+
86
+ ## 在 apps/x 里联调本组件库
72
87
 
73
- monorepo 项目从公共 npm 装(scope `@ptengine`,`access: public`,无需 token)。
74
- **对外安装名是 `@ptengine/design-components`**:
88
+ apps/x 默认吃 npm 发布版。要让它直连你本地这份源码(**改组件刷新即见,不用发版**),
89
+ `apps/x/.env.development.local` 里写一行:
75
90
 
76
- ```bash
77
- pnpm add @ptengine/design-components
91
+ ```
92
+ PT_DESIGN_COMPONENTS_SRC=/你的路径/design-components
78
93
  ```
79
94
 
80
- 1. **Tailwind preset + 扫描包产物** — `tailwind.config.js`
81
- ```js
82
- import preset from '@ptengine/design-components/tailwind-preset';
83
- export default {
84
- presets: [preset],
85
- content: [
86
- './src/**/*.{ts,tsx}',
87
- './node_modules/@ptengine/design-components/dist/**/*.{js,cjs}'
88
- ]
89
- };
90
- ```
91
- 2. **入口引 token 并挂作用域类**
92
- ```ts
93
- import '@ptengine/design-components/styles/tokens.css';
94
- document.documentElement.classList.add('pt-ui');
95
- ```
96
- 3. **组件从包根引**
97
- ```ts
98
- import { Button, Dialog, Tabs } from '@ptengine/design-components';
99
- ```
95
+ 重启 apps/x dev server 生效。想验证「发出去的版本对不对」,把这行注释掉再重启。
100
96
 
101
- > **包里没有编译好的 CSS**:观感全靠消费方自己的 Tailwind 编译 + `tokens.css` 变量。
102
- > 上面两步少任何一步,组件都会渲染成无样式的裸 DOM——这不是 bug。
103
- > `react` / `react-dom`(≥18)是 peerDependency,需宿主自行安装。
104
- > 浮层 z-index 对齐同上一节第 5 步。
97
+ 三个必须知道的点:
98
+
99
+ - **类型提示仍来自 npm 发布版**。改了组件的 props 类型,要发一版才在 apps/x 里有提示。
100
+ 运行时以 vite alias 为准,所以覆盖模式下「页面对但编辑器报红」是正常现象,不是 bug。
101
+ - **`tailwind.preset.js` 不走覆盖**(它是静态 import,条件加载需要顶层 await,
102
+ tailwind 的配置加载器不支持)。改 preset 里的语义色 / state-layer 要发版才生效;
103
+ 改组件(占改动的绝大多数)不受影响。
104
+ - **忘了这行配置会两个方向都困惑**:设了但没重启 → 「改了组件库没反应」;
105
+ 忘了自己设过 → 「apps/x 里看到的不是发布版的样子」。两种都难自查,
106
+ 改组件前先确认当前是哪种模式。
105
107
 
106
108
  ## 使用规约(消费方必读)
107
109
 
108
- 本库以**源码直连**方式被消费(`workspace:*` + vite alias 指向 `src`),因此
109
- **库侧任何修改(token / 组件样式 / 交互规范)一经提交,所有引用项目下次构建或
110
- 热更新即自动生效**——无需发版、无需升级依赖。要让这个同步机制持续成立,
111
- 业务项目使用时须遵守:
110
+ 本库经 npm 分发,消费方装的是**锁定的版本号**。因此改动的传播分两段,
111
+ 别把它们当成一回事:
112
+
113
+ | | 怎么发生 |
114
+ |---|---|
115
+ | **你在本地看到改动** | 开了覆盖开关就是即时的(见上一节),零流程 |
116
+ | **产品真正用上新版本** | 发版(打 tag → CI 发 npm)+ 消费方升版本号装一次,**不会自动** |
112
117
 
113
- 1. **只从包入口引用**:`import { Button } from '@ptengine/pt-ai-components'`。
118
+ 第二段的手动闸门是有意的:库里手滑改错一行,不该让全线产品下次构建就跟着炸。
119
+
120
+ 要让改动能顺畅传播下去,业务项目使用时须遵守:
121
+
122
+ 1. **只从包入口引用**:`import { Button } from '@ptengine/design-components'`。
114
123
  **禁止**把组件源码复制进业务项目——复制即与库脱钩,后续更新不再同步。
115
124
  2. **观感全部交给库**:颜色、字体、字号、圆角、阴影一律由组件与 token 提供。
116
125
  业务代码**禁止**硬编码色值(`#xxx` / `rgb()`)、字体名、字阶之外的字号;
@@ -131,16 +140,14 @@ pnpm add @ptengine/design-components
131
140
 
132
141
  ### 规约的执行
133
142
 
134
- 机器强制分三层,现状:**ESLint 层已随迁移阶段 0 在 apps/x 恢复**
135
- (`apps/x/eslint.config.js`「组件库治理」块:禁直引 Radix / cva、禁深路径引
136
- 库内部文件、封死 antd;存量 `src/components/ui/**` 豁免,随迁移批次收紧)。
137
- jscpd 跨包查重 CI 与 CODEOWNERS 审批仍处精简移除状态,如需恢复参考
138
- 历史提交 c1c0b142f。
143
+ 机器强制现状:**ESLint 层在 apps/x**(`apps/x/eslint.config.js`「组件库治理」块:
144
+ 禁直引 Radix / cva、禁深路径引库内部文件、封死 antd;存量 `src/components/ui/**`
145
+ 豁免,随迁移批次收紧)。那批存量副本的清理是搬仓之后的下一期工作。
139
146
 
140
147
  ## 使用
141
148
 
142
149
  ```tsx
143
- import { Button, Input, Label, cn } from '@ptengine/pt-ai-components';
150
+ import { Button, Input, Label, cn } from '@ptengine/design-components';
144
151
 
145
152
  <Button variant="default">保存</Button>
146
153
  <Button variant="secondary" size="sm">取消</Button>
@@ -187,6 +194,42 @@ Primary(黑,暗色反白)这类深色表面用 `state-layer-inverse`,其
187
194
  百分比只维护在 `src/styles/tokens.css` 语义层(`--pt-interaction-hover/press/focus`),
188
195
  调整后组件与 `/tokens` 展示页自动跟随。
189
196
 
197
+ ## 圆角 Radius(六档)
198
+
199
+ | 类名 | 值 | 用在 |
200
+ |---|---|---|
201
+ | `rounded-sm` | 6px | sm 档控件(24px 高) |
202
+ | `rounded-md` | 8px | default / lg 档控件(32 / 40px 高) |
203
+ | `rounded-lg` | 10px | 卡片、弹窗、浮层 —— 基准档 |
204
+ | `rounded-12` | 12px | 更柔和的面板 |
205
+ | `rounded-16` | 16px | 页面级外壳、对话坞 |
206
+ | `rounded-20` | 20px | 需要强调圆润的大面 |
207
+
208
+ 正圆用 `rounded-full`。可视对照与选档指南见 playground 的 **Radius** 页。
209
+
210
+ **为什么大档位用 px 命名而不是 `xl` / `2xl`**:Tailwind 默认 `rounded-xl`=12px、
211
+ `rounded-2xl`=16px,与本库需要的 16 / 20 同名不同值。沿用 t 恤码会让从 shadcn / Tailwind
212
+ 生态抄来的代码**静默偏移几 px** —— 不报错、不警告,只是看着「有点不对」,极难自查。
213
+ `rounded-12/16/20` 在两边都不存在,不可能撞。
214
+
215
+ **两种产生方式有意混用**(改值前必读):
216
+
217
+ ```
218
+ --pt-radius 10px 手写,基准
219
+ --pt-radius-md calc(基准 − 2px) 派生 → 8px
220
+ --pt-radius-sm calc(基准 − 4px) 派生 → 6px
221
+ --pt-radius-12 12px 固定,不跟随基准
222
+ --pt-radius-16 16px 固定,不跟随基准
223
+ --pt-radius-20 20px 固定,不跟随基准
224
+ ```
225
+
226
+ 派生那套来自 shadcn(一个 `--radius` 旋钮整体缩放,档间恒差 2px);后加的三档要的是
227
+ 「更细的尺子」而不是「可整体缩放的比例」,且基准自建库起从未调过,那个旋钮实际没人用。
228
+ **后果**:真去调基准时,前三档会动、后三档不动 —— 这个分裂是有意的,不是漏改。要统一
229
+ 应把前三档也写死,而不是把后三档改成 calc(那会让 `rounded-16` 在基准变化后不再是 16px)。
230
+
231
+ ⚠️ **缺档就加档,不要硬写 `rounded-[18px]` 这类任意值**,否则每个面板各写各的数,刻度失效。
232
+
190
233
  ## 字体 Typography(中/日/英三语)
191
234
 
192
235
  品牌字体(源自 Figma `Type/Mode` 的 family 变量):EN `Inter` / JA `Noto Sans JP` /
@@ -292,9 +335,13 @@ Chart 色板走 `--chart-1..5` token(映射品牌色系)。
292
335
 
293
336
  **依赖版本锚定**(升级前先改对应组件源):`recharts ^2.15`(chart.tsx 按 2.x API 写,
294
337
  3.x 类型不兼容)· `react-resizable-panels ^2.1`(4.x 改了导出名)·
295
- `react-day-picker ^10` + `date-fns ^4`(calendar.tsx 按 v9+ classNames API 写;
296
- **须与 apps/x 声明的版本保持同一大版本**——源码直连下 Vite 预构建对裸导入只保留
297
- 一份,两端版本劈叉会让其中一方拿到错误版本、日历样式全失效)。
338
+ `react-day-picker ^10` + `date-fns ^4`(calendar.tsx 按 v9+ classNames API 写)。
339
+
340
+ ⚠️ **这几个依赖须与 apps/x 声明的版本保持同一大版本**。装包模式下本库自带依赖、
341
+ 两端各持一份,问题不大;但**开着本地覆盖开关时**,vite 是在 apps/x 的解析环境里编译
342
+ 本库源码的,`react-day-picker` 这类裸导入会解析到 **apps/x 的那一份**,版本劈叉就会
343
+ 拿到错误版本 —— 现象是日历样式整个失效。这个坑只在覆盖模式下出现,
344
+ 在装包模式下复现不了,所以升这几个依赖时两边要一起升。
298
345
 
299
346
  ## 授权
300
347
 
@@ -307,5 +354,8 @@ Chart 色板走 `--chart-1..5` token(映射品牌色系)。
307
354
  因此**任何机密内容都不能进这个包** —— `src` / `llms.txt` / `tailwind.preset.js` 全部随包
308
355
  公开发布。新增文件前先确认它属于「可公开的 UI 与设计 token」范畴。
309
356
 
310
- 发版流程见 [RELEASING.md](./RELEASING.md);`@ptmafia` GitHub Packages 那条并行分发线见
311
- [PUBLISHING.md](./PUBLISHING.md)。
357
+ 发版流程见 [RELEASING.md](./RELEASING.md)
358
+
359
+ > 历史遗留:本库曾并行发布到 GitHub Packages(`@ptmafia/pt-ai-components`,镜像仓
360
+ > `ptmafia/Design-components`)。该线已于 2026-09 退役,已发版本保留但不再更新。
361
+ > 给 AI 用的 `llms.txt` 现在走 `https://unpkg.com/@ptengine/design-components/llms.txt`。
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../../src/components/ui/breadcrumb.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,QAAA,MAAM,UAAU;gBAE0C,KAAK,CAAC,SAAS;qCACK,CAAC;AAG/E,QAAA,MAAM,cAAc,2KAWnB,CAAC;AAGF,QAAA,MAAM,cAAc,kKAInB,CAAC;AAGF,QAAA,MAAM,cAAc;cAEkC,OAAO;2CAU3D,CAAC;AAGH,QAAA,MAAM,cAAc,sKAWnB,CAAC;AAGF,QAAA,MAAM,mBAAmB;wCAAuC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;;CASzF,CAAC;AAIF,QAAA,MAAM,kBAAkB;qCAIrB,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;CAUnD,CAAC;AAGF,OAAO,EACH,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EACrB,CAAC"}
1
+ {"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../../src/components/ui/breadcrumb.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,QAAA,MAAM,UAAU;gBAE0C,KAAK,CAAC,SAAS;qCACK,CAAC;AAG/E,QAAA,MAAM,cAAc,2KAanB,CAAC;AAGF,QAAA,MAAM,cAAc,kKAInB,CAAC;AAGF,QAAA,MAAM,cAAc;cAEkC,OAAO;2CAU3D,CAAC;AAGH,QAAA,MAAM,cAAc,sKAWnB,CAAC;AAGF,QAAA,MAAM,mBAAmB;wCAAuC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;;CASzF,CAAC;AAIF,QAAA,MAAM,kBAAkB;qCAIrB,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;CAUnD,CAAC;AAGF,OAAO,EACH,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EACrB,CAAC"}
@@ -5,8 +5,11 @@ declare const DialogTrigger: React.ForwardRefExoticComponent<DialogPrimitive.Dia
5
5
  declare const DialogPortal: React.FC<DialogPrimitive.DialogPortalProps>;
6
6
  declare const DialogClose: React.ForwardRefExoticComponent<DialogPrimitive.DialogCloseProps & React.RefAttributes<HTMLButtonElement>>;
7
7
  declare const DialogOverlay: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
8
+ /** 弹窗宽度三档(px 硬值,与产品 DialogV2 规范一致):sm=480 / md=640 / lg=960,默认 sm */
9
+ type DialogSize = 'sm' | 'md' | 'lg';
8
10
  declare const DialogContent: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
9
11
  closeLabel?: string;
12
+ size?: DialogSize;
10
13
  } & React.RefAttributes<HTMLDivElement>>;
11
14
  declare const DialogHeader: {
12
15
  ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAK1D,QAAA,MAAM,MAAM,uCAAuB,CAAC;AAEpC,QAAA,MAAM,aAAa,8GAA0B,CAAC;AAE9C,QAAA,MAAM,YAAY,6CAAyB,CAAC;AAE5C,QAAA,MAAM,WAAW,4GAAwB,CAAC;AAE1C,QAAA,MAAM,aAAa,8JAYjB,CAAC;AAIH,QAAA,MAAM,aAAa;iBAEiE,MAAM;wCAmBxF,CAAC;AAGH,QAAA,MAAM,YAAY;8BAA6B,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAElF,CAAC;AAGF,QAAA,MAAM,YAAY;8BAA6B,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAKlF,CAAC;AAGF,QAAA,MAAM,WAAW,oKASf,CAAC;AAGH,QAAA,MAAM,iBAAiB,8KASrB,CAAC;AAGH,OAAO,EACH,MAAM,EACN,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,iBAAiB,EACpB,CAAC"}
1
+ {"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAM1D,QAAA,MAAM,MAAM,uCAAuB,CAAC;AAEpC,QAAA,MAAM,aAAa,8GAA0B,CAAC;AAE9C,QAAA,MAAM,YAAY,6CAAyB,CAAC;AAE5C,QAAA,MAAM,WAAW,4GAAwB,CAAC;AAE1C,QAAA,MAAM,aAAa,8JAYjB,CAAC;AAGH,qEAAqE;AACrE,KAAK,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AASrC,QAAA,MAAM,aAAa;iBAGE,MAAM;WACZ,UAAU;wCAuCvB,CAAC;AAGH,QAAA,MAAM,YAAY;8BAA6B,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAElF,CAAC;AAGF,QAAA,MAAM,YAAY;8BAA6B,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;;CAKlF,CAAC;AAGF,QAAA,MAAM,WAAW,oKAYf,CAAC;AAGH,QAAA,MAAM,iBAAiB,8KASrB,CAAC;AAGH,OAAO,EACH,MAAM,EACN,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,iBAAiB,EACpB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
2
+ declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "nonce" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
3
3
  value?: string;
4
4
  onChange?: (newValue: string) => unknown;
5
5
  maxLength: number;
@@ -9,10 +9,11 @@ declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHT
9
9
  pasteTransformer?: (pasted: string) => string;
10
10
  containerClassName?: string;
11
11
  noScriptCSSFallback?: string | null;
12
+ nonce?: string;
12
13
  } & {
13
14
  render: (props: import('input-otp').RenderProps) => React.ReactNode;
14
15
  children?: never;
15
- } & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
16
+ } & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "nonce" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
16
17
  value?: string;
17
18
  onChange?: (newValue: string) => unknown;
18
19
  maxLength: number;
@@ -22,6 +23,7 @@ declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHT
22
23
  pasteTransformer?: (pasted: string) => string;
23
24
  containerClassName?: string;
24
25
  noScriptCSSFallback?: string | null;
26
+ nonce?: string;
25
27
  } & {
26
28
  render?: never;
27
29
  children: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"input-otp.d.ts","sourceRoot":"","sources":["../../../src/components/ui/input-otp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,QAAA,MAAM,QAAQ;;;;;kBAUC,GAAG;;;;;;;;;;;;;kBAAH,GAAG;;;;;;;;2FAGhB,CAAC;AAGH,QAAA,MAAM,aAAa,mKAIlB,CAAC;AAGF,QAAA,MAAM,YAAY;WAEmC,MAAM;wCAuBzD,CAAC;AAGH,QAAA,MAAM,iBAAiB,mKAMtB,CAAC;AAGF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"input-otp.d.ts","sourceRoot":"","sources":["../../../src/components/ui/input-otp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,QAAA,MAAM,QAAQ;;;;;kBAUC,GAAG;;;;;;;;;;;;;;kBAAH,GAAG;;;;;;;;;2FAGhB,CAAC;AAGH,QAAA,MAAM,aAAa,mKAIlB,CAAC;AAGF,QAAA,MAAM,YAAY;WAEmC,MAAM;wCAuBzD,CAAC;AAGH,QAAA,MAAM,iBAAiB,mKAMtB,CAAC;AAGF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * PromptPicker —— 一组「起点选项」。
4
+ *
5
+ * 用户点其中一条,这条对应的内容由**页面**放进旁边的输入框,列表随即退场;
6
+ * 输入框里那条内容被删掉,列表又回来。支持一层与两层两种形态。
7
+ *
8
+ * 规格来源:`2026-08-25-prompt-picker-component-design.md`(lin 提出)。
9
+ *
10
+ * ## 三条硬规则(照抄自规格,改动前先回去读)
11
+ *
12
+ * 1. **任何「进入」都必须有对应的「退出」,且退出必须看得见。** 上一版之所以重做,就是
13
+ * 因为「选了某一条就再也回不到起始状态」—— 隐藏式操作(再点一次取消)不算退路。
14
+ * 2. **一层模式不做选中高亮。** 内容已经在输入框里了,再在胶囊上亮一次是同一件事表示
15
+ * 两遍,会产生「看着不同、其实一样」的冗余状态。第二层顶部那条分类的高亮属于
16
+ * **面包屑**,不是选中态,两者不要混。
17
+ * 3. **列表退场是隐藏,不是销毁。** 列表本体用切 display 类藏(仍在 DOM 里),回来时
18
+ * 顺序不变。
19
+ *
20
+ * ## 与规格的两处偏离(lin 裁定 2026-08-25)
21
+ *
22
+ * 规格 §3 原写「点第二层条目 → 列表隐藏,**顶部那条分类保留**」+「删掉内容 →
23
+ * **回到第二层**(用户还在那个分类里)」。现改为:
24
+ *
25
+ * 1. **面包屑与列表同进同退** —— 内容进输入框后整个选项区一起消失。
26
+ * 2. **清空后回第一层、重新开始** —— 不再保留所处分类。
27
+ *
28
+ * 结果:组件只有「在选」「已选(全部退场)」两个可见状态,没有中间态。
29
+ * 规则 1 仍成立 —— 退出是**输入框上那个 ×**(页面侧,规格 §7 要求它必须存在且入口
30
+ * 可见)。它现在是唯一退路,接入时漏做就真的回不去了。
31
+ *
32
+ * ## 谁管什么
33
+ *
34
+ * | 事情 | 归属 |
35
+ * |---|---|
36
+ * | 现在在第几层、第一层选了哪个 | **组件内部 state** |
37
+ * | 列表显示还是隐藏 | **页面**(经 `hasContent` 下发),组件不自作主张 |
38
+ * | 点了一条之后往输入框放什么内容 | **页面**(`onPick` 回调里做) |
39
+ * | 输入框里那条内容怎么删、× 长什么样 | **页面** |
40
+ *
41
+ * 组件不 import 任何输入框相关的东西,也不读全局 store,不写死任何业务概念 ——
42
+ * 它将来要用在首页 Chat、编辑器 Growth Agent 面板等任何「一组预制起点」的地方。
43
+ *
44
+ * ## 已知取舍(lin 拍的,实现时不要自行改回去)
45
+ *
46
+ * 改成「点了就退场」之后,**换起点从 1 步变成 2 步**:先删掉输入框里那条 → 列表回来
47
+ * → 再选另一条。这与更早一轮「五条要能随意切换」的要求冲突,换来的是没有冗余状态、
48
+ * 状态只有一处表示。
49
+ */
50
+ export interface PromptPickerItem {
51
+ /** 稳定标识,用于回传与去重。**不要用文案当 id** —— 早期版本用文案反查条目,脆 */
52
+ id: string;
53
+ /** 胶囊上显示的那一行。一行显示不下时截断,全文走 title 悬停 */
54
+ label: string;
55
+ /** 可选:一行放不下的补充说明,走原生 title 悬停提示 */
56
+ hint?: string;
57
+ /**
58
+ * 可选。有 children 即为第一层分类节点(两层模式);没有则是叶子节点,点了就 onPick。
59
+ * **只支持两层,不要做递归多层。**
60
+ */
61
+ children?: PromptPickerItem[];
62
+ /**
63
+ * 可选图标。⚠️ **一组条目全用同一个图标时不要传** —— 它不携带任何用于选择的信息,
64
+ * 只会在每行左边留一段空白。只有各条图标不同、且图标在编码类别时才传。
65
+ * 不传时整格不渲染(不是渲染一个空 span)。
66
+ */
67
+ icon?: React.ReactNode;
68
+ }
69
+ export interface PromptPickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
70
+ items: PromptPickerItem[];
71
+ /**
72
+ * 用户点了一个叶子条目。页面据此把对应内容放进输入框。
73
+ * 组件不知道「内容」是什么 —— 那是页面的事。
74
+ */
75
+ onPick: (item: PromptPickerItem) => void;
76
+ /**
77
+ * 输入框里当前有没有本组件放进去的那条内容。
78
+ * true → 列表隐藏;false → 列表出现。**这是列表显隐的唯一依据**,
79
+ * 组件内部不自己记「我放过东西了」。
80
+ */
81
+ hasContent: boolean;
82
+ /**
83
+ * ⚠️ **当前没有触发点,保留为将来的钩子。**
84
+ *
85
+ * 原设计是「第二层点顶部 × 时调用,让页面清掉输入框里那条内容」。但 2026-08-25 改成
86
+ * 「内容进输入框后面包屑与列表一起退场」之后,× 只在输入框为空时才可见 —— 也就
87
+ * 永远不需要请页面清空了。清空的唯一入口在页面自己那个 ×(规格 §7)。
88
+ *
89
+ * 留着而不删:若将来恢复「内容在框里时面包屑仍可见」,这个回调是现成的接口。
90
+ * 不想留可以直接删,组件内部已无任何调用。
91
+ */
92
+ onClear?: () => void;
93
+ /** 可选:列表上方一行小字(如「为你推荐」)。不传则不渲染 */
94
+ lead?: string;
95
+ /** 第二层顶部分类项的 × 的读屏文案。库不做 i18n,消费方传译文,默认英文 */
96
+ backLabel?: string;
97
+ }
98
+ declare const PromptPicker: React.ForwardRefExoticComponent<PromptPickerProps & React.RefAttributes<HTMLDivElement>>;
99
+ export { PromptPicker };
100
+ //# sourceMappingURL=prompt-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-picker.d.ts","sourceRoot":"","sources":["../../../src/components/ui/prompt-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,WAAW,gBAAgB;IAC7B,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B;;;;OAIG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC7F,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B;;;OAGG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACzC;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AA8BD,QAAA,MAAM,YAAY,0FA4GjB,CAAC;AAGF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -3,6 +3,21 @@ import * as SelectPrimitive from '@radix-ui/react-select';
3
3
  declare const Select: React.FC<SelectPrimitive.SelectProps>;
4
4
  declare const SelectGroup: React.ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & React.RefAttributes<HTMLDivElement>>;
5
5
  declare const SelectValue: React.ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
6
+ /**
7
+ * 下拉触发器的样式 —— **单独导出,因为不止 `SelectTrigger` 需要它**。
8
+ *
9
+ * Radix `Select` 的 value 是标量,装不了「多选筛选器」(一次选多个类型 / 多个状态)。
10
+ * 那类控件只能自己用 Popover + Checkbox 搭,但它**必须和 Select 长得一模一样** ——
11
+ * 同一排筛选器里两种触发器,用户看到的是「这两个东西不是一类」。
12
+ *
13
+ * 此前的做法是在使用点拿 `Button` 去模仿这串 class,结果必然漂移:
14
+ * 2026-08-28 实测两者文字色(#12262b vs #344563)、底色(不透明白 vs 透明)都不同,
15
+ * 而高度 / 圆角 / 字号是上一轮手工对齐的 —— 手工对齐的东西下次改库时又会散开。
16
+ * 所以样式收在这里一处,多选触发器 `cn(selectTriggerClassName, …)` 复用。
17
+ *
18
+ * `w-full` 不在里面:Select 自己要撑满容器,而筛选器通常按内容宽。各自加。
19
+ */
20
+ export declare const selectTriggerClassName = "flex h-[32px] items-center justify-between whitespace-nowrap rounded-[var(--pt-radius-md)] border border-input bg-transparent px-[12px] py-[8px] text-[13px] leading-[20px] ring-offset-background transition-colors placeholder:text-muted-foreground enabled:hover:border-neutral focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:text-destructive aria-[invalid=true]:enabled:hover:border-destructive aria-[invalid=true]:focus-visible:ring-destructive/30 [&>span]:line-clamp-1";
6
21
  declare const SelectTrigger: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
7
22
  declare const SelectScrollUpButton: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollUpButtonProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
8
23
  declare const SelectScrollDownButton: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectScrollDownButtonProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAK1D,QAAA,MAAM,MAAM,uCAAuB,CAAC;AAEpC,QAAA,MAAM,WAAW,yGAAwB,CAAC;AAE1C,QAAA,MAAM,WAAW,0GAAwB,CAAC;AAE1C,QAAA,MAAM,aAAa,oKAkBjB,CAAC;AAGH,QAAA,MAAM,oBAAoB,qKAWxB,CAAC;AAGH,QAAA,MAAM,sBAAsB,uKAW1B,CAAC;AAGH,QAAA,MAAM,aAAa,8JA6BjB,CAAC;AAGH,QAAA,MAAM,WAAW,4JASf,CAAC;AAGH,QAAA,MAAM,UAAU,2JAmBd,CAAC;AAGH,QAAA,MAAM,eAAe,gKASnB,CAAC;AAGH,OAAO,EACH,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACzB,CAAC"}
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAK1D,QAAA,MAAM,MAAM,uCAAuB,CAAC;AAEpC,QAAA,MAAM,WAAW,yGAAwB,CAAC;AAE1C,QAAA,MAAM,WAAW,0GAAwB,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,6lBAC2jB,CAAC;AAE/lB,QAAA,MAAM,aAAa,oKAejB,CAAC;AAGH,QAAA,MAAM,oBAAoB,qKAWxB,CAAC;AAGH,QAAA,MAAM,sBAAsB,uKAW1B,CAAC;AAGH,QAAA,MAAM,aAAa,8JA6BjB,CAAC;AAGH,QAAA,MAAM,WAAW,4JASf,CAAC;AAGH,QAAA,MAAM,UAAU,2JAmBd,CAAC;AAGH,QAAA,MAAM,eAAe,gKASnB,CAAC;AAGH,OAAO,EACH,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACzB,CAAC"}