@teamix-evo/ui 0.1.1 → 0.3.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 +184 -184
- package/manifest.json +680 -492
- package/package.json +20 -10
- package/src/components/accordion/accordion.meta.md +5 -4
- package/src/components/accordion/accordion.stories.tsx +14 -9
- package/src/components/accordion/accordion.tsx +104 -8
- package/src/components/affix/affix.meta.md +20 -2
- package/src/components/affix/affix.stories.tsx +102 -25
- package/src/components/affix/affix.tsx +79 -9
- package/src/components/alert/alert.meta.md +44 -13
- package/src/components/alert/alert.stories.tsx +66 -21
- package/src/components/alert/alert.tsx +81 -34
- package/src/components/alert-dialog/alert-dialog.meta.md +61 -16
- package/src/components/alert-dialog/alert-dialog.stories.tsx +145 -3
- package/src/components/alert-dialog/alert-dialog.tsx +60 -13
- package/src/components/anchor/anchor.meta.md +8 -3
- package/src/components/anchor/anchor.stories.tsx +3 -3
- package/src/components/anchor/anchor.tsx +2 -2
- package/src/components/app/app.meta.md +9 -4
- package/src/components/app/app.stories.tsx +9 -7
- package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -3
- package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
- package/src/components/auto-complete/auto-complete.meta.md +14 -6
- package/src/components/auto-complete/auto-complete.stories.tsx +47 -4
- package/src/components/auto-complete/auto-complete.tsx +119 -71
- package/src/components/avatar/avatar.meta.md +6 -7
- package/src/components/avatar/avatar.stories.tsx +21 -3
- package/src/components/avatar/avatar.tsx +24 -23
- package/src/components/badge/badge.meta.md +10 -9
- package/src/components/badge/badge.stories.tsx +2 -2
- package/src/components/badge/badge.tsx +9 -15
- package/src/components/breadcrumb/breadcrumb.meta.md +27 -7
- package/src/components/breadcrumb/breadcrumb.stories.tsx +127 -4
- package/src/components/breadcrumb/breadcrumb.tsx +22 -8
- package/src/components/button/button.meta.md +258 -21
- package/src/components/button/button.stories.tsx +549 -41
- package/src/components/button/button.tsx +335 -33
- package/src/components/button/demo/as-child.tsx +24 -0
- package/src/components/button/demo/basic.tsx +8 -0
- package/src/components/button/demo/block.tsx +16 -0
- package/src/components/button/demo/loading.tsx +19 -0
- package/src/components/button/demo/shapes.tsx +18 -0
- package/src/components/button/demo/sizes.tsx +19 -0
- package/src/components/button/demo/variants.tsx +19 -0
- package/src/components/button/demo/with-icon.tsx +20 -0
- package/src/components/calendar/calendar.meta.md +13 -3
- package/src/components/calendar/calendar.stories.tsx +6 -6
- package/src/components/calendar/calendar.tsx +73 -8
- package/src/components/card/card.meta.md +27 -5
- package/src/components/card/card.stories.tsx +42 -3
- package/src/components/card/card.tsx +146 -63
- package/src/components/carousel/carousel.meta.md +4 -3
- package/src/components/carousel/carousel.stories.tsx +11 -6
- package/src/components/cascader/cascader.meta.md +47 -17
- package/src/components/cascader/cascader.stories.tsx +22 -10
- package/src/components/cascader/cascader.tsx +428 -85
- package/src/components/checkbox/checkbox.meta.md +75 -7
- package/src/components/checkbox/checkbox.stories.tsx +161 -3
- package/src/components/checkbox/checkbox.tsx +77 -9
- package/src/components/collapsible/collapsible.meta.md +14 -6
- package/src/components/collapsible/collapsible.stories.tsx +10 -2
- package/src/components/collapsible/collapsible.tsx +93 -6
- package/src/components/color-picker/color-picker.meta.md +12 -7
- package/src/components/color-picker/color-picker.stories.tsx +86 -7
- package/src/components/color-picker/color-picker.tsx +20 -9
- package/src/components/command/command.meta.md +29 -13
- package/src/components/command/command.stories.tsx +4 -4
- package/src/components/command/command.tsx +19 -8
- package/src/components/context-menu/context-menu.meta.md +11 -8
- package/src/components/context-menu/context-menu.stories.tsx +11 -3
- package/src/components/context-menu/context-menu.tsx +21 -8
- package/src/components/data-table/data-table.meta.md +6 -5
- package/src/components/data-table/data-table.stories.tsx +13 -6
- package/src/components/data-table/data-table.tsx +2 -2
- package/src/components/date-picker/date-picker.meta.md +88 -19
- package/src/components/date-picker/date-picker.stories.tsx +55 -5
- package/src/components/date-picker/date-picker.tsx +1489 -91
- package/src/components/descriptions/descriptions.meta.md +10 -5
- package/src/components/descriptions/descriptions.stories.tsx +3 -3
- package/src/components/descriptions/descriptions.tsx +22 -14
- package/src/components/dialog/dialog.meta.md +76 -13
- package/src/components/dialog/dialog.stories.tsx +182 -20
- package/src/components/dialog/dialog.tsx +67 -15
- package/src/components/dialog/imperative.tsx +252 -0
- package/src/components/drawer/drawer.meta.md +33 -34
- package/src/components/drawer/drawer.stories.tsx +29 -12
- package/src/components/drawer/drawer.tsx +22 -113
- package/src/components/dropdown-menu/dropdown-menu.meta.md +78 -10
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +88 -2
- package/src/components/dropdown-menu/dropdown-menu.tsx +24 -10
- package/src/components/ellipsis/ellipsis.meta.md +87 -0
- package/src/components/ellipsis/ellipsis.stories.tsx +72 -0
- package/src/components/ellipsis/ellipsis.tsx +153 -0
- package/src/components/empty/empty.meta.md +9 -4
- package/src/components/empty/empty.stories.tsx +4 -4
- package/src/components/empty/empty.tsx +10 -3
- package/src/components/field/field.meta.md +47 -9
- package/src/components/field/field.stories.tsx +385 -5
- package/src/components/field/field.tsx +263 -35
- package/src/components/filter-bar/filter-bar.meta.md +92 -0
- package/src/components/filter-bar/filter-bar.stories.tsx +1083 -0
- package/src/components/filter-bar/filter-bar.tsx +568 -0
- package/src/components/flex/flex.meta.md +54 -6
- package/src/components/flex/flex.stories.tsx +107 -20
- package/src/components/flex/flex.tsx +27 -4
- package/src/components/float-button/float-button.meta.md +8 -3
- package/src/components/float-button/float-button.stories.tsx +9 -7
- package/src/components/float-button/float-button.tsx +1 -1
- package/src/components/form/form.meta.md +39 -17
- package/src/components/form/form.stories.tsx +350 -3
- package/src/components/form/form.tsx +101 -35
- package/src/components/grid/grid.meta.md +7 -2
- package/src/components/grid/grid.stories.tsx +6 -4
- package/src/components/hover-card/hover-card.meta.md +20 -9
- package/src/components/hover-card/hover-card.stories.tsx +34 -5
- package/src/components/hover-card/hover-card.tsx +51 -13
- package/src/components/icon/DEVELOPMENT.md +809 -0
- package/src/components/icon/icon.meta.md +170 -0
- package/src/components/icon/icon.stories.tsx +344 -0
- package/src/components/icon/icon.tsx +248 -0
- package/src/components/image/image.meta.md +9 -4
- package/src/components/image/image.stories.tsx +3 -3
- package/src/components/image/image.tsx +6 -4
- package/src/components/input/demo/basic.tsx +12 -0
- package/src/components/input/demo/clearable.tsx +21 -0
- package/src/components/input/demo/show-count.tsx +18 -0
- package/src/components/input/demo/sizes.tsx +15 -0
- package/src/components/input/input.meta.md +39 -33
- package/src/components/input/input.stories.tsx +62 -35
- package/src/components/input/input.tsx +97 -98
- package/src/components/input-group/input-group.meta.md +54 -22
- package/src/components/input-group/input-group.stories.tsx +49 -16
- package/src/components/input-group/input-group.tsx +44 -8
- package/src/components/input-number/input-number.meta.md +64 -7
- package/src/components/input-number/input-number.stories.tsx +46 -8
- package/src/components/input-number/input-number.tsx +99 -26
- package/src/components/input-otp/input-otp.meta.md +4 -3
- package/src/components/input-otp/input-otp.stories.tsx +3 -3
- package/src/components/input-otp/input-otp.tsx +1 -1
- package/src/components/item/item.meta.md +8 -3
- package/src/components/item/item.stories.tsx +8 -5
- package/src/components/item/item.tsx +7 -6
- package/src/components/kbd/kbd.meta.md +13 -4
- package/src/components/kbd/kbd.stories.tsx +4 -4
- package/src/components/kbd/kbd.tsx +10 -5
- package/src/components/label/label.meta.md +18 -10
- package/src/components/label/label.stories.tsx +64 -6
- package/src/components/label/label.tsx +91 -19
- package/src/components/masonry/masonry.meta.md +8 -3
- package/src/components/masonry/masonry.stories.tsx +7 -5
- package/src/components/masonry/masonry.tsx +1 -0
- package/src/components/mentions/mentions.meta.md +36 -6
- package/src/components/mentions/mentions.stories.tsx +120 -6
- package/src/components/mentions/mentions.tsx +11 -5
- package/src/components/menubar/menubar.meta.md +30 -12
- package/src/components/menubar/menubar.stories.tsx +62 -2
- package/src/components/menubar/menubar.tsx +9 -9
- package/src/components/native-select/native-select.meta.md +8 -3
- package/src/components/native-select/native-select.stories.tsx +8 -5
- package/src/components/native-select/native-select.tsx +1 -1
- package/src/components/navigation-menu/navigation-menu.meta.md +19 -9
- package/src/components/navigation-menu/navigation-menu.stories.tsx +112 -9
- package/src/components/navigation-menu/navigation-menu.tsx +8 -4
- package/src/components/notification/notification.meta.md +52 -10
- package/src/components/notification/notification.stories.tsx +11 -9
- package/src/components/notification/notification.tsx +36 -21
- package/src/components/page-header/DEVELOPMENT.md +842 -0
- package/src/components/page-header/page-header.meta.md +208 -0
- package/src/components/page-header/page-header.stories.tsx +421 -0
- package/src/components/page-header/page-header.tsx +281 -0
- package/src/components/pagination/pagination.meta.md +140 -37
- package/src/components/pagination/pagination.stories.tsx +232 -10
- package/src/components/pagination/pagination.tsx +355 -63
- package/src/components/popconfirm/popconfirm.meta.md +9 -4
- package/src/components/popconfirm/popconfirm.stories.tsx +3 -4
- package/src/components/popconfirm/popconfirm.tsx +2 -2
- package/src/components/popover/popover.meta.md +62 -5
- package/src/components/popover/popover.stories.tsx +83 -7
- package/src/components/popover/popover.tsx +77 -28
- package/src/components/progress/progress.meta.md +38 -6
- package/src/components/progress/progress.stories.tsx +3 -3
- package/src/components/progress/progress.tsx +24 -16
- package/src/components/radio-group/radio-group.meta.md +79 -7
- package/src/components/radio-group/radio-group.stories.tsx +39 -3
- package/src/components/radio-group/radio-group.tsx +149 -18
- package/src/components/rate/rate.meta.md +35 -4
- package/src/components/rate/rate.stories.tsx +13 -5
- package/src/components/rate/rate.tsx +37 -10
- package/src/components/resizable/resizable.meta.md +7 -4
- package/src/components/resizable/resizable.stories.tsx +6 -6
- package/src/components/resizable/resizable.tsx +1 -1
- package/src/components/result/result.meta.md +7 -2
- package/src/components/result/result.stories.tsx +4 -8
- package/src/components/result/result.tsx +24 -15
- package/src/components/scroll-area/scroll-area.meta.md +4 -3
- package/src/components/scroll-area/scroll-area.stories.tsx +12 -4
- package/src/components/scroll-area/scroll-area.tsx +3 -3
- package/src/components/segmented/segmented.meta.md +7 -4
- package/src/components/segmented/segmented.stories.tsx +37 -8
- package/src/components/segmented/segmented.tsx +15 -7
- package/src/components/select/select.meta.md +197 -52
- package/src/components/select/select.stories.tsx +238 -63
- package/src/components/select/select.tsx +718 -171
- package/src/components/separator/separator.meta.md +4 -3
- package/src/components/separator/separator.stories.tsx +3 -3
- package/src/components/separator/separator.tsx +3 -7
- package/src/components/sheet/sheet.meta.md +32 -16
- package/src/components/sheet/sheet.stories.tsx +116 -10
- package/src/components/sheet/sheet.tsx +116 -29
- package/src/components/sidebar/sidebar.meta.md +37 -18
- package/src/components/sidebar/sidebar.stories.tsx +701 -29
- package/src/components/sidebar/sidebar.tsx +615 -142
- package/src/components/skeleton/skeleton.meta.md +4 -5
- package/src/components/skeleton/skeleton.stories.tsx +4 -4
- package/src/components/skeleton/skeleton.tsx +7 -7
- package/src/components/slider/slider.meta.md +57 -5
- package/src/components/slider/slider.stories.tsx +58 -6
- package/src/components/slider/slider.tsx +154 -13
- package/src/components/sonner/sonner.meta.md +58 -7
- package/src/components/sonner/sonner.stories.tsx +78 -5
- package/src/components/sonner/sonner.tsx +137 -8
- package/src/components/spinner/spinner.meta.md +62 -13
- package/src/components/spinner/spinner.stories.tsx +66 -14
- package/src/components/spinner/spinner.tsx +111 -9
- package/src/components/statistic/statistic.meta.md +7 -2
- package/src/components/statistic/statistic.stories.tsx +3 -7
- package/src/components/statistic/statistic.tsx +5 -6
- package/src/components/steps/steps.meta.md +18 -4
- package/src/components/steps/steps.stories.tsx +43 -3
- package/src/components/steps/steps.tsx +15 -12
- package/src/components/switch/switch.meta.md +51 -5
- package/src/components/switch/switch.stories.tsx +6 -6
- package/src/components/switch/switch.tsx +109 -41
- package/src/components/table/table.meta.md +17 -6
- package/src/components/table/table.stories.tsx +10 -5
- package/src/components/table/table.tsx +4 -4
- package/src/components/tabs/tabs.meta.md +38 -25
- package/src/components/tabs/tabs.stories.tsx +111 -25
- package/src/components/tabs/tabs.tsx +125 -54
- package/src/components/tag/tag.meta.md +105 -40
- package/src/components/tag/tag.stories.tsx +189 -16
- package/src/components/tag/tag.tsx +222 -21
- package/src/components/textarea/textarea.meta.md +35 -19
- package/src/components/textarea/textarea.stories.tsx +32 -6
- package/src/components/textarea/textarea.tsx +33 -9
- package/src/components/time-picker/time-picker.meta.md +124 -32
- package/src/components/time-picker/time-picker.stories.tsx +85 -15
- package/src/components/time-picker/time-picker.tsx +913 -61
- package/src/components/timeline/timeline.meta.md +14 -6
- package/src/components/timeline/timeline.stories.tsx +37 -7
- package/src/components/timeline/timeline.tsx +35 -14
- package/src/components/toggle/toggle.meta.md +5 -4
- package/src/components/toggle/toggle.stories.tsx +4 -4
- package/src/components/toggle/toggle.tsx +4 -3
- package/src/components/toggle-group/toggle-group.meta.md +5 -4
- package/src/components/toggle-group/toggle-group.stories.tsx +3 -3
- package/src/components/toggle-group/toggle-group.tsx +2 -2
- package/src/components/tooltip/tooltip.meta.md +55 -5
- package/src/components/tooltip/tooltip.stories.tsx +42 -5
- package/src/components/tooltip/tooltip.tsx +81 -21
- package/src/components/tour/tour.meta.md +9 -4
- package/src/components/tour/tour.stories.tsx +3 -3
- package/src/components/tour/tour.tsx +4 -4
- package/src/components/transfer/transfer.meta.md +11 -6
- package/src/components/transfer/transfer.stories.tsx +4 -8
- package/src/components/transfer/transfer.tsx +28 -21
- package/src/components/tree/tree.meta.md +63 -5
- package/src/components/tree/tree.stories.tsx +31 -12
- package/src/components/tree/tree.tsx +9 -8
- package/src/components/tree-select/tree-select.meta.md +59 -8
- package/src/components/tree-select/tree-select.stories.tsx +3 -3
- package/src/components/tree-select/tree-select.tsx +42 -7
- package/src/components/typography/typography.meta.md +61 -14
- package/src/components/typography/typography.stories.tsx +12 -11
- package/src/components/typography/typography.tsx +43 -28
- package/src/components/upload/upload.meta.md +49 -4
- package/src/components/upload/upload.stories.tsx +72 -12
- package/src/components/upload/upload.tsx +170 -37
- package/src/components/watermark/watermark.meta.md +7 -2
- package/src/components/watermark/watermark.stories.tsx +101 -9
- package/src/components/watermark/watermark.tsx +1 -0
- package/src/hooks/use-breakpoint.ts +117 -0
- package/src/hooks/use-debounce-callback.ts +52 -0
- package/src/hooks/use-mobile.ts +23 -0
- package/src/stories/theme-tokens.stories.tsx +747 -0
- package/src/utils/trigger-input.ts +53 -0
- package/src/components/button-group/button-group.meta.md +0 -92
- package/src/components/button-group/button-group.stories.tsx +0 -90
- package/src/components/button-group/button-group.tsx +0 -75
- package/src/components/combobox/combobox.meta.md +0 -93
- package/src/components/combobox/combobox.stories.tsx +0 -55
- package/src/components/combobox/combobox.tsx +0 -130
- package/src/components/space/space.meta.md +0 -94
- package/src/components/space/space.stories.tsx +0 -94
- package/src/components/space/space.tsx +0 -106
|
@@ -177,12 +177,12 @@ const TreeRow: React.FC<NodeProps> = ({
|
|
|
177
177
|
<li role="treeitem" aria-expanded={hasChildren ? isOpen : undefined}>
|
|
178
178
|
<div
|
|
179
179
|
className={cn(
|
|
180
|
-
'flex items-center gap-
|
|
181
|
-
selectable && !node.disabled && 'hover:bg-accent',
|
|
182
|
-
isSelected && 'bg-accent text-accent-foreground',
|
|
180
|
+
'group/tree-row flex items-center gap-1.5 rounded-md py-1 pr-2 text-xs transition-colors',
|
|
181
|
+
selectable && !node.disabled && 'hover:bg-accent/50',
|
|
182
|
+
isSelected && 'bg-accent font-medium text-accent-foreground',
|
|
183
183
|
node.disabled && 'cursor-not-allowed opacity-50',
|
|
184
184
|
)}
|
|
185
|
-
style={{ paddingLeft: `${depth *
|
|
185
|
+
style={{ paddingLeft: `${depth * 20 + 4}px` }}
|
|
186
186
|
>
|
|
187
187
|
{hasChildren ? (
|
|
188
188
|
<button
|
|
@@ -190,11 +190,11 @@ const TreeRow: React.FC<NodeProps> = ({
|
|
|
190
190
|
aria-label={isOpen ? '收起' : '展开'}
|
|
191
191
|
onClick={() => onToggleExpand(node.key)}
|
|
192
192
|
disabled={node.disabled}
|
|
193
|
-
className="flex size-5 shrink-0 items-center justify-center rounded-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
193
|
+
className="flex size-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
194
194
|
>
|
|
195
195
|
<ChevronRight
|
|
196
196
|
className={cn(
|
|
197
|
-
'size-3
|
|
197
|
+
'size-3 transition-transform duration-150',
|
|
198
198
|
isOpen && 'rotate-90',
|
|
199
199
|
)}
|
|
200
200
|
/>
|
|
@@ -282,7 +282,8 @@ const Tree = React.forwardRef<HTMLDivElement, TreeProps>(
|
|
|
282
282
|
return [];
|
|
283
283
|
}, [defaultExpandAll, defaultExpandedKeys, data]);
|
|
284
284
|
|
|
285
|
-
const [internalExpanded, setInternalExpanded] =
|
|
285
|
+
const [internalExpanded, setInternalExpanded] =
|
|
286
|
+
React.useState<string[]>(initialExpanded);
|
|
286
287
|
const [internalSelected, setInternalSelected] = React.useState<string[]>(
|
|
287
288
|
defaultSelectedKeys ?? [],
|
|
288
289
|
);
|
|
@@ -339,7 +340,7 @@ const Tree = React.forwardRef<HTMLDivElement, TreeProps>(
|
|
|
339
340
|
};
|
|
340
341
|
|
|
341
342
|
return (
|
|
342
|
-
<div ref={ref} className={cn('text-
|
|
343
|
+
<div ref={ref} className={cn('text-xs', className)} {...props}>
|
|
343
344
|
<ul role="tree" className="flex flex-col gap-0.5">
|
|
344
345
|
{data.map((n) => (
|
|
345
346
|
<TreeRow
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: tree-select
|
|
3
3
|
name: TreeSelect
|
|
4
|
+
displayName: 树选择
|
|
4
5
|
type: component
|
|
5
|
-
category:
|
|
6
|
+
category: data-entry
|
|
6
7
|
since: 0.1.0
|
|
7
|
-
package:
|
|
8
|
+
package: '@teamix-evo/ui'
|
|
8
9
|
---
|
|
9
10
|
|
|
10
|
-
# TreeSelect
|
|
11
|
+
# TreeSelect 树选择
|
|
11
12
|
|
|
12
13
|
树形下拉选择 — antd 独有补足。**等价 antd `TreeSelect`**。把 `Tree` 嵌入 Popover,提供**单选**(selectable)或**多选**(checkable)两种模式 — 组织架构 / 分类树形选择 / 文件夹路径选择常用。
|
|
13
14
|
|
|
@@ -23,6 +24,8 @@ package: "@teamix-evo/ui"
|
|
|
23
24
|
- 严格级联(每层必选一个,不可跨层) → `Cascader`
|
|
24
25
|
- 树形浏览(不需要"选中"语义) → `Tree`
|
|
25
26
|
|
|
27
|
+
## Props
|
|
28
|
+
|
|
26
29
|
<!-- auto:props:begin -->
|
|
27
30
|
| 名称 | 类型 | 默认值 | 必填 | 说明 |
|
|
28
31
|
| --- | --- | --- | --- | --- |
|
|
@@ -35,9 +38,12 @@ package: "@teamix-evo/ui"
|
|
|
35
38
|
| `placeholder` | `string` | `"请选择"` | – | 占位文本。 |
|
|
36
39
|
| `disabled` | `boolean` | – | – | 整体禁用。 |
|
|
37
40
|
| `className` | `string` | – | – | 触发器 className。 |
|
|
38
|
-
| `size` | `'sm' \| 'default' \| 'lg'` | `"default"` | – | 触发器尺寸。 |
|
|
41
|
+
| `size` | `'sm' \| 'md' \| 'default' \| 'lg'` | `"default"` | – | 触发器尺寸。 |
|
|
42
|
+
| `allowClear` | `boolean` | `false` | – | 显示清除按钮(antd `allowClear` 并集) — 触发器有值时右侧出现 ✕,点击清空。 |
|
|
39
43
|
<!-- auto:props:end -->
|
|
40
44
|
|
|
45
|
+
## 依赖
|
|
46
|
+
|
|
41
47
|
<!-- auto:deps:begin -->
|
|
42
48
|
### 同库依赖
|
|
43
49
|
|
|
@@ -46,8 +52,8 @@ package: "@teamix-evo/ui"
|
|
|
46
52
|
| Entry | 类型 | 描述 |
|
|
47
53
|
| --- | --- | --- |
|
|
48
54
|
| `cn` | util | Tailwind className 合并工具(clsx + tailwind-merge) |
|
|
49
|
-
| `button` | component | 通用按钮 — shadcn 实现 +
|
|
50
|
-
| `popover` | component | 可交互浮层 — Radix Popover + antd arrow
|
|
55
|
+
| `button` | component | 通用按钮 — shadcn 实现 + cloud-design 能力并集(loading / icon / shape / block / dashed variant / color 语义双 prop / disabledTooltip)。同文件合一导出 ButtonGroup + ButtonGroupText(等价 antd Space.Compact + cd SplitButton)。 |
|
|
56
|
+
| `popover` | component | 可交互浮层 — Radix Popover + antd arrow 并集,使用 showArrow 控制尖角(与 Tooltip / HoverCard 命名统一) |
|
|
51
57
|
| `tree` | component | 树形控件 — antd 独有补足。递归层级展示(目录、组织、分类),可展开 / 可选 / 可勾选(父子级联 + 半选),受控与非受控并存 |
|
|
52
58
|
|
|
53
59
|
### npm 依赖
|
|
@@ -92,9 +98,54 @@ const data = [
|
|
|
92
98
|
];
|
|
93
99
|
|
|
94
100
|
// 单选
|
|
95
|
-
<TreeSelect data={data} defaultExpandAll
|
|
101
|
+
<TreeSelect data={data} defaultExpandAll />;
|
|
96
102
|
|
|
97
103
|
// 多选 + 受控
|
|
98
104
|
const [v, setV] = React.useState<string[]>(['fe', 'be']);
|
|
99
|
-
<TreeSelect
|
|
105
|
+
<TreeSelect
|
|
106
|
+
data={data}
|
|
107
|
+
multiple
|
|
108
|
+
defaultExpandAll
|
|
109
|
+
value={v}
|
|
110
|
+
onChange={(next) => setV(next as string[])}
|
|
111
|
+
/>;
|
|
112
|
+
|
|
113
|
+
// 可清除(hover 时右侧出现 ✕)
|
|
114
|
+
<TreeSelect data={data} allowClear defaultValue="fe" />;
|
|
100
115
|
```
|
|
116
|
+
|
|
117
|
+
## TreeSelect 形态 — 旧库 API → 新库映射
|
|
118
|
+
|
|
119
|
+
> 旧库 `TreeSelect`(hybridcloud) → 新库 `TreeSelect`(命名一致)。
|
|
120
|
+
> 新库基于 Radix Popover + 内嵌 `Tree` 组件,触发器复用 `Button outline variant`。
|
|
121
|
+
|
|
122
|
+
### 命名映射
|
|
123
|
+
|
|
124
|
+
| 旧库 API | 新库 API | 备注 |
|
|
125
|
+
| --- | --- | --- |
|
|
126
|
+
| `dataSource` | `data` | 字段命名简化(对齐 React 习惯) |
|
|
127
|
+
| `treeDefaultExpandAll` | `defaultExpandAll` | 去 `tree` 前缀 |
|
|
128
|
+
| `treeCheckable` | `multiple` | 与 Select 多选 prop 命名统一 |
|
|
129
|
+
| `value` / `onChange(value, data)` | `value` / `onChange(value)` | 单参数化 |
|
|
130
|
+
| `size="small\|medium\|large"` | `size="sm\|md\|lg"` | 三档对齐 Button(24/32/36) |
|
|
131
|
+
| `hasClear` | `allowClear` | ✅ 本波次落地 — hover 触发器右侧显示 ✕ |
|
|
132
|
+
| `placeholder` | `placeholder` | 同名 |
|
|
133
|
+
| `disabled` | `disabled` | 同名 |
|
|
134
|
+
|
|
135
|
+
### 不修复 / 后续工序清单(报告 §3 P1)
|
|
136
|
+
|
|
137
|
+
> 以下 P1 缺失项**未在 TreeSelect 层补**,因为它们都依赖底层 `Tree` 组件先具备相应能力。**业务真有需求时**优先在 Tree 层做,然后 TreeSelect 透传 prop 即可。
|
|
138
|
+
|
|
139
|
+
- **showSearch + onSearch 搜索过滤**(P1):Tree 层先实现节点筛选高亮,TreeSelect 在 Popover 顶部加搜索框
|
|
140
|
+
- **loadData 异步加载**(P1):Tree 层先实现节点点击触发异步加载子节点,TreeSelect 透传
|
|
141
|
+
- **treeCheckStrictly 父子不关联**(P1):Tree 层 checkable 模式增 `checkStrictly` prop 关掉父子级联
|
|
142
|
+
- **treeCheckedStrategy 回填策略**(P1):Tree 层暴露 `checkedStrategy: 'all' \| 'parent' \| 'child'`,影响 onCheck 返回的 value 集合
|
|
143
|
+
- **useVirtual 虚拟滚动**(P2):Tree 层加 react-virtual 支持(> 500 节点时显著优化)
|
|
144
|
+
|
|
145
|
+
### 不修复(报告 §5 已明确)
|
|
146
|
+
|
|
147
|
+
- **`hasArrow` / `hasBorder`**:统一走 Button outline variant 视觉
|
|
148
|
+
- **`label` 内联标签**:外层用 `<Label>` 配合,组件内不内置
|
|
149
|
+
- **`popupStyle` / `popupClassName` / `popupProps`**:Popover 自身已有 `className`,无需中转
|
|
150
|
+
- **`isPreview` / `renderPreview`**:无预览态(antd 也已废弃)
|
|
151
|
+
- **`preserveNonExistentValue`**:简化处理,不识别的 key 直接舍去
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
3
|
import { TreeSelect } from './tree-select';
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof TreeSelect> = {
|
|
6
|
-
title: '
|
|
6
|
+
title: '数据录入 · Data Entry/TreeSelect',
|
|
7
7
|
component: TreeSelect,
|
|
8
8
|
tags: ['autodocs'],
|
|
9
9
|
parameters: {
|
|
10
10
|
docs: {
|
|
11
11
|
description: {
|
|
12
12
|
component:
|
|
13
|
-
'树形下拉 — Tree 嵌入 Popover
|
|
13
|
+
'树形下拉 — Tree 嵌入 Popover,单选(selectable)或多选(checkable)两种模式。组织架构 / 分类树形选择 / 文件夹路径选择常用。等价 antd `TreeSelect`。',
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
16
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ChevronDown } from 'lucide-react';
|
|
2
|
+
import { ChevronDown, X } from 'lucide-react';
|
|
3
3
|
|
|
4
4
|
import { cn } from '@/utils/cn';
|
|
5
5
|
import { Button } from '@/components/button/button';
|
|
@@ -43,7 +43,12 @@ export interface TreeSelectProps {
|
|
|
43
43
|
* 触发器尺寸。
|
|
44
44
|
* @default "default"
|
|
45
45
|
*/
|
|
46
|
-
size?: 'sm' | 'default' | 'lg';
|
|
46
|
+
size?: 'sm' | 'md' | 'default' | 'lg';
|
|
47
|
+
/**
|
|
48
|
+
* 显示清除按钮(antd `allowClear` 并集) — 触发器有值时右侧出现 ✕,点击清空。
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
allowClear?: boolean;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
function flattenLabelMap(nodes: TreeNode[]): Map<string, React.ReactNode> {
|
|
@@ -72,7 +77,8 @@ const TreeSelect = React.forwardRef<HTMLButtonElement, TreeSelectProps>(
|
|
|
72
77
|
placeholder = '请选择',
|
|
73
78
|
disabled = false,
|
|
74
79
|
className,
|
|
75
|
-
size = '
|
|
80
|
+
size = 'md',
|
|
81
|
+
allowClear = false,
|
|
76
82
|
},
|
|
77
83
|
ref,
|
|
78
84
|
) => {
|
|
@@ -105,7 +111,7 @@ const TreeSelect = React.forwardRef<HTMLButtonElement, TreeSelectProps>(
|
|
|
105
111
|
{display.map((d, i) => (
|
|
106
112
|
<span
|
|
107
113
|
key={i}
|
|
108
|
-
className="inline-flex rounded-
|
|
114
|
+
className="inline-flex items-center rounded-md bg-muted px-1.5 py-0.5 text-xs text-muted-foreground"
|
|
109
115
|
>
|
|
110
116
|
{d}
|
|
111
117
|
</span>
|
|
@@ -116,6 +122,18 @@ const TreeSelect = React.forwardRef<HTMLButtonElement, TreeSelectProps>(
|
|
|
116
122
|
return <span className="truncate">{display}</span>;
|
|
117
123
|
};
|
|
118
124
|
|
|
125
|
+
const hasValue = multiple
|
|
126
|
+
? Array.isArray(current) && current.length > 0
|
|
127
|
+
: !!current;
|
|
128
|
+
|
|
129
|
+
const handleClear = (e: React.MouseEvent) => {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
e.stopPropagation();
|
|
132
|
+
const next = multiple ? [] : '';
|
|
133
|
+
if (!isControlled) setInternal(next);
|
|
134
|
+
onChange?.(next);
|
|
135
|
+
};
|
|
136
|
+
|
|
119
137
|
return (
|
|
120
138
|
<Popover open={open} onOpenChange={setOpen}>
|
|
121
139
|
<PopoverTrigger asChild>
|
|
@@ -126,16 +144,33 @@ const TreeSelect = React.forwardRef<HTMLButtonElement, TreeSelectProps>(
|
|
|
126
144
|
size={size}
|
|
127
145
|
disabled={disabled}
|
|
128
146
|
className={cn(
|
|
129
|
-
'min-w-
|
|
147
|
+
'group/treeselect min-w-panel-sm justify-between font-normal',
|
|
130
148
|
!display && 'text-muted-foreground',
|
|
131
149
|
className,
|
|
132
150
|
)}
|
|
133
151
|
>
|
|
134
152
|
<span className="min-w-0 flex-1 text-left">{renderDisplay()}</span>
|
|
135
|
-
|
|
153
|
+
{allowClear && hasValue && !disabled ? (
|
|
154
|
+
<span
|
|
155
|
+
role="button"
|
|
156
|
+
tabIndex={-1}
|
|
157
|
+
aria-label="清除"
|
|
158
|
+
onClick={handleClear}
|
|
159
|
+
onMouseDown={(e) => e.stopPropagation()}
|
|
160
|
+
className="ml-2 hidden shrink-0 rounded-sm text-muted-foreground transition-colors hover:text-foreground group-hover/treeselect:inline-flex"
|
|
161
|
+
>
|
|
162
|
+
<X className="size-3.5" />
|
|
163
|
+
</span>
|
|
164
|
+
) : null}
|
|
165
|
+
<ChevronDown
|
|
166
|
+
className={cn(
|
|
167
|
+
'ml-2 size-4 shrink-0 opacity-50',
|
|
168
|
+
allowClear && hasValue && 'group-hover/treeselect:hidden',
|
|
169
|
+
)}
|
|
170
|
+
/>
|
|
136
171
|
</Button>
|
|
137
172
|
</PopoverTrigger>
|
|
138
|
-
<PopoverContent className="w-72 p-
|
|
173
|
+
<PopoverContent className="w-72 p-1" align="start">
|
|
139
174
|
{multiple ? (
|
|
140
175
|
<Tree
|
|
141
176
|
data={data}
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: typography
|
|
3
3
|
name: Typography
|
|
4
|
+
displayName: 排版
|
|
4
5
|
type: component
|
|
5
|
-
category:
|
|
6
|
+
category: general
|
|
6
7
|
since: 0.1.0
|
|
7
|
-
package:
|
|
8
|
+
package: '@teamix-evo/ui'
|
|
8
9
|
---
|
|
9
10
|
|
|
10
|
-
# Typography
|
|
11
|
+
# Typography 排版
|
|
11
12
|
|
|
12
|
-
排版组件 — `Prose`(富文本容器)+ shadcn 风格 `Title / Paragraph / Text / Link` + antd `Text` 的 `
|
|
13
|
+
排版组件 — `Prose`(富文本容器)+ shadcn 风格 `Title / Paragraph / Text / Link` + antd `Text` 的 `strong / delete / disabled / code / ellipsis / copyable` 并集。语义色采用 [ADR 0021](../../../../../docs/adr/0021-semantic-color-api-unification.md) 统一 `color` API。
|
|
13
14
|
|
|
14
15
|
> Prose 不依赖 `@tailwindcss/typography` 插件,样式手写并对齐 OpenTrek tokens。
|
|
15
16
|
|
|
16
17
|
## When to use
|
|
17
18
|
|
|
18
19
|
- **Prose**:Markdown / CMS 富文本渲染容器(自动套排版样式)
|
|
19
|
-
- **Title**:页面 / 区块标题(`level={1..
|
|
20
|
+
- **Title**:页面 / 区块标题(`level={1..6}` 自动映射 `<h1>~<h6>`,对齐 antd `Typography.Title.level`)
|
|
20
21
|
- **Paragraph**:正文段落(行高 / 字号 / 颜色统一)
|
|
21
|
-
- **Text**:行内文本带语义色 / 强调 / 复制
|
|
22
|
-
- **Link**:语义化链接(
|
|
22
|
+
- **Text**:行内文本带语义色(`color`) / 强调 / 复制
|
|
23
|
+
- **Link**:语义化链接(`color` + 默认下划线 hover)
|
|
23
24
|
|
|
24
25
|
## When NOT to use
|
|
25
26
|
|
|
@@ -27,10 +28,14 @@ package: "@teamix-evo/ui"
|
|
|
27
28
|
- 单一颜色文本 → 直接 `<span className="text-...">`,无需包装
|
|
28
29
|
- 多行 ellipsis(2 行 / 3 行) → 自行 `line-clamp-N`(本组件 ellipsis 仅单行)
|
|
29
30
|
|
|
31
|
+
## Props
|
|
32
|
+
|
|
33
|
+
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`typography.tsx`](./typography.tsx) 的 `TextProps` interface JSDoc。
|
|
34
|
+
|
|
30
35
|
<!-- auto:props:begin -->
|
|
31
36
|
| 名称 | 类型 | 默认值 | 必填 | 说明 |
|
|
32
37
|
| --- | --- | --- | --- | --- |
|
|
33
|
-
| `
|
|
38
|
+
| `color` | `TextColor` | `"default"` | – | 语义色 — 6 档枚举,字面与 OpenTrek tokens 对齐(见 [ADR 0021](../../../../../docs/adr/0021-semantic-color-api-unification.md))。 antd `type` 迁移:`secondary`→`muted`、`danger`→`destructive`。 |
|
|
34
39
|
| `delete` | `boolean` | `false` | – | 删除线。 |
|
|
35
40
|
| `disabled` | `boolean` | `false` | – | 不可用(灰色 + 不可选)。 |
|
|
36
41
|
| `strong` | `boolean` | `false` | – | 加粗。 |
|
|
@@ -39,6 +44,10 @@ package: "@teamix-evo/ui"
|
|
|
39
44
|
| `copyable` | `boolean \| { text: string; tooltips?: [string, string] }` | `false` | – | 可复制(antd `copyable` 并集)— 末尾追加复制图标按钮。 传对象时可指定要复制的文本(默认是 children 的纯文本);传 `true` 用 children。 |
|
|
40
45
|
<!-- auto:props:end -->
|
|
41
46
|
|
|
47
|
+
## 依赖
|
|
48
|
+
|
|
49
|
+
> 以下表格由 `pnpm --filter @teamix-evo/ui gen:meta` 自动生成,数据源是 [`manifest.json`](../../../manifest.json)。**手工编辑 marker 之间的内容会在下次生成时被覆盖**。
|
|
50
|
+
|
|
42
51
|
<!-- auto:deps:begin -->
|
|
43
52
|
### 同库依赖
|
|
44
53
|
|
|
@@ -57,16 +66,54 @@ pnpm add lucide-react@^0.460.0
|
|
|
57
66
|
```
|
|
58
67
|
<!-- auto:deps:end -->
|
|
59
68
|
|
|
60
|
-
> 子组件:`Prose` / `Title`(level 1~5)/ `Paragraph` / `Text`(type / strong / delete / disabled / code / ellipsis / copyable)/ `Link`。各自的 props 详见 [`typography.tsx`](./typography.tsx)。
|
|
61
|
-
|
|
62
69
|
## AI 生成纪律
|
|
63
70
|
|
|
64
71
|
- **`Title level` 决定标签**:不要用 `<h2>` 配 `level={1}`,语义会冲突
|
|
65
|
-
- **`Text
|
|
72
|
+
- **`Text color` 优先于 className 颜色**:语义色让暗色模式自动适配
|
|
66
73
|
- **`copyable` 仅当 children 是 string**:富节点请显式传 `copyable={{ text: '...' }}`
|
|
67
74
|
- **`ellipsis` 单行**:多行省略请直接 `className="line-clamp-2"`
|
|
68
75
|
- **Prose 内部不要嵌套 Prose**:嵌套排版会双倍间距
|
|
69
76
|
|
|
77
|
+
## Typography 形态 — 旧库 API → 新库映射
|
|
78
|
+
|
|
79
|
+
旧库(Teamix 1.0 / `@alifd/next.Typography` + `Typography.Text` / `Typography.Paragraph` / `Typography.H1`~`H6`)与新库(`Typography` / `Title` / `Paragraph` / `Text` / `Link` / `Prose`)逐项对应。
|
|
80
|
+
|
|
81
|
+
### 组件拆合
|
|
82
|
+
|
|
83
|
+
| 旧库 | 新库 | 备注 |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `Typography` | `Prose` | 富文本容器,渲染 Markdown / CMS 输出 |
|
|
86
|
+
| `Typography.H1` ~ `Typography.H6` | `<Title level={1..6}>` | level 决定字号 + 标签;新增 level=6 对齐 antd |
|
|
87
|
+
| `Typography.Paragraph` | `Paragraph` | 同义 |
|
|
88
|
+
| `Typography.Text` | `Text` | 行内文本 |
|
|
89
|
+
| — | `Link` | 新增 — 语义化 `<a>` 元素 |
|
|
90
|
+
|
|
91
|
+
### Props / 值映射
|
|
92
|
+
|
|
93
|
+
| 旧库 | 新库 | 备注 |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `<Text type="secondary">` | `<Text color="muted">` | ADR 0021 语义色重命名 |
|
|
96
|
+
| `<Text type="danger">` | `<Text color="destructive">` | ADR 0021 — 不收 antd `error` / `danger` 别名 |
|
|
97
|
+
| `<Text strong>` | `<Text strong>` | 行为一致 |
|
|
98
|
+
| `<Text delete>` | `<Text delete>` | 行为一致 |
|
|
99
|
+
| `<Text code>` | `<Text code>` | 行为一致 |
|
|
100
|
+
| `<Text disabled>` | `<Text disabled>` | 行为一致 |
|
|
101
|
+
| `<Text ellipsis>` | `<Text ellipsis>` | P0 已实现 — 单行 truncate;多行用 `className="line-clamp-N"` |
|
|
102
|
+
| `<Text copyable>` | `<Text copyable>` | P0 已实现 — 默认复制 children;传对象指定 `text` |
|
|
103
|
+
| `<Text copyable={{ text }}>` | `<Text copyable={{ text }}>` | 对象签名一致 |
|
|
104
|
+
| `size="body1/body2/caption/overline"` | className `text-sm/text-xs/...` | shadcn 字号通过 Tailwind 直控,不抽 prop |
|
|
105
|
+
| `mark` 黄色高亮 | 直接用 `<mark>` 标签 | HTML 原生 |
|
|
106
|
+
| `underline` | `className="underline"` | Tailwind utility |
|
|
107
|
+
| `editable` 行内编辑 | 不修复 — 用 Tiptap / Lexical / Input + state | 复杂度高,业务低频 |
|
|
108
|
+
|
|
109
|
+
### 不修复清单
|
|
110
|
+
|
|
111
|
+
| 旧库能力 | 理由 |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `mark` / `underline` / `delete` / `code` 全 prop | 直接用 HTML 原生 / Tailwind utility 更简洁,只保留 `delete` / `code` 的便捷 prop |
|
|
114
|
+
| `editable` 行内编辑 | 业务低频 + 复杂度高,推荐用 Tiptap 等编辑器 |
|
|
115
|
+
| `component` 自定义根标签 | shadcn 走 `asChild` (Slot) 替代 — 需要时用 `<Title asChild><span>...</span></Title>` |
|
|
116
|
+
|
|
70
117
|
## Examples
|
|
71
118
|
|
|
72
119
|
```tsx
|
|
@@ -80,8 +127,8 @@ import { Prose, Title, Paragraph, Text, Link } from '@/components/ui/typography'
|
|
|
80
127
|
<Paragraph>正文段落,统一字号 / 行高 / 颜色。</Paragraph>
|
|
81
128
|
|
|
82
129
|
// 行内文本
|
|
83
|
-
<Text
|
|
84
|
-
<Text
|
|
130
|
+
<Text color="success" strong>成功</Text>
|
|
131
|
+
<Text color="destructive" delete>已废弃</Text>
|
|
85
132
|
<Text disabled>不可用</Text>
|
|
86
133
|
<Text code>const x = 1</Text>
|
|
87
134
|
<Text ellipsis>这是一段非常长的文字...被截断</Text>
|
|
@@ -90,7 +137,7 @@ import { Prose, Title, Paragraph, Text, Link } from '@/components/ui/typography'
|
|
|
90
137
|
|
|
91
138
|
// 链接
|
|
92
139
|
<Link href="/docs">文档</Link>
|
|
93
|
-
<Link href="/danger"
|
|
140
|
+
<Link href="/danger" color="destructive">危险链接</Link>
|
|
94
141
|
|
|
95
142
|
// Prose 容器(渲染 Markdown 等富文本)
|
|
96
143
|
<Prose>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
2
|
import { Prose, Title, Paragraph, Text, Link } from './typography';
|
|
3
3
|
|
|
4
4
|
const meta: Meta<typeof Text> = {
|
|
5
|
-
title: '
|
|
5
|
+
title: '通用 · General/Typography',
|
|
6
6
|
component: Text,
|
|
7
7
|
tags: ['autodocs'],
|
|
8
8
|
parameters: {
|
|
9
9
|
docs: {
|
|
10
10
|
description: {
|
|
11
11
|
component:
|
|
12
|
-
'排版组件 — Prose 富文本容器 + Title/Paragraph/Text/Link
|
|
12
|
+
'排版组件 — Prose 富文本容器 + Title / Paragraph / Text / Link,合并 antd 的 `type` / `strong` / `delete` / `disabled` / `code` / `ellipsis` / `copyable` 能力。语义色采用 [ADR 0021](../../../../../docs/adr/0021-semantic-color-api-unification.md) 统一 `color` API(antd `type` 的 secondary/success/warning/danger 合并为 `color` 的 muted/success/warning/destructive)。',
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
15
|
},
|
|
@@ -31,15 +31,16 @@ export const Titles: Story = {
|
|
|
31
31
|
),
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
export const
|
|
34
|
+
export const TextColors: Story = {
|
|
35
35
|
parameters: { controls: { disable: true } },
|
|
36
36
|
render: () => (
|
|
37
37
|
<div className="flex flex-col gap-2 text-sm">
|
|
38
38
|
<Text>默认</Text>
|
|
39
|
-
<Text
|
|
40
|
-
<Text
|
|
41
|
-
<Text
|
|
42
|
-
<Text
|
|
39
|
+
<Text color="muted">次要</Text>
|
|
40
|
+
<Text color="primary">信息 / 主颜色</Text>
|
|
41
|
+
<Text color="success">成功</Text>
|
|
42
|
+
<Text color="warning">警告</Text>
|
|
43
|
+
<Text color="destructive">危险</Text>
|
|
43
44
|
<Text strong>加粗</Text>
|
|
44
45
|
<Text delete>已废弃</Text>
|
|
45
46
|
<Text disabled>不可用</Text>
|
|
@@ -78,7 +79,7 @@ export const Links: Story = {
|
|
|
78
79
|
</Link>
|
|
79
80
|
<Link
|
|
80
81
|
href="#delete"
|
|
81
|
-
|
|
82
|
+
color="destructive"
|
|
82
83
|
onClick={(e) => e.preventDefault()}
|
|
83
84
|
>
|
|
84
85
|
危险操作链接
|
|
@@ -98,8 +99,8 @@ export const ProseDemo: Story = {
|
|
|
98
99
|
</p>
|
|
99
100
|
<h2>子标题</h2>
|
|
100
101
|
<p>
|
|
101
|
-
访问 <a href="#">链接</a> 查看更多。<strong>强调</strong>{' '}
|
|
102
|
-
<
|
|
102
|
+
访问 <a href="#">链接</a> 查看更多。<strong>强调</strong> <em>斜体</em>{' '}
|
|
103
|
+
<code>inline-code</code>。
|
|
103
104
|
</p>
|
|
104
105
|
<ul>
|
|
105
106
|
<li>列表项 1</li>
|
|
@@ -35,6 +35,7 @@ const Prose = React.forwardRef<HTMLDivElement, ProseProps>(
|
|
|
35
35
|
'[&_strong]:font-semibold',
|
|
36
36
|
'[&_em]:italic',
|
|
37
37
|
// code
|
|
38
|
+
// eslint-disable-next-line teamix-evo/no-arbitrary-tw-value -- inline `<code>` uses em-relative size to scale with surrounding text; not tokenizable since it depends on parent context.
|
|
38
39
|
'[&_code]:rounded [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.875em]',
|
|
39
40
|
'[&_pre]:my-4 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-4',
|
|
40
41
|
'[&_pre_code]:bg-transparent [&_pre_code]:p-0',
|
|
@@ -57,25 +58,22 @@ const titleSizes = {
|
|
|
57
58
|
3: 'text-xl font-semibold',
|
|
58
59
|
4: 'text-lg font-medium',
|
|
59
60
|
5: 'text-base font-medium',
|
|
61
|
+
6: 'text-sm font-medium',
|
|
60
62
|
} as const;
|
|
61
63
|
|
|
62
64
|
export interface TitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
|
|
63
65
|
/**
|
|
64
|
-
* 层级(1~
|
|
66
|
+
* 层级(1~6),决定字号 / 粗细;同时映射为 `<h1>~<h6>` 标签 — 对齐 antd `Typography.Title.level`。
|
|
65
67
|
* @default 1
|
|
66
68
|
*/
|
|
67
|
-
level?: 1 | 2 | 3 | 4 | 5;
|
|
69
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
const Title = React.forwardRef<HTMLHeadingElement, TitleProps>(
|
|
71
73
|
({ level = 1, className, ...props }, ref) => {
|
|
72
|
-
const Comp = `h${level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5';
|
|
74
|
+
const Comp = `h${level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
73
75
|
return (
|
|
74
|
-
<Comp
|
|
75
|
-
ref={ref}
|
|
76
|
-
className={cn(titleSizes[level], className)}
|
|
77
|
-
{...props}
|
|
78
|
-
/>
|
|
76
|
+
<Comp ref={ref} className={cn(titleSizes[level], className)} {...props} />
|
|
79
77
|
);
|
|
80
78
|
},
|
|
81
79
|
);
|
|
@@ -97,16 +95,30 @@ const Paragraph = React.forwardRef<HTMLParagraphElement, ParagraphProps>(
|
|
|
97
95
|
);
|
|
98
96
|
Paragraph.displayName = 'Paragraph';
|
|
99
97
|
|
|
100
|
-
// ─── Text(行内文本,支持 antd ellipsis / copyable /
|
|
98
|
+
// ─── Text(行内文本,支持 antd ellipsis / copyable / color)──────────────────
|
|
101
99
|
|
|
102
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Text 语义色 6 档(见 [ADR 0021](../../../../../docs/adr/0021-semantic-color-api-unification.md))。
|
|
102
|
+
* 字面与 OpenTrek tokens 对齐:
|
|
103
|
+
* - antd `secondary` → `muted`(对齐 `--muted-foreground`)
|
|
104
|
+
* - antd `danger` → `destructive`(对齐 `--destructive`)
|
|
105
|
+
* - **不收 `info`** — 如需信息色,用 `primary`。
|
|
106
|
+
*/
|
|
107
|
+
export type TextColor =
|
|
108
|
+
| 'default'
|
|
109
|
+
| 'muted'
|
|
110
|
+
| 'primary'
|
|
111
|
+
| 'success'
|
|
112
|
+
| 'warning'
|
|
113
|
+
| 'destructive';
|
|
103
114
|
|
|
104
115
|
export interface TextProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
105
116
|
/**
|
|
106
|
-
* 语义色(
|
|
117
|
+
* 语义色 — 6 档枚举,字面与 OpenTrek tokens 对齐(见 [ADR 0021](../../../../../docs/adr/0021-semantic-color-api-unification.md))。
|
|
118
|
+
* antd `type` 迁移:`secondary`→`muted`、`danger`→`destructive`。
|
|
107
119
|
* @default "default"
|
|
108
120
|
*/
|
|
109
|
-
|
|
121
|
+
color?: TextColor;
|
|
110
122
|
/**
|
|
111
123
|
* 删除线。
|
|
112
124
|
* @default false
|
|
@@ -140,18 +152,19 @@ export interface TextProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
140
152
|
copyable?: boolean | { text: string; tooltips?: [string, string] };
|
|
141
153
|
}
|
|
142
154
|
|
|
143
|
-
const
|
|
155
|
+
const colorClass: Record<TextColor, string> = {
|
|
144
156
|
default: 'text-foreground',
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
157
|
+
muted: 'text-muted-foreground',
|
|
158
|
+
primary: 'text-primary',
|
|
159
|
+
success: 'text-success',
|
|
160
|
+
warning: 'text-warning',
|
|
161
|
+
destructive: 'text-destructive',
|
|
149
162
|
};
|
|
150
163
|
|
|
151
164
|
const Text = React.forwardRef<HTMLSpanElement, TextProps>(
|
|
152
165
|
(
|
|
153
166
|
{
|
|
154
|
-
|
|
167
|
+
color = 'default',
|
|
155
168
|
delete: del = false,
|
|
156
169
|
disabled = false,
|
|
157
170
|
strong = false,
|
|
@@ -170,8 +183,8 @@ const Text = React.forwardRef<HTMLSpanElement, TextProps>(
|
|
|
170
183
|
typeof copyable === 'object' && copyable.text
|
|
171
184
|
? copyable.text
|
|
172
185
|
: typeof children === 'string'
|
|
173
|
-
|
|
174
|
-
|
|
186
|
+
? children
|
|
187
|
+
: '';
|
|
175
188
|
void navigator.clipboard?.writeText(text).then(() => {
|
|
176
189
|
setCopied(true);
|
|
177
190
|
window.setTimeout(() => setCopied(false), 1500);
|
|
@@ -179,12 +192,13 @@ const Text = React.forwardRef<HTMLSpanElement, TextProps>(
|
|
|
179
192
|
};
|
|
180
193
|
|
|
181
194
|
const cls = cn(
|
|
182
|
-
|
|
195
|
+
colorClass[color],
|
|
183
196
|
strong && 'font-semibold',
|
|
184
197
|
del && 'line-through',
|
|
185
198
|
disabled && 'cursor-not-allowed select-none opacity-50',
|
|
186
199
|
ellipsis && 'inline-block max-w-full truncate align-bottom',
|
|
187
200
|
code &&
|
|
201
|
+
// eslint-disable-next-line teamix-evo/no-arbitrary-tw-value -- inline `<code>` uses em-relative size to scale with surrounding text; not tokenizable.
|
|
188
202
|
'rounded bg-muted px-1.5 py-0.5 font-mono text-[0.875em]',
|
|
189
203
|
className,
|
|
190
204
|
);
|
|
@@ -199,10 +213,10 @@ const Text = React.forwardRef<HTMLSpanElement, TextProps>(
|
|
|
199
213
|
type="button"
|
|
200
214
|
onClick={handleCopy}
|
|
201
215
|
aria-label={copied ? '已复制' : '复制'}
|
|
202
|
-
className="rounded-sm p-0.5 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
216
|
+
className="cursor-pointer rounded-sm p-0.5 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
203
217
|
>
|
|
204
218
|
{copied ? (
|
|
205
|
-
<Check className="size-3.5 text-
|
|
219
|
+
<Check className="size-3.5 text-success" />
|
|
206
220
|
) : (
|
|
207
221
|
<Copy className="size-3.5" />
|
|
208
222
|
)}
|
|
@@ -222,18 +236,19 @@ Text.displayName = 'Text';
|
|
|
222
236
|
|
|
223
237
|
// ─── Link(antd 风格,默认下划线 hover)────────────────────────────────────
|
|
224
238
|
|
|
225
|
-
export interface LinkProps
|
|
226
|
-
|
|
227
|
-
|
|
239
|
+
export interface LinkProps
|
|
240
|
+
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
241
|
+
/** 语义色(同 Text 的 color)。 @default "default" */
|
|
242
|
+
color?: TextColor;
|
|
228
243
|
}
|
|
229
244
|
|
|
230
245
|
const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
|
|
231
|
-
({ className,
|
|
246
|
+
({ className, color = 'default', ...props }, ref) => (
|
|
232
247
|
<a
|
|
233
248
|
ref={ref}
|
|
234
249
|
className={cn(
|
|
235
250
|
'underline-offset-4 transition-colors hover:underline',
|
|
236
|
-
|
|
251
|
+
color === 'default' ? 'text-primary' : colorClass[color],
|
|
237
252
|
className,
|
|
238
253
|
)}
|
|
239
254
|
{...props}
|