@tfdesign/b-end 1.0.4

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.
Files changed (176) hide show
  1. package/AI_READ_FIRST.md +131 -0
  2. package/LICENSE +21 -0
  3. package/README.md +353 -0
  4. package/package.json +67 -0
  5. package/scripts/check-tfds-contract.mjs +334 -0
  6. package/scripts/check-tfds-integration.mjs +263 -0
  7. package/scripts/postinstall-cursor-skill.mjs +382 -0
  8. package/scripts/setup.mjs +520 -0
  9. package/skills/tfds/CHECKLIST.md +205 -0
  10. package/skills/tfds/COMMON_FAILURES.md +238 -0
  11. package/skills/tfds/DESIGN_PRINCIPLES.md +477 -0
  12. package/skills/tfds/GLOBAL_DESIGN_RULES.md +636 -0
  13. package/skills/tfds/LAYOUT_RECIPES.md +140 -0
  14. package/skills/tfds/LAYOUT_RULES.md +1355 -0
  15. package/skills/tfds/PAGE_ARCHETYPES.md +201 -0
  16. package/skills/tfds/SKILL.md +188 -0
  17. package/skills/tfds/components.index.json +7305 -0
  18. package/skills/tfds/components.summary.json +1809 -0
  19. package/src/_b_end_runtime/components/AiSuggestionShared.jsx +166 -0
  20. package/src/_b_end_runtime/components/Avatar.jsx +325 -0
  21. package/src/_b_end_runtime/components/Avatar.tokens.js +76 -0
  22. package/src/_b_end_runtime/components/AvatarGridPreview.jsx +56 -0
  23. package/src/_b_end_runtime/components/AvatarGroup.jsx +80 -0
  24. package/src/_b_end_runtime/components/AvatarGroup.tokens.js +28 -0
  25. package/src/_b_end_runtime/components/Button.jsx +144 -0
  26. package/src/_b_end_runtime/components/Button.tokens.js +90 -0
  27. package/src/_b_end_runtime/components/Card.jsx +460 -0
  28. package/src/_b_end_runtime/components/Card.tokens.js +124 -0
  29. package/src/_b_end_runtime/components/CardPreview.jsx +51 -0
  30. package/src/_b_end_runtime/components/ChatBubble.jsx +384 -0
  31. package/src/_b_end_runtime/components/ChatBubble.tokens.js +60 -0
  32. package/src/_b_end_runtime/components/ChatBubblePreview.jsx +129 -0
  33. package/src/_b_end_runtime/components/ChatInput.jsx +1399 -0
  34. package/src/_b_end_runtime/components/ChatInput.tokens.js +75 -0
  35. package/src/_b_end_runtime/components/ChatMessage.jsx +2215 -0
  36. package/src/_b_end_runtime/components/ChatMessage.tokens.js +257 -0
  37. package/src/_b_end_runtime/components/ChatMessagePreview.jsx +388 -0
  38. package/src/_b_end_runtime/components/Checkbox.jsx +317 -0
  39. package/src/_b_end_runtime/components/Checkbox.tokens.js +59 -0
  40. package/src/_b_end_runtime/components/ConversationList.jsx +1264 -0
  41. package/src/_b_end_runtime/components/ConversationList.tokens.js +135 -0
  42. package/src/_b_end_runtime/components/ConversationListPreview.jsx +108 -0
  43. package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.jsx +324 -0
  44. package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.tokens.js +69 -0
  45. package/src/_b_end_runtime/components/DatePicker.jsx +739 -0
  46. package/src/_b_end_runtime/components/DatePicker.tokens.js +99 -0
  47. package/src/_b_end_runtime/components/Empty.jsx +141 -0
  48. package/src/_b_end_runtime/components/Empty.tokens.js +40 -0
  49. package/src/_b_end_runtime/components/Form.jsx +609 -0
  50. package/src/_b_end_runtime/components/Form.tokens.js +77 -0
  51. package/src/_b_end_runtime/components/FormFieldStack.jsx +123 -0
  52. package/src/_b_end_runtime/components/FormFieldStack.tokens.js +12 -0
  53. package/src/_b_end_runtime/components/FormTitle.jsx +119 -0
  54. package/src/_b_end_runtime/components/FormTitle.tokens.js +87 -0
  55. package/src/_b_end_runtime/components/FullScreenPage.jsx +97 -0
  56. package/src/_b_end_runtime/components/FullScreenPage.tokens.js +19 -0
  57. package/src/_b_end_runtime/components/Icon.jsx +172 -0
  58. package/src/_b_end_runtime/components/Icon.tokens.js +26 -0
  59. package/src/_b_end_runtime/components/IconGridPreview.jsx +277 -0
  60. package/src/_b_end_runtime/components/InfoDisplayPanel.jsx +620 -0
  61. package/src/_b_end_runtime/components/InfoDisplayPanel.tokens.js +71 -0
  62. package/src/_b_end_runtime/components/InfoDisplayPanelPreview.jsx +133 -0
  63. package/src/_b_end_runtime/components/Input.jsx +258 -0
  64. package/src/_b_end_runtime/components/Input.tokens.js +68 -0
  65. package/src/_b_end_runtime/components/InputNumber.jsx +242 -0
  66. package/src/_b_end_runtime/components/InputNumber.tokens.js +55 -0
  67. package/src/_b_end_runtime/components/Modal.jsx +155 -0
  68. package/src/_b_end_runtime/components/Modal.tokens.js +73 -0
  69. package/src/_b_end_runtime/components/NavBar.jsx +842 -0
  70. package/src/_b_end_runtime/components/NavBar.tokens.js +97 -0
  71. package/src/_b_end_runtime/components/NavBarPreview.jsx +11 -0
  72. package/src/_b_end_runtime/components/Radio.jsx +227 -0
  73. package/src/_b_end_runtime/components/Radio.tokens.js +59 -0
  74. package/src/_b_end_runtime/components/Select.jsx +766 -0
  75. package/src/_b_end_runtime/components/Select.tokens.js +99 -0
  76. package/src/_b_end_runtime/components/Sheet.jsx +132 -0
  77. package/src/_b_end_runtime/components/Sheet.tokens.js +61 -0
  78. package/src/_b_end_runtime/components/Slider.jsx +346 -0
  79. package/src/_b_end_runtime/components/Slider.tokens.js +47 -0
  80. package/src/_b_end_runtime/components/Switch.jsx +124 -0
  81. package/src/_b_end_runtime/components/Switch.tokens.js +38 -0
  82. package/src/_b_end_runtime/components/Table.jsx +1338 -0
  83. package/src/_b_end_runtime/components/Table.tokens.js +147 -0
  84. package/src/_b_end_runtime/components/TablePreview.jsx +599 -0
  85. package/src/_b_end_runtime/components/Tabs.jsx +149 -0
  86. package/src/_b_end_runtime/components/Tabs.tokens.js +102 -0
  87. package/src/_b_end_runtime/components/Tag.jsx +199 -0
  88. package/src/_b_end_runtime/components/Tag.tokens.js +171 -0
  89. package/src/_b_end_runtime/components/TagBar.jsx +1134 -0
  90. package/src/_b_end_runtime/components/TagBar.tokens.js +75 -0
  91. package/src/_b_end_runtime/components/TagGridPreview.jsx +23 -0
  92. package/src/_b_end_runtime/components/TagInput.jsx +382 -0
  93. package/src/_b_end_runtime/components/TagInput.tokens.js +52 -0
  94. package/src/_b_end_runtime/components/TextArea.jsx +363 -0
  95. package/src/_b_end_runtime/components/TextArea.tokens.js +65 -0
  96. package/src/_b_end_runtime/components/TimePicker.jsx +444 -0
  97. package/src/_b_end_runtime/components/TimePicker.tokens.js +77 -0
  98. package/src/_b_end_runtime/components/Toast.jsx +120 -0
  99. package/src/_b_end_runtime/components/Toast.tokens.js +146 -0
  100. package/src/_b_end_runtime/components/Tooltip.jsx +282 -0
  101. package/src/_b_end_runtime/components/Tooltip.tokens.js +48 -0
  102. package/src/_b_end_runtime/components/TooltipPreview.jsx +50 -0
  103. package/src/_b_end_runtime/components/Upload.jsx +455 -0
  104. package/src/_b_end_runtime/components/Upload.tokens.js +47 -0
  105. package/src/_b_end_runtime/components/avatar-assets/avatar-default.png +0 -0
  106. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-1.png +0 -0
  107. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-2.png +0 -0
  108. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-3.png +0 -0
  109. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-4.png +0 -0
  110. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-5.png +0 -0
  111. package/src/_b_end_runtime/components/empty-assets/administrator-1.svg +40 -0
  112. package/src/_b_end_runtime/components/empty-assets/administrator-2.svg +33 -0
  113. package/src/_b_end_runtime/components/empty-assets/construction.svg +33 -0
  114. package/src/_b_end_runtime/components/empty-assets/failure.svg +49 -0
  115. package/src/_b_end_runtime/components/empty-assets/idle.svg +34 -0
  116. package/src/_b_end_runtime/components/empty-assets/no-access.svg +36 -0
  117. package/src/_b_end_runtime/components/empty-assets/no-content.svg +77 -0
  118. package/src/_b_end_runtime/components/empty-assets/no-result.svg +61 -0
  119. package/src/_b_end_runtime/components/empty-assets/not-found.svg +46 -0
  120. package/src/_b_end_runtime/components/empty-assets/success.svg +38 -0
  121. package/src/_b_end_runtime/components/file-type-assets/batch-report.png +0 -0
  122. package/src/_b_end_runtime/components/file-type-assets/catcat.svg +21 -0
  123. package/src/_b_end_runtime/components/file-type-assets/code.png +0 -0
  124. package/src/_b_end_runtime/components/file-type-assets/conversation.png +0 -0
  125. package/src/_b_end_runtime/components/file-type-assets/document.png +0 -0
  126. package/src/_b_end_runtime/components/file-type-assets/feishu-card.png +0 -0
  127. package/src/_b_end_runtime/components/file-type-assets/feishu-sheet.png +0 -0
  128. package/src/_b_end_runtime/components/file-type-assets/feishu.png +0 -0
  129. package/src/_b_end_runtime/components/file-type-assets/image.png +0 -0
  130. package/src/_b_end_runtime/components/file-type-assets/index.js +105 -0
  131. package/src/_b_end_runtime/components/file-type-assets/knowledge.png +0 -0
  132. package/src/_b_end_runtime/components/file-type-assets/pdf.png +0 -0
  133. package/src/_b_end_runtime/components/file-type-assets/pe.png +0 -0
  134. package/src/_b_end_runtime/components/file-type-assets/strategy.png +0 -0
  135. package/src/_b_end_runtime/components/file-type-assets/table.png +0 -0
  136. package/src/_b_end_runtime/components/file-type-assets/webpage.png +0 -0
  137. package/src/_b_end_runtime/components/file-type-assets/xmind.png +0 -0
  138. package/src/_b_end_runtime/components/icons/icon-data.js +12496 -0
  139. package/src/_b_end_runtime/components/nav-bar-assets/bytehi-logo-mark.svg +21 -0
  140. package/src/_b_end_runtime/components/table-assets/avatar.png +0 -0
  141. package/src/_b_end_runtime/components/table-assets/button.png +0 -0
  142. package/src/_b_end_runtime/components/table-assets/icon-chevron-down.png +0 -0
  143. package/src/_b_end_runtime/components/table-cell-assets/avatar.png +0 -0
  144. package/src/_b_end_runtime/components/table-cell-assets/button.png +0 -0
  145. package/src/_b_end_runtime/components/table-cell-assets/checkbox.png +0 -0
  146. package/src/_b_end_runtime/components/table-cell-assets/icon-chevron-right.png +0 -0
  147. package/src/_b_end_runtime/components/table-cell-assets/icon.png +0 -0
  148. package/src/_b_end_runtime/components/table-cell-assets/semi-icons-handle.png +0 -0
  149. package/src/_b_end_runtime/components/table-cell-assets/semi-icons-tree-triangle-right.png +0 -0
  150. package/src/_b_end_runtime/components/table-cell-assets/switch.png +0 -0
  151. package/src/_b_end_runtime/components/tagShared.js +3 -0
  152. package/src/_b_end_runtime/components/team-avatar-assets/chengcheng-murphy.png +0 -0
  153. package/src/_b_end_runtime/components/team-avatar-assets/duan-ran.png +0 -0
  154. package/src/_b_end_runtime/components/team-avatar-assets/guo-zhezhi.png +0 -0
  155. package/src/_b_end_runtime/components/team-avatar-assets/li-siru.png +0 -0
  156. package/src/_b_end_runtime/components/team-avatar-assets/liu-delin.png +0 -0
  157. package/src/_b_end_runtime/components.js +3499 -0
  158. package/src/_b_end_runtime/index.js +9 -0
  159. package/src/_b_end_runtime/page-patterns/BasePageFramePattern.jsx +395 -0
  160. package/src/_b_end_runtime/page-patterns/ChatConversationPattern.jsx +989 -0
  161. package/src/_b_end_runtime/page-patterns/ChatHomePagePattern.jsx +281 -0
  162. package/src/_b_end_runtime/page-patterns/CopilotPagePattern.jsx +380 -0
  163. package/src/_b_end_runtime/page-patterns/CustomerServiceWorkspaceFramePattern.jsx +392 -0
  164. package/src/_b_end_runtime/page-patterns/IMConversationPattern.jsx +590 -0
  165. package/src/_b_end_runtime/page-patterns/McpManagementPage.jsx +237 -0
  166. package/src/_b_end_runtime/page-patterns/StrategyListPage.jsx +189 -0
  167. package/src/_b_end_runtime/page-patterns/TabTopBarListPage.jsx +594 -0
  168. package/src/_b_end_runtime/page-patterns/VariableManagementPage.jsx +87 -0
  169. package/src/_b_end_runtime/page-patterns/pageListShared.jsx +177 -0
  170. package/src/_b_end_runtime/patterns.js +428 -0
  171. package/src/_b_end_runtime/preview-registry.jsx +4719 -0
  172. package/src/_b_end_runtime/teamMembers.js +56 -0
  173. package/src/_b_end_runtime/tokens.js +500 -0
  174. package/src/index.d.ts +1073 -0
  175. package/src/index.js +52 -0
  176. package/theme.css +350 -0
@@ -0,0 +1,97 @@
1
+ export const NAVBAR_TOKEN_MAP = {
2
+ 品牌: [
3
+ { label: '品牌语义', cssProp: 'content', value: '顶部文案展示真实平台名称;OLA 仅为模板示意,不是固定文案' },
4
+ { label: '平台默认', cssProp: 'variant', value: '默认使用 OLA 类型菜单栏结构;ByteHi 仅限明确“客服工作台”场景' },
5
+ { label: '文字色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary' },
6
+ { label: '字号', cssProp: 'font-size', token: '--text-sm', value: '14px' },
7
+ { label: '字重', cssProp: 'font-weight', value: '900' },
8
+ { label: '行高', cssProp: 'line-height', token: '--leading-5', value: '20px' },
9
+ ],
10
+ 业务卡: [
11
+ { label: '背景', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary' },
12
+ { label: '悬浮底', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'hover' },
13
+ { label: '描边', cssProp: 'border-color', token: '--color-white', value: '#FFFFFF' },
14
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-md', value: '8px' },
15
+ { label: '图标底', cssProp: 'background', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary' },
16
+ { label: '下拉选项间距', cssProp: 'gap', token: '--spacing-1', value: '4px', state: 'dropdown' },
17
+ ],
18
+ 模块: [
19
+ { label: '菜单身份', cssProp: 'semantics', value: 'moduleLabel 是 OLA 第一个菜单项,默认文案“平台首页”,不是装饰标题' },
20
+ { label: '首页默认', cssProp: 'state', value: 'AI 新生成页面或明确为首页时,默认 selectedItemId="module" / activeModule=true' },
21
+ { label: '默认色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary', state: 'default' },
22
+ { label: '激活色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary', state: 'active' },
23
+ { label: '图标色', cssProp: 'color', token: '--color-brand-500', value: '#56D3BC', state: 'active' },
24
+ { label: '悬浮底', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'hover' },
25
+ { label: '激活底', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'active' },
26
+ { label: '激活悬浮', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'active-hover' },
27
+ { label: '描边', cssProp: 'border-color', token: '--color-white', value: '#FFFFFF', state: 'active' },
28
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-md', value: '8px' },
29
+ ],
30
+ 导航: [
31
+ { label: '自由切换', cssProp: 'interaction', value: '平台首页、所有主导航项和可选底部工具项都必须支持点击切换' },
32
+ { label: '选中状态源', cssProp: 'state', value: '推荐 selectedItemId + onSelect 单一受控状态;不要同时混用多套 active* 状态源' },
33
+ { label: '默认色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary', state: 'default' },
34
+ { label: '激活色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary', state: 'active' },
35
+ { label: '图标色', cssProp: 'color', token: '--color-brand-500', value: '#56D3BC', state: 'active' },
36
+ { label: '悬浮底', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'hover' },
37
+ { label: '激活底', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'active' },
38
+ { label: '激活悬浮', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'active-hover' },
39
+ { label: '描边', cssProp: 'border-color', token: '--color-white', value: '#FFFFFF', state: 'active' },
40
+ { label: '字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
41
+ { label: '行高', cssProp: 'line-height', token: '--leading-4', value: '16px' },
42
+ { label: '按钮宽', cssProp: 'width', value: '88px' },
43
+ { label: '按钮高', cssProp: 'height', value: '60px' },
44
+ ],
45
+ 工具: [
46
+ { label: '图标色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
47
+ { label: '选中色', cssProp: 'color', token: '--color-brand-500', value: '#56D3BC', state: 'active' },
48
+ { label: '悬浮底', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'hover' },
49
+ { label: '选中底', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'active' },
50
+ { label: '选中悬浮', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'active-hover' },
51
+ { label: '描边', cssProp: 'border-color', token: '--color-white', value: '#FFFFFF', state: 'active' },
52
+ { label: '按钮高', cssProp: 'height', value: '52px' },
53
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-md', value: '8px' },
54
+ ],
55
+ 头像: [
56
+ { label: '尺寸', cssProp: 'width/height', value: '24px' },
57
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-full', value: '9999px' },
58
+ ],
59
+ 尺寸: [
60
+ { label: 'OLA宽度', cssProp: 'width', value: '120px' },
61
+ { label: 'ByteHi布局占位宽度', cssProp: 'width', value: '60px' },
62
+ { label: 'ByteHi展开面板宽度', cssProp: 'width', value: '180px', state: 'hover-expanded-panel' },
63
+ { label: 'ByteHi展开方式', cssProp: 'position', value: '外层固定占位 60px;内部面板 absolute 覆盖展开,不挤压右侧内容', state: 'hover-expanded-panel' },
64
+ { label: '顶栏高度', cssProp: 'height', value: '48px', state: 'bytehi-header' },
65
+ { label: '首项间距', cssProp: 'padding-top', token: '--spacing-4', value: '16px', state: 'bytehi-first-nav-gap' },
66
+ { label: '高度', cssProp: 'height', value: '100%(随父容器撑满)' },
67
+ { label: '横向边距', cssProp: 'padding-inline', token: '--spacing-4', value: '16px' },
68
+ { label: '纵向节奏', cssProp: 'gap', token: '--spacing-1', value: '4px' },
69
+ ],
70
+ ByteHi导航: [
71
+ { label: '容器底色', cssProp: 'background', token: '--color-blueGrey-200', value: '#F2F4F7' },
72
+ { label: '展开阴影', cssProp: 'box-shadow', value: '0 1px 6px 0 rgba(0,0,0,0.1), 0 0 1px 0 rgba(0,0,0,0.15)', state: 'expanded' },
73
+ { label: '选中底', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'active' },
74
+ { label: '默认文字', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary', state: 'default' },
75
+ { label: '选中文字', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary', state: 'active' },
76
+ { label: '图标尺寸', cssProp: 'icon-size', value: '20px' },
77
+ { label: '字号', cssProp: 'font-size', token: '--text-sm', value: '14px' },
78
+ { label: '默认字重', cssProp: 'font-weight', token: '--font-medium', value: '500', state: 'default' },
79
+ { label: '选中字重', cssProp: 'font-weight', token: '--font-semibold', value: '600', state: 'active' },
80
+ { label: '行高', cssProp: 'line-height', token: '--leading-5', value: '20px' },
81
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-md', value: '8px' },
82
+ ],
83
+ ByteHi底部: [
84
+ { label: '网络图标', cssProp: 'color', token: '--color-success', value: '#3EB346', semanticRef: 'status-success' },
85
+ { label: '说明文字', cssProp: 'color', token: '--color-foreground-secondary', value: '#475467', semanticRef: 'text-secondary' },
86
+ { label: '主标题', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary' },
87
+ { label: '网络卡高', cssProp: 'height', value: '56px' },
88
+ { label: '网络圆角', cssProp: 'border-radius', token: '--radius-avatar', value: '3px' },
89
+ { label: '头像尺寸', cssProp: 'width/height', value: '32px' },
90
+ { label: '默认头像', cssProp: 'content', value: 'ByteHi image 头像未传 src 时固定使用本地成员“段然”,hover/展开不随机变化' },
91
+ { label: '辅助字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
92
+ ],
93
+ 引用组件: [
94
+ { label: '导航图标', cssProp: '—', value: 'Icon / hiai-logo / icon-logo-douyin / home-smile-stroked / if-stroked / book-open-01-stroked / tool-01-stroked / message-chat-circle-stroked / grid-03-stroked / bell-03-stroked / settings-02-stroked / dots-grid-stroked / message-dots-circle-stroked / message-dots-square-stroked / clock-stroked / shield-tick-stroked / menu-03-stroked / phone-stroked / server-01-stroked / server-02-stroked / help-circle-stroked / wifi-stroked' },
95
+ { label: '用户头像', cssProp: '—', value: 'Avatar / type=image|robot|fallback / size=xs|s / shape=round' },
96
+ ],
97
+ };
@@ -0,0 +1,11 @@
1
+ import NavBar from './NavBar';
2
+
3
+ const CANVAS = 'flex h-full min-h-0 w-full items-stretch justify-start';
4
+
5
+ export default function NavBarPreview(props) {
6
+ return (
7
+ <div className={CANVAS}>
8
+ <NavBar {...props} />
9
+ </div>
10
+ );
11
+ }
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Radio / RadioGroup — B端设计系统 (Tailwind 内联)
3
+ *
4
+ * 单选组:API 对齐 HiUI Radio(RadioGroup + Radio、value/defaultValue/onChange、禁用)。
5
+ * **选型**:互斥单选且选项少(建议 ≤5)、需平铺展示 → Radio;选项多或占位窄 → `Select`;多选 → `CheckboxGroup`;单布尔即时切换 → `Switch`。
6
+ * 视觉参考 HIUIpackage 内 @douyinfe/semi-ui 的 `.semi-radio` 规范(umd/view.css):
7
+ * 默认 16×16px、1px 边框(未选)、hover/active 填充态、选中为实心主色圆 + 中心白点、
8
+ * 纵向组 row-gap 12px、横向组 gap 16px、项内图文间距 8px、指示器 margin-top 2px 与 20px 行高对齐。
9
+ *
10
+ * @component RadioGroup
11
+ * @prop {'brand'|'black'} [variant='brand'] — 色系:brand 选中绿色、black 选中深灰
12
+ * @prop {'vertical'|'horizontal'} [layout='vertical'] — 布局:vertical 纵向 12px / horizontal 横向 16px
13
+ * @prop {boolean} [disabled=false] — 禁用整组
14
+ * @prop {string} [value] — 受控选中值
15
+ * @prop {string} [defaultValue] — 非受控初始值
16
+ * @prop {(value, event) => void} [onChange] — 选中回调
17
+ * @prop {string} [name] — 原生 name(同组共享,未传时自动生成)
18
+ * @prop {string} [className='']
19
+ *
20
+ * @component Radio(须在 RadioGroup 内)
21
+ * @prop {string} value — 选项标识(必填)
22
+ * @prop {boolean} [disabled=false] — 单项禁用
23
+ * @prop {string} [className='']
24
+ * @prop {ReactNode} children — 文案
25
+ */
26
+
27
+ import {
28
+ createContext,
29
+ useContext,
30
+ useId,
31
+ useMemo,
32
+ useState,
33
+ useCallback,
34
+ } from 'react';
35
+
36
+ const RadioContext = createContext(null);
37
+
38
+ /* ── 布局方向 → 纵向组距 12px / 横向组距 16px ── */
39
+ const LAYOUT_CLASS = {
40
+ vertical: 'flex flex-col gap-3',
41
+ horizontal: 'inline-flex flex-row flex-wrap items-start gap-4',
42
+ };
43
+
44
+ /* ── 基础 → 组容器字体继承 ── */
45
+ const GROUP_BASE = '[font-family:inherit]';
46
+
47
+ const LABEL_ROW = 'group inline-flex items-start gap-2 select-none rounded-sm';
48
+
49
+ /* ── 指示器 → 内包裹层,margin-top 2px 与 20px 行高对齐 ── */
50
+ const INNER_WRAP = 'relative mt-[2px] inline-flex shrink-0';
51
+
52
+ /* ── 指示圈 → 外圈基础样式(16×16、1px solid、圆角 full) ── */
53
+ const OUTER_BASE = [
54
+ 'relative flex shrink-0 items-center justify-center rounded-full',
55
+ 'border border-solid transition-colors duration-150',
56
+ ].join(' ');
57
+
58
+ const OUTER_SIZE = 'size-[16px]';
59
+
60
+ const INNER_DOT = 'size-[6px]';
61
+
62
+ const LABEL_TEXT = 'text-sm leading-[20px]';
63
+
64
+ const FOCUS_OUTLINE = {
65
+ brand: 'has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-brand-200',
66
+ black: 'has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-grey-400',
67
+ };
68
+
69
+ function buildDisplayClass(checked, disabled, variant) {
70
+ const sz = OUTER_SIZE;
71
+ if (disabled) {
72
+ if (checked) {
73
+ if (variant === 'black') {
74
+ return [
75
+ OUTER_BASE, sz,
76
+ 'opacity-75 bg-blueGrey-400 border-blueGrey-400',
77
+ ].join(' ');
78
+ }
79
+ return [
80
+ OUTER_BASE, sz,
81
+ 'opacity-75 bg-brand-200 border-brand-200',
82
+ ].join(' ');
83
+ }
84
+ return [
85
+ OUTER_BASE, sz,
86
+ 'opacity-75 bg-disabled border-border-default',
87
+ ].join(' ');
88
+ }
89
+
90
+ if (checked) {
91
+ if (variant === 'black') {
92
+ return [
93
+ OUTER_BASE, sz,
94
+ 'bg-grey-950 border-grey-950',
95
+ 'group-hover:bg-grey-900 group-hover:border-grey-900',
96
+ 'group-active:bg-grey-800 group-active:border-grey-800',
97
+ ].join(' ');
98
+ }
99
+ return [
100
+ OUTER_BASE, sz,
101
+ 'bg-brand-500 border-brand-500',
102
+ 'group-hover:bg-brand-600 group-hover:border-brand-600',
103
+ 'group-active:bg-brand-700 group-active:border-brand-700',
104
+ ].join(' ');
105
+ }
106
+
107
+ return [
108
+ OUTER_BASE, sz,
109
+ 'border-foreground-muted bg-transparent',
110
+ 'group-hover:bg-fill group-hover:border-border-brand',
111
+ 'group-active:bg-blueGrey-100',
112
+ ].join(' ');
113
+ }
114
+
115
+ export function Radio({ value, disabled: itemDisabled = false, className = '', children }) {
116
+ const ctx = useContext(RadioContext);
117
+ if (!ctx) return null;
118
+
119
+ const {
120
+ selected,
121
+ setSelected,
122
+ groupDisabled,
123
+ variant,
124
+ name,
125
+ } = ctx;
126
+
127
+ const disabled = groupDisabled || itemDisabled;
128
+ const checked = String(selected) === String(value);
129
+ const fo = FOCUS_OUTLINE[variant] || FOCUS_OUTLINE.brand;
130
+
131
+ const displayCls = buildDisplayClass(checked, disabled, variant);
132
+
133
+ const dot = INNER_DOT;
134
+ const textCls = LABEL_TEXT;
135
+
136
+ const onChange = useCallback((e) => {
137
+ if (disabled) return;
138
+ setSelected(value, e);
139
+ }, [disabled, setSelected, value]);
140
+
141
+ return (
142
+ <label
143
+ className={[`tfds-radio`, [
144
+ LABEL_ROW,
145
+ fo,
146
+ disabled ? 'cursor-not-allowed' : 'cursor-pointer',
147
+ className,
148
+ ].filter(Boolean).join(' ')].filter(Boolean).join(' ')}
149
+ data-tfds-component="Radio">
150
+ <span className={INNER_WRAP}>
151
+ <input
152
+ type="radio"
153
+ name={name}
154
+ value={String(value)}
155
+ checked={checked}
156
+ disabled={disabled}
157
+ onChange={onChange}
158
+ className="sr-only"
159
+ />
160
+ <span className={displayCls} aria-hidden>
161
+ {checked ? (
162
+ <span className={`rounded-full bg-white ${dot}`} />
163
+ ) : null}
164
+ </span>
165
+ </span>
166
+ {children != null && children !== false ? (
167
+ <span
168
+ className={[
169
+ textCls,
170
+ disabled ? 'text-foreground-disabled' : 'text-foreground',
171
+ ].filter(Boolean).join(' ')}
172
+ >
173
+ {children}
174
+ </span>
175
+ ) : null}
176
+ </label>
177
+ );
178
+ }
179
+
180
+ export default function RadioGroup({
181
+ variant = 'brand',
182
+ size: _size = 'md',
183
+ layout = 'vertical',
184
+ disabled = false,
185
+ value,
186
+ defaultValue,
187
+ onChange,
188
+ name: nameProp,
189
+ className = '',
190
+ children,
191
+ ...rest
192
+ }) {
193
+ const uid = useId();
194
+ const name = nameProp ?? `radio-group-${uid.replace(/:/g, '')}`;
195
+ const isControlled = value !== undefined;
196
+ const [inner, setInner] = useState(defaultValue);
197
+
198
+ const selected = isControlled ? value : inner;
199
+
200
+ const setSelected = useCallback((next, e) => {
201
+ if (!isControlled) setInner(next);
202
+ onChange?.(next, e);
203
+ }, [isControlled, onChange]);
204
+
205
+ const ctxValue = useMemo(() => ({
206
+ selected,
207
+ setSelected,
208
+ groupDisabled: disabled,
209
+ variant,
210
+ name,
211
+ }), [selected, setSelected, disabled, variant, name]);
212
+
213
+ const layoutCls = LAYOUT_CLASS[layout] || LAYOUT_CLASS.vertical;
214
+ const sizeText = 'text-sm';
215
+
216
+ return (
217
+ <RadioContext.Provider value={ctxValue}>
218
+ <div
219
+ role="radiogroup"
220
+ className={[GROUP_BASE, sizeText, 'leading-[20px]', layoutCls, className].filter(Boolean).join(' ')}
221
+ {...rest}
222
+ >
223
+ {children}
224
+ </div>
225
+ </RadioContext.Provider>
226
+ );
227
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Radio / RadioGroup — TOKEN_MAP(供平台属性面板展示)
3
+ *
4
+ * 与 HIUIpackage 中 Semi `.semi-radio` / `.semi-radioGroup` 语义对齐后,映射到 B 端 tokens.js。
5
+ */
6
+ export const RADIO_TOKEN_MAP = {
7
+ base: [
8
+ { label: '纵向间距', cssProp: 'row-gap', token: '--spacing-3', value: '12px' },
9
+ { label: '横向间距', cssProp: 'gap', token: '--spacing-4', value: '16px' },
10
+ ],
11
+ 组内排版: [
12
+ { label: '图文间距', cssProp: 'column-gap', token: '--spacing-2', value: '8px' },
13
+ { label: '顶部偏移', cssProp: 'margin-top', value: '2px' },
14
+ { label: '默认行高', cssProp: 'line-height', value: '20px' },
15
+ ],
16
+ 标签文字: [
17
+ { label: '默认颜色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary' },
18
+ { label: '禁用颜色', cssProp: 'color', token: '--color-foreground-disabled', value: '#98A2B3', semanticRef: 'text-disabled', state: 'disabled' },
19
+ ],
20
+ variants: {
21
+ brand: [
22
+ { label: '选中填充', cssProp: 'background / border-color', token: '--color-brand-500', value: '#56D3BC', semanticRef: 'status-primary', state: 'checked' },
23
+ { label: '选中悬浮', cssProp: 'background / border-color', token: '--color-brand-600', value: '#32C4AC', state: 'checked+hover' },
24
+ { label: '选中按下', cssProp: 'background / border-color', token: '--color-brand-700', value: '#18B49D', state: 'checked+active' },
25
+ { label: '中心点', cssProp: 'background', token: '--color-white', value: '#FFFFFF', state: 'checked' },
26
+ { label: '聚焦环', cssProp: 'outline-color', token: '--color-brand-200', value: '#A8E8D7', state: 'focus' },
27
+ { label: '禁用选中', cssProp: 'background / border-color', token: '--color-brand-200', value: '#A8E8D7', state: 'disabled+checked' },
28
+ ],
29
+ black: [
30
+ { label: '选中填充', cssProp: 'background / border-color', token: '--color-grey-950', value: '#111116', state: 'checked' },
31
+ { label: '选中悬浮', cssProp: 'background / border-color', token: '--color-grey-900', value: '#1C1C23', state: 'checked+hover' },
32
+ { label: '选中按下', cssProp: 'background / border-color', token: '--color-grey-800', value: '#2E2F38', state: 'checked+active' },
33
+ { label: '中心点', cssProp: 'background', token: '--color-white', value: '#FFFFFF', state: 'checked' },
34
+ { label: '聚焦环', cssProp: 'outline-color', token: '--color-blueGrey-400', value: '#D0D5DD', state: 'focus' },
35
+ { label: '禁用选中', cssProp: 'background / border-color', token: '--color-blueGrey-400', value: '#D0D5DD', state: 'disabled+checked' },
36
+ ],
37
+ },
38
+ 指示圈: [
39
+ { label: '边框色', cssProp: 'border-color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
40
+ { label: '悬浮背景', cssProp: 'background', token: '--color-blueGrey-50', value: '#FCFCFD', state: 'hover' },
41
+ { label: '悬浮边框', cssProp: 'border-color', token: '--color-blueGrey-400', value: '#D0D5DD', state: 'hover' },
42
+ { label: '按下背景', cssProp: 'background', token: '--color-blueGrey-100', value: '#F9FAFB', state: 'active' },
43
+ { label: '禁用透明度', cssProp: 'opacity', value: '0.75', state: 'disabled' },
44
+ { label: '禁用背景', cssProp: 'background', token: '--color-disabled', value: '#F9FAFB', semanticRef: 'bg-disabled', state: 'disabled' },
45
+ { label: '禁用边框', cssProp: 'border-color', token: '--color-border-default', value: '#E4E7EC', semanticRef: 'border-default', state: 'disabled' },
46
+ ],
47
+ sizes: {
48
+ sm: [
49
+ { label: '外圆边长', cssProp: 'width / height', value: '14px' },
50
+ { label: '白点尺寸', cssProp: 'width / height', value: '5px' },
51
+ { label: '标签字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
52
+ ],
53
+ md: [
54
+ { label: '外圆边长', cssProp: 'width / height', value: '16px' },
55
+ { label: '白点尺寸', cssProp: 'width / height', value: '6px' },
56
+ { label: '标签字号', cssProp: 'font-size', token: '--text-sm', value: '14px' },
57
+ ],
58
+ },
59
+ };