@keyfunc/keybricks-ds 1.0.4 → 2.3.1

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 (381) hide show
  1. package/DEPLOY.md +14 -5
  2. package/DESIGN.md +245 -59
  3. package/INTEGRATION.md +243 -49
  4. package/SKILL.md +13 -11
  5. package/_adherence.oxlintrc.json +183 -70
  6. package/_scripts/build-index.mjs +24 -4
  7. package/_scripts/build-tokens.mjs +5 -2
  8. package/assets/icons/icon-index.js +1 -1
  9. package/assets/icons/icon-index.json +1 -1
  10. package/components/_cards/accordion.card.html +2 -2
  11. package/components/_cards/action-chip.card.html +11 -9
  12. package/components/_cards/activity.card.html +3 -3
  13. package/components/_cards/alert.card.html +3 -3
  14. package/components/_cards/app-chrome.card.html +4 -4
  15. package/components/_cards/banner.card.html +1 -1
  16. package/components/_cards/breadcrumb.card.html +5 -5
  17. package/components/_cards/button-1-base.card.html +23 -26
  18. package/components/_cards/button-2-states.card.html +27 -25
  19. package/components/_cards/button-3-sizes-icons.card.html +20 -19
  20. package/components/_cards/button-4-group.card.html +14 -31
  21. package/components/_cards/canvas-zoom-controls.card.html +1 -1
  22. package/components/_cards/cards-indicators.card.html +2 -2
  23. package/components/_cards/charts-1-sparkline.card.html +5 -5
  24. package/components/_cards/charts-10-gauge.card.html +5 -5
  25. package/components/_cards/charts-11-funnel.card.html +3 -3
  26. package/components/_cards/charts-12-treemap.card.html +3 -3
  27. package/components/_cards/charts-14-radar.card.html +3 -3
  28. package/components/_cards/charts-15-distribution.card.html +2 -2
  29. package/components/_cards/charts-16-pareto.card.html +3 -3
  30. package/components/_cards/charts-17-candlestick.card.html +3 -3
  31. package/components/_cards/charts-18-sankey.card.html +3 -3
  32. package/components/_cards/charts-19-chord.card.html +3 -3
  33. package/components/_cards/charts-2-line.card.html +4 -4
  34. package/components/_cards/charts-20-sunburst.card.html +3 -3
  35. package/components/_cards/charts-21-worldmap.card.html +4 -4
  36. package/components/_cards/charts-22-gantt.card.html +3 -3
  37. package/components/_cards/charts-23-bar3d.card.html +3 -3
  38. package/components/_cards/charts-24-pie3d.card.html +3 -3
  39. package/components/_cards/charts-25-surface3d.card.html +3 -3
  40. package/components/_cards/charts-26-scatter3d.card.html +3 -3
  41. package/components/_cards/charts-27-ribbon3d.card.html +3 -3
  42. package/components/_cards/charts-3-bar.card.html +7 -7
  43. package/components/_cards/charts-4-barlist.card.html +3 -3
  44. package/components/_cards/charts-5-donut.card.html +4 -4
  45. package/components/_cards/charts-6-scatter.card.html +3 -3
  46. package/components/_cards/charts-7-heatmap.card.html +3 -3
  47. package/components/_cards/charts-8-waterfall.card.html +3 -3
  48. package/components/_cards/charts-9-bullet.card.html +3 -3
  49. package/components/_cards/charts-99-fullpage.card.html +5 -5
  50. package/components/_cards/checkbox.card.html +9 -6
  51. package/components/_cards/codeblock.card.html +2 -2
  52. package/components/_cards/combobox.card.html +6 -3
  53. package/components/_cards/context-menu.card.html +6 -3
  54. package/components/_cards/date-picker.card.html +10 -4
  55. package/components/_cards/diffvalue.card.html +3 -3
  56. package/components/_cards/divider.card.html +4 -4
  57. package/components/_cards/drawer.card.html +4 -4
  58. package/components/_cards/dropdown-menu.card.html +7 -7
  59. package/components/_cards/dropzone.card.html +5 -3
  60. package/components/_cards/empty-state.card.html +6 -6
  61. package/components/_cards/filter-bar.card.html +5 -5
  62. package/components/_cards/icon-button.card.html +14 -14
  63. package/components/_cards/icons-1-core.card.html +4 -4
  64. package/components/_cards/icons-2-feather.card.html +4 -4
  65. package/components/_cards/icons-3-unicons.card.html +4 -4
  66. package/components/_cards/input.card.html +5 -2
  67. package/components/_cards/kbd.card.html +2 -2
  68. package/components/_cards/keyvalue.card.html +2 -2
  69. package/components/_cards/listrow.card.html +2 -2
  70. package/components/_cards/loading.card.html +3 -3
  71. package/components/_cards/log-viewer.card.html +3 -3
  72. package/components/_cards/modal.card.html +9 -9
  73. package/components/_cards/multi-select.card.html +6 -3
  74. package/components/_cards/number-stepper.card.html +9 -5
  75. package/components/_cards/pagination.card.html +6 -3
  76. package/components/_cards/people.card.html +4 -4
  77. package/components/_cards/pipeline-node.card.html +8 -8
  78. package/components/_cards/pipeline-palette.card.html +5 -5
  79. package/components/_cards/radio.card.html +12 -7
  80. package/components/_cards/search.card.html +6 -3
  81. package/components/_cards/segmented-control.card.html +11 -10
  82. package/components/_cards/select.card.html +8 -4
  83. package/components/_cards/slider.card.html +2 -2
  84. package/components/_cards/smart-table.card.html +3 -3
  85. package/components/_cards/spreadsheet.card.html +3 -3
  86. package/components/_cards/stepper.card.html +3 -3
  87. package/components/_cards/table.card.html +165 -0
  88. package/components/_cards/tabs.card.html +6 -3
  89. package/components/_cards/tag.card.html +6 -3
  90. package/components/_cards/textarea.card.html +2 -2
  91. package/components/_cards/timeline.card.html +3 -3
  92. package/components/_cards/toast.card.html +10 -8
  93. package/components/_cards/toggles.card.html +15 -10
  94. package/components/_cards/tooltip.card.html +7 -7
  95. package/components/_cards/tree.card.html +3 -3
  96. package/components/_shared/card-kit.css +25 -0
  97. package/components/_shared/card-kit.js +50 -0
  98. package/components/_shared/src-buttons.js +1 -1
  99. package/components/_shared/src-charts.js +1 -1
  100. package/components/_shared/src-data.js +1 -1
  101. package/components/_shared/src-display.js +1 -1
  102. package/components/_shared/src-feedback.js +1 -1
  103. package/components/_shared/src-forms.js +1 -1
  104. package/components/_shared/src-icons.js +1 -1
  105. package/components/_shared/src-navigation.js +1 -1
  106. package/components/_shared/src-pipeline.js +1 -1
  107. package/components/_shared/src-tabs.js +1 -1
  108. package/components/_shared/view-source.js +3 -3
  109. package/components/_vue/index.mjs +16 -5
  110. package/components/buttons/ActionChip.d.ts +3 -1
  111. package/components/buttons/ActionChip.jsx +4 -4
  112. package/components/buttons/ActionChip.vue +4 -4
  113. package/components/buttons/Button.d.ts +5 -2
  114. package/components/buttons/Button.jsx +15 -18
  115. package/components/buttons/Button.vue +17 -18
  116. package/components/buttons/ButtonGroup.vue +1 -1
  117. package/components/buttons/IconButton.d.ts +2 -1
  118. package/components/buttons/IconButton.jsx +13 -9
  119. package/components/buttons/IconButton.vue +12 -9
  120. package/components/buttons/buttons.prompt.md +6 -5
  121. package/components/charts/Bar3D.jsx +2 -2
  122. package/components/charts/Bar3D.vue +3 -3
  123. package/components/charts/BarChart.jsx +4 -4
  124. package/components/charts/BarChart.vue +6 -6
  125. package/components/charts/BarList.jsx +4 -4
  126. package/components/charts/BarList.vue +4 -4
  127. package/components/charts/BoxPlot.jsx +1 -1
  128. package/components/charts/BoxPlot.vue +3 -3
  129. package/components/charts/BulletChart.jsx +6 -6
  130. package/components/charts/BulletChart.vue +6 -6
  131. package/components/charts/CandlestickChart.jsx +2 -2
  132. package/components/charts/CandlestickChart.vue +5 -5
  133. package/components/charts/ChartKit.jsx +8 -7
  134. package/components/charts/ChartLegend.vue +16 -0
  135. package/components/charts/ChartTooltip.vue +16 -0
  136. package/components/charts/ChordChart.jsx +2 -2
  137. package/components/charts/ChordChart.vue +3 -3
  138. package/components/charts/DonutChart.jsx +1 -1
  139. package/components/charts/DonutChart.vue +2 -2
  140. package/components/charts/FunnelChart.jsx +3 -3
  141. package/components/charts/FunnelChart.vue +4 -4
  142. package/components/charts/GanttChart.jsx +2 -2
  143. package/components/charts/GanttChart.vue +3 -3
  144. package/components/charts/GaugeChart.jsx +2 -2
  145. package/components/charts/GaugeChart.vue +2 -2
  146. package/components/charts/HeatmapChart.jsx +2 -2
  147. package/components/charts/HeatmapChart.vue +2 -2
  148. package/components/charts/Histogram.jsx +2 -2
  149. package/components/charts/Histogram.vue +4 -4
  150. package/components/charts/LineChart.jsx +1 -1
  151. package/components/charts/LineChart.vue +4 -4
  152. package/components/charts/ParetoChart.jsx +3 -3
  153. package/components/charts/ParetoChart.vue +5 -5
  154. package/components/charts/Pie3D.jsx +1 -1
  155. package/components/charts/Pie3D.vue +2 -2
  156. package/components/charts/PlotGrid.vue +18 -0
  157. package/components/charts/RadarChart.jsx +1 -1
  158. package/components/charts/RadarChart.vue +2 -2
  159. package/components/charts/Ribbon3D.jsx +2 -2
  160. package/components/charts/Ribbon3D.vue +3 -3
  161. package/components/charts/SankeyChart.jsx +2 -2
  162. package/components/charts/SankeyChart.vue +3 -3
  163. package/components/charts/Scatter3D.jsx +1 -1
  164. package/components/charts/Scatter3D.vue +2 -2
  165. package/components/charts/ScatterChart.jsx +3 -3
  166. package/components/charts/ScatterChart.vue +5 -5
  167. package/components/charts/Sparkline.jsx +1 -1
  168. package/components/charts/Sparkline.vue +1 -1
  169. package/components/charts/SunburstChart.jsx +1 -1
  170. package/components/charts/SunburstChart.vue +2 -2
  171. package/components/charts/Surface3D.jsx +2 -2
  172. package/components/charts/Surface3D.vue +3 -3
  173. package/components/charts/TreemapChart.jsx +2 -2
  174. package/components/charts/TreemapChart.vue +3 -3
  175. package/components/charts/WaterfallChart.jsx +2 -2
  176. package/components/charts/WaterfallChart.vue +6 -5
  177. package/components/charts/WorldMap.jsx +4 -4
  178. package/components/charts/WorldMap.vue +5 -5
  179. package/components/charts/XLabels.vue +11 -0
  180. package/components/data/CodeBlock.jsx +1 -1
  181. package/components/data/CodeBlock.vue +1 -1
  182. package/components/data/DiffValue.d.ts +1 -0
  183. package/components/data/DiffValue.jsx +1 -1
  184. package/components/data/DiffValue.vue +1 -1
  185. package/components/data/FilterBar.d.ts +2 -0
  186. package/components/data/FilterBar.jsx +10 -9
  187. package/components/data/FilterBar.vue +9 -8
  188. package/components/data/KeyValue.d.ts +1 -1
  189. package/components/data/KeyValue.jsx +4 -4
  190. package/components/data/KeyValue.vue +4 -4
  191. package/components/data/ListRow.jsx +2 -2
  192. package/components/data/ListRow.vue +2 -2
  193. package/components/data/Pagination.d.ts +5 -1
  194. package/components/data/Pagination.jsx +16 -12
  195. package/components/data/Pagination.vue +14 -9
  196. package/components/data/SmartTable.d.ts +4 -1
  197. package/components/data/SmartTable.jsx +16 -14
  198. package/components/data/SmartTable.vue +26 -23
  199. package/components/data/Spreadsheet.d.ts +2 -0
  200. package/components/data/Spreadsheet.jsx +16 -15
  201. package/components/data/Spreadsheet.vue +19 -18
  202. package/components/data/Table.d.ts +101 -0
  203. package/components/data/Table.jsx +223 -0
  204. package/components/data/Table.vue +153 -0
  205. package/components/data/data.prompt.md +3 -3
  206. package/components/display/Avatar.jsx +2 -2
  207. package/components/display/Avatar.vue +3 -2
  208. package/components/display/AvatarGroup.vue +3 -2
  209. package/components/display/Badge.d.ts +4 -1
  210. package/components/display/Badge.jsx +10 -5
  211. package/components/display/Badge.vue +1 -1
  212. package/components/display/Divider.vue +3 -3
  213. package/components/display/Donut.vue +3 -2
  214. package/components/display/IconTile.vue +10 -4
  215. package/components/display/Kbd.d.ts +1 -1
  216. package/components/display/Kbd.jsx +1 -1
  217. package/components/display/Kbd.vue +2 -2
  218. package/components/display/ProgressBar.jsx +1 -1
  219. package/components/display/ProgressBar.vue +1 -1
  220. package/components/display/StatCard.vue +1 -1
  221. package/components/display/Tag.d.ts +3 -1
  222. package/components/display/Tag.jsx +4 -4
  223. package/components/display/Tag.vue +4 -4
  224. package/components/feedback/Accordion.jsx +2 -2
  225. package/components/feedback/Accordion.vue +2 -2
  226. package/components/feedback/ActivityItem.d.ts +3 -1
  227. package/components/feedback/ActivityItem.jsx +6 -6
  228. package/components/feedback/ActivityItem.vue +5 -4
  229. package/components/feedback/Alert.jsx +4 -4
  230. package/components/feedback/Alert.vue +3 -3
  231. package/components/feedback/Banner.jsx +5 -5
  232. package/components/feedback/Banner.vue +5 -5
  233. package/components/feedback/ContextMenu.d.ts +3 -1
  234. package/components/feedback/ContextMenu.jsx +5 -5
  235. package/components/feedback/ContextMenu.vue +5 -5
  236. package/components/feedback/DotActivity.vue +3 -3
  237. package/components/feedback/Drawer.d.ts +2 -0
  238. package/components/feedback/Drawer.jsx +6 -6
  239. package/components/feedback/Drawer.vue +22 -15
  240. package/components/feedback/EmptyState.vue +2 -2
  241. package/components/feedback/LogViewer.vue +1 -1
  242. package/components/feedback/Modal.d.ts +2 -0
  243. package/components/feedback/Modal.jsx +12 -11
  244. package/components/feedback/Modal.vue +10 -8
  245. package/components/feedback/Skeleton.vue +2 -1
  246. package/components/feedback/Spinner.vue +2 -1
  247. package/components/feedback/Stepper.vue +1 -1
  248. package/components/feedback/Timeline.jsx +1 -1
  249. package/components/feedback/Timeline.vue +3 -3
  250. package/components/feedback/Toast.vue +4 -4
  251. package/components/feedback/ToastStack.vue +11 -0
  252. package/components/feedback/Tooltip.vue +19 -0
  253. package/components/feedback/feedback.prompt.md +4 -4
  254. package/components/forms/Checkbox.d.ts +3 -2
  255. package/components/forms/Checkbox.jsx +7 -7
  256. package/components/forms/Checkbox.vue +8 -8
  257. package/components/forms/Combobox.d.ts +2 -0
  258. package/components/forms/Combobox.jsx +12 -10
  259. package/components/forms/Combobox.vue +11 -10
  260. package/components/forms/DatePicker.d.ts +4 -0
  261. package/components/forms/DatePicker.jsx +16 -12
  262. package/components/forms/DatePicker.vue +15 -11
  263. package/components/forms/Dropzone.jsx +2 -2
  264. package/components/forms/Dropzone.vue +5 -5
  265. package/components/forms/Field.d.ts +5 -1
  266. package/components/forms/Field.jsx +4 -4
  267. package/components/forms/Field.vue +4 -4
  268. package/components/forms/Input.d.ts +5 -1
  269. package/components/forms/Input.jsx +8 -8
  270. package/components/forms/Input.vue +3 -3
  271. package/components/forms/MultiSelect.d.ts +2 -0
  272. package/components/forms/MultiSelect.jsx +13 -11
  273. package/components/forms/MultiSelect.vue +12 -11
  274. package/components/forms/NumberStepper.d.ts +3 -1
  275. package/components/forms/NumberStepper.jsx +7 -7
  276. package/components/forms/NumberStepper.vue +8 -7
  277. package/components/forms/Radio.d.ts +5 -3
  278. package/components/forms/Radio.jsx +13 -15
  279. package/components/forms/Radio.vue +9 -10
  280. package/components/forms/RadioGroup.vue +5 -5
  281. package/components/forms/SearchInput.d.ts +3 -1
  282. package/components/forms/SearchInput.jsx +6 -6
  283. package/components/forms/SearchInput.vue +7 -6
  284. package/components/forms/Select.d.ts +3 -2
  285. package/components/forms/Select.jsx +6 -7
  286. package/components/forms/Select.vue +6 -6
  287. package/components/forms/Slider.jsx +3 -3
  288. package/components/forms/Slider.vue +3 -3
  289. package/components/forms/Switch.d.ts +2 -2
  290. package/components/forms/Switch.jsx +20 -22
  291. package/components/forms/Switch.vue +22 -18
  292. package/components/forms/Textarea.vue +5 -5
  293. package/components/forms/forms.prompt.md +1 -1
  294. package/components/forms/input-base.js +2 -1
  295. package/components/icons/Icon.jsx +17 -1
  296. package/components/icons/Icon.prompt.md +2 -0
  297. package/components/icons/Icon.vue +1 -1
  298. package/components/icons/icon-paths.js +15 -0
  299. package/components/index.d.ts +1 -2
  300. package/components/index.js +4 -5
  301. package/components/navigation/Breadcrumb.jsx +6 -10
  302. package/components/navigation/Breadcrumb.vue +6 -12
  303. package/components/navigation/DocTree.jsx +3 -3
  304. package/components/navigation/DocTree.vue +3 -3
  305. package/components/navigation/PageHeading.vue +1 -1
  306. package/components/navigation/PageToolbar.vue +7 -6
  307. package/components/navigation/Sidebar.jsx +4 -23
  308. package/components/navigation/Sidebar.vue +5 -10
  309. package/components/navigation/ThemeToggle.vue +2 -1
  310. package/components/navigation/TopBar.d.ts +3 -1
  311. package/components/navigation/TopBar.jsx +6 -6
  312. package/components/navigation/Tree.jsx +5 -5
  313. package/components/navigation/Tree.vue +13 -8
  314. package/components/navigation/nav-model.js +23 -0
  315. package/components/navigation/theme-store.js +9 -0
  316. package/components/pipeline/ConfigPanel.d.ts +2 -0
  317. package/components/pipeline/ConfigPanel.jsx +9 -9
  318. package/components/pipeline/ConfigPanel.vue +9 -9
  319. package/components/pipeline/DataPreview.d.ts +3 -1
  320. package/components/pipeline/DataPreview.jsx +7 -7
  321. package/components/pipeline/DataPreview.vue +7 -7
  322. package/components/pipeline/NodeCard.jsx +3 -3
  323. package/components/pipeline/NodeCard.vue +3 -3
  324. package/components/pipeline/PaletteItem.vue +2 -2
  325. package/components/pipeline/PaletteListItem.vue +1 -1
  326. package/components/pipeline/PalettePanel.jsx +2 -2
  327. package/components/pipeline/PalettePanel.vue +1 -1
  328. package/components/pipeline/Port.vue +15 -0
  329. package/components/pipeline/PortLabel.vue +15 -0
  330. package/components/pipeline/ZoomControls.vue +1 -1
  331. package/components/pipeline/port-skin.js +13 -0
  332. package/components/px.js +4 -0
  333. package/components/tabs/PanelTabs.vue +5 -4
  334. package/components/tabs/PillTabs.vue +5 -4
  335. package/components/tabs/SegmentedControl.d.ts +2 -2
  336. package/components/tabs/SegmentedControl.jsx +7 -7
  337. package/components/tabs/SegmentedControl.vue +7 -7
  338. package/components/tabs/Tabs.d.ts +5 -3
  339. package/components/tabs/Tabs.jsx +15 -15
  340. package/components/tabs/Tabs.vue +5 -5
  341. package/components/tabs/ViewToggle.d.ts +3 -1
  342. package/components/tabs/ViewToggle.jsx +5 -5
  343. package/components/tabs/ViewToggle.vue +5 -5
  344. package/components/tabs/tabs.prompt.md +1 -1
  345. package/keybricks.css +4 -0
  346. package/package.json +6 -3
  347. package/readme.md +91 -122
  348. package/readme.zh-CN.md +121 -0
  349. package/tokens/alpha.css +3 -1
  350. package/tokens/charts.css +20 -17
  351. package/tokens/colors.css +3 -3
  352. package/tokens/dark.css +3 -3
  353. package/tokens/hover.css +32 -0
  354. package/tokens/interaction.css +3 -1
  355. package/tokens/layout.css +31 -7
  356. package/tokens/tokens.d.ts +58 -0
  357. package/tokens/tokens.js +179 -92
  358. package/tokens/tokens.json +327 -114
  359. package/tokens/typography.css +45 -15
  360. package/components/_cards/brand-visual.card.html +0 -43
  361. package/components/_cards/datatable.card.html +0 -48
  362. package/components/_shared/src-brand.js +0 -1
  363. package/components/brand/BrandVisual.d.ts +0 -17
  364. package/components/brand/BrandVisual.jsx +0 -29
  365. package/components/brand/BrandVisual.vue +0 -34
  366. package/components/brand/_dir.card.html +0 -13
  367. package/components/brand/brandMotifs.js +0 -210
  368. package/components/buttons/_dir.card.html +0 -13
  369. package/components/charts/ChartKit.vue +0 -47
  370. package/components/charts/_dir.card.html +0 -7
  371. package/components/data/DataTable.d.ts +0 -28
  372. package/components/data/DataTable.jsx +0 -32
  373. package/components/data/DataTable.vue +0 -25
  374. package/components/data/_dir.card.html +0 -13
  375. package/components/display/_dir.card.html +0 -13
  376. package/components/feedback/_dir.card.html +0 -13
  377. package/components/forms/_dir.card.html +0 -13
  378. package/components/icons/_dir.card.html +0 -13
  379. package/components/navigation/_dir.card.html +0 -13
  380. package/components/pipeline/_dir.card.html +0 -13
  381. package/components/tabs/_dir.card.html +0 -13
@@ -5,7 +5,7 @@ const props = defineProps({ modelValue: { type: Number, default: 100 }, style: O
5
5
  const emit = defineEmits(['update:modelValue', 'fit'])
6
6
  </script>
7
7
  <template>
8
- <div :style="{ display: 'inline-flex', alignItems: 'center', gap: 2, background: 'var(--bg-surface)', border: '1px solid var(--border-control)', borderRadius: 'var(--radius-md)', boxShadow: 'var(--shadow-menu)', padding: 3, boxSizing: 'border-box', ...style }">
8
+ <div :style="{ display: 'inline-flex', alignItems: 'center', gap: '2px', background: 'var(--bg-surface)', border: '1px solid var(--border-control)', borderRadius: 'var(--radius-md)', boxShadow: 'var(--shadow-menu)', padding: '3px', boxSizing: 'border-box', ...style }">
9
9
  <IconButton icon="minus" size="sm" label="Zoom out" @click="emit('update:modelValue', Math.max(25, modelValue - 10))" />
10
10
  <span style="min-width:40px;text-align:center;font-family:var(--font-sans);font-size:var(--text-xs);color:var(--text-secondary)">{{ modelValue }}%</span>
11
11
  <IconButton icon="plus" size="sm" label="Zoom in" @click="emit('update:modelValue', Math.min(200, modelValue + 10))" />
@@ -0,0 +1,13 @@
1
+ // Shared port skin for Port.vue / PortLabel.vue / NodeCard.vue — mirrors portSkin() in NodeCard.jsx.
2
+ // tone: "default" | "active" (a wire is being dragged from it) | "target" (valid drop here).
3
+ export function portSkin(tone, hover, interactive) {
4
+ const hot = tone === 'active' || tone === 'target' || (interactive && hover)
5
+ return {
6
+ background: tone === 'target' ? 'var(--soft-bg)' : 'var(--bg-surface)',
7
+ border: `2px solid ${hot ? 'var(--action-primary)' : 'var(--port-border)'}`,
8
+ boxShadow: tone === 'active' || tone === 'target' ? '0 0 0 3px var(--focus-ring)' : 'none',
9
+ color: hot ? 'var(--action-primary)' : 'var(--text-muted)',
10
+ cursor: interactive ? (tone === 'active' ? 'grabbing' : 'grab') : 'default',
11
+ transition: 'var(--t-hover)'
12
+ }
13
+ }
@@ -0,0 +1,4 @@
1
+ // Vue's :style binding does not append "px" to numbers the way React does —
2
+ // { height: 30 } is silently dropped by the browser. Wrap any numeric length in px().
3
+ // Strings ('100%', 'var(--radius-md)', '12px') pass through untouched.
4
+ export const px = (v) => (typeof v === 'number' ? v + 'px' : v)
@@ -1,10 +1,11 @@
1
1
  <script setup>
2
- defineProps({ tabs: { type: Array, default: () => [] }, active: String, style: Object })
2
+ // Panel tabs (Node Info · Calc Rules · …): a lighter underline tab bar at the region's bar height with regular-weight control text. Put the panel in an sm region for the compact 32px/12px look.
3
+ defineProps({ tabs: { type: Array, default: () => [] }, active: String, size: String, style: Object })
3
4
  const emit = defineEmits(['change'])
4
5
  </script>
5
6
  <template>
6
- <div :style="{ display: 'flex', borderBottom: '1px solid var(--border-subtle)', ...style }">
7
- <button v-for="t in tabs" :key="t" type="button" @click="emit('change', t)"
8
- :style="{ background: 'transparent', border: 'none', cursor: 'pointer', padding: '8px 12px', marginBottom: -1, borderBottom: t === active ? '2px solid var(--action-primary)' : '2px solid transparent', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-sm)', lineHeight: 'var(--leading-sm)', color: t === active ? 'var(--action-primary)' : 'var(--text-secondary)' }">{{ t }}</button>
7
+ <div role="tablist" :data-size="size" :style="{ display: 'flex', borderBottom: '1px solid var(--border-subtle)', ...style }">
8
+ <button v-for="t in tabs" :key="t" type="button" role="tab" :aria-selected="t === active" :data-ink="t === active ? undefined : ''" @click="emit('change', t)"
9
+ :style="{ background: 'transparent', border: 'none', cursor: 'pointer', height: 'var(--bar-h)', boxSizing: 'border-box', padding: '0 var(--control-px)', marginBottom: '-1px', borderBottom: t === active ? '2px solid var(--action-primary)' : '2px solid transparent', fontFamily: 'var(--font-sans)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: t === active ? 'var(--action-primary)' : 'var(--ink, var(--text-secondary))', whiteSpace: 'nowrap' }">{{ t }}</button>
9
10
  </div>
10
11
  </template>
@@ -1,10 +1,11 @@
1
1
  <script setup>
2
- defineProps({ tabs: { type: Array, default: () => [] }, active: String, style: Object })
2
+ // Text pill filter tabs. Active = tinted pill. Pills are control-height (sm 28 · md 32 · lg 40); omit `size` to inherit.
3
+ defineProps({ tabs: { type: Array, default: () => [] }, active: String, size: String, style: Object })
3
4
  const emit = defineEmits(['change'])
4
5
  </script>
5
6
  <template>
6
- <div :style="{ display: 'flex', gap: 8, ...style }">
7
- <button v-for="t in tabs" :key="t" type="button" @click="emit('change', t)"
8
- :style="{ background: t === active ? 'var(--bg-active)' : 'transparent', border: 'none', cursor: 'pointer', height: 28, padding: '0 11px', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--text-sm)', lineHeight: 'var(--leading-sm)', color: t === active ? 'var(--text-heading)' : 'var(--text-secondary)' }">{{ t }}</button>
7
+ <div role="tablist" :data-size="size" :style="{ display: 'flex', gap: 'var(--control-gap)', ...style }">
8
+ <button v-for="t in tabs" :key="t" type="button" role="tab" :aria-selected="t === active" :data-ink="t === active ? undefined : ''" :data-wash="t === active ? undefined : ''" @click="emit('change', t)"
9
+ :style="{ background: t === active ? 'var(--bg-active)' : 'var(--wash, transparent)', border: 'none', cursor: 'pointer', height: 'var(--control-h)', padding: '0 var(--control-px)', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: t === active ? 'var(--text-heading)' : 'var(--ink, var(--text-secondary))', whiteSpace: 'nowrap' }">{{ t }}</button>
9
10
  </div>
10
11
  </template>
@@ -5,8 +5,8 @@ export interface SegmentedControlProps {
5
5
  options?: (string | { label: string; icon?: string; disabled?: boolean })[];
6
6
  value?: string;
7
7
  onChange?: (value: string) => void;
8
- /** md 32px (default) · sm 26px */
9
- size?: "sm" | "md";
8
+ /** Size tier: sm 28 · md 32 · lg 40. Omit to inherit the enclosing region's tier (the default). */
9
+ size?: "sm" | "md" | "lg";
10
10
  /** Hide labels; each label becomes the segment's aria-label and tooltip */
11
11
  iconOnly?: boolean;
12
12
  /** Greys the whole control */
@@ -4,12 +4,12 @@ import { Icon } from "../icons/Icon.jsx";
4
4
  /**
5
5
  * Segmented control — inset track, raised active segment. Switches views of the same data, applies instantly.
6
6
  * options: string[] | { label, icon?, disabled? }[] value/onChange by label
7
- * size "md" (32) | "sm" (26) · iconOnly hides labels (label becomes aria-label / title)
7
+ * size sm 28 | md 32 | lg 40 — omit it to inherit the region's tier · iconOnly hides labels (label becomes aria-label / title)
8
8
  * disabled greys the whole control · fullWidth stretches segments evenly
9
9
  * Keyboard: ← → move between enabled segments.
10
10
  */
11
- export function SegmentedControl({ options = [], value, onChange, size = "md", iconOnly, disabled, fullWidth, style }) {
12
- const h = size === "sm" ? 26 : 32;
11
+ const tierIcon = { width: "var(--control-icon)", height: "var(--control-icon)" };
12
+ export function SegmentedControl({ options = [], value, onChange, size, iconOnly, disabled, fullWidth, style }) {
13
13
  const opts = options.map((o) => (typeof o === "string" ? { label: o } : o));
14
14
  const enabled = opts.filter((o) => !o.disabled);
15
15
  const onKey = (e) => {
@@ -20,14 +20,14 @@ export function SegmentedControl({ options = [], value, onChange, size = "md", i
20
20
  onChange && onChange(n.label);
21
21
  };
22
22
  return (
23
- <div role="tablist" aria-disabled={disabled || undefined} onKeyDown={onKey} style={{ display: fullWidth ? "flex" : "inline-flex", padding: 2, gap: 2, background: "var(--bg-inset)", border: "1px solid var(--border-control)", borderRadius: "var(--radius-md)", boxSizing: "border-box", opacity: disabled ? .5 : 1, ...style }}>
23
+ <div role="tablist" data-size={size} aria-disabled={disabled || undefined} onKeyDown={onKey} style={{ display: fullWidth ? "flex" : "inline-flex", height: "var(--control-h)", padding: 2, gap: 2, background: "var(--bg-inset)", border: "1px solid var(--border-control)", borderRadius: "var(--radius-md)", boxSizing: "border-box", opacity: disabled ? .5 : 1, ...style }}>
24
24
  {opts.map((o) => {
25
25
  const is = value === o.label, off = disabled || o.disabled;
26
26
  return (
27
- <button key={o.label} type="button" role="tab" aria-selected={is} aria-label={iconOnly ? o.label : undefined} title={iconOnly ? o.label : undefined} disabled={off} tabIndex={is ? 0 : -1}
27
+ <button key={o.label} type="button" role="tab" aria-selected={is} aria-label={iconOnly ? o.label : undefined} title={iconOnly ? o.label : undefined} disabled={off} tabIndex={is ? 0 : -1} data-ink={is || off ? undefined : ""}
28
28
  onClick={() => !off && onChange && onChange(o.label)}
29
- style={{ height: h - 6, padding: iconOnly ? "0 8px" : "0 10px", flex: fullWidth ? 1 : "none", justifyContent: "center", display: "inline-flex", alignItems: "center", gap: 6, borderRadius: "var(--radius-sm)", border: "none", cursor: off ? "not-allowed" : "pointer", background: is ? "var(--bg-surface)" : "transparent", boxShadow: is ? "0 1px 2px rgba(0,0,0,.08)" : "none", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: size === "sm" ? "var(--text-xs)" : "var(--text-sm)", color: is ? "var(--text-heading)" : "var(--text-secondary)", opacity: o.disabled && !disabled ? .45 : 1, whiteSpace: "nowrap", transition: "var(--t-hover)" }}>
30
- {o.icon ? <Icon name={o.icon} size={13} /> : null}{iconOnly ? null : o.label}
29
+ style={{ height: "calc(var(--control-h) - 6px)", padding: iconOnly ? "0 calc(var(--control-px) - 4px)" : "0 calc(var(--control-px) - 2px)", flex: fullWidth ? 1 : "none", justifyContent: "center", display: "inline-flex", alignItems: "center", gap: 6, borderRadius: "var(--radius-sm)", border: "none", cursor: off ? "not-allowed" : "pointer", background: is ? "var(--bg-surface)" : "transparent", boxShadow: is ? "0 1px 2px rgba(0,0,0,.08)" : "none", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--text-heading)" : "var(--ink, var(--text-secondary))", opacity: o.disabled && !disabled ? .45 : 1, whiteSpace: "nowrap", transition: "var(--t-hover)" }}>
30
+ {o.icon ? <Icon name={o.icon} size={16} style={tierIcon} /> : null}{iconOnly ? null : o.label}
31
31
  </button>
32
32
  );
33
33
  })}
@@ -2,13 +2,13 @@
2
2
  import { computed } from 'vue'
3
3
  import Icon from '../icons/Icon.vue'
4
4
  // Segmented control — inset track, raised active segment. Switches views of the same data, applies instantly.
5
- // options: string[] | { label, icon?, disabled? }[] · v-model by label · size md (32) | sm (26)
5
+ // options: string[] | { label, icon?, disabled? }[] · v-model by label · size sm 28 | md 32 | lg 40 — omit it to inherit the region's tier
6
6
  // iconOnly hides labels (label → aria-label/title) · disabled greys the control · fullWidth stretches segments · ← → keyboard.
7
- const props = defineProps({ options: { type: Array, default: () => [] }, modelValue: String, size: { type: String, default: 'md' }, iconOnly: Boolean, disabled: Boolean, fullWidth: Boolean, style: Object })
7
+ const tierIcon = { width: 'var(--control-icon)', height: 'var(--control-icon)' }
8
+ const props = defineProps({ options: { type: Array, default: () => [] }, modelValue: String, size: String, iconOnly: Boolean, disabled: Boolean, fullWidth: Boolean, style: Object })
8
9
  const emit = defineEmits(['update:modelValue'])
9
10
  const opts = computed(() => props.options.map(o => typeof o === 'string' ? { label: o } : o))
10
11
  const enabled = computed(() => opts.value.filter(o => !o.disabled))
11
- const h = computed(() => props.size === 'sm' ? 26 : 32)
12
12
  const pick = (o) => { if (!(props.disabled || o.disabled)) emit('update:modelValue', o.label) }
13
13
  function onKey(e) {
14
14
  if ((e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') || props.disabled || !enabled.value.length) return
@@ -18,10 +18,10 @@ function onKey(e) {
18
18
  }
19
19
  </script>
20
20
  <template>
21
- <div role="tablist" :aria-disabled="disabled || undefined" @keydown="onKey" :style="{ display: fullWidth ? 'flex' : 'inline-flex', padding: '2px', gap: '2px', background: 'var(--bg-inset)', border: '1px solid var(--border-control)', borderRadius: 'var(--radius-md)', boxSizing: 'border-box', opacity: disabled ? .5 : 1, ...style }">
22
- <button v-for="o in opts" :key="o.label" type="button" role="tab" :aria-selected="modelValue === o.label" :aria-label="iconOnly ? o.label : undefined" :title="iconOnly ? o.label : undefined" :disabled="disabled || o.disabled" :tabindex="modelValue === o.label ? 0 : -1" @click="pick(o)"
23
- :style="{ height: (h - 6) + 'px', padding: iconOnly ? '0 8px' : '0 10px', flex: fullWidth ? 1 : 'none', justifyContent: 'center', display: 'inline-flex', alignItems: 'center', gap: '6px', borderRadius: 'var(--radius-sm)', border: 'none', cursor: (disabled || o.disabled) ? 'not-allowed' : 'pointer', background: modelValue === o.label ? 'var(--bg-surface)' : 'transparent', boxShadow: modelValue === o.label ? '0 1px 2px rgba(0,0,0,.08)' : 'none', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: size === 'sm' ? 'var(--text-xs)' : 'var(--text-sm)', color: modelValue === o.label ? 'var(--text-heading)' : 'var(--text-secondary)', opacity: o.disabled && !disabled ? .45 : 1, whiteSpace: 'nowrap', transition: 'var(--t-hover)' }">
24
- <Icon v-if="o.icon" :name="o.icon" :size="13" /><template v-if="!iconOnly">{{ o.label }}</template>
21
+ <div role="tablist" :data-size="size" :aria-disabled="disabled || undefined" @keydown="onKey" :style="{ display: fullWidth ? 'flex' : 'inline-flex', height: 'var(--control-h)', padding: '2px', gap: '2px', background: 'var(--bg-inset)', border: '1px solid var(--border-control)', borderRadius: 'var(--radius-md)', boxSizing: 'border-box', opacity: disabled ? .5 : 1, ...style }">
22
+ <button v-for="o in opts" :key="o.label" type="button" role="tab" :aria-selected="modelValue === o.label" :aria-label="iconOnly ? o.label : undefined" :title="iconOnly ? o.label : undefined" :disabled="disabled || o.disabled" :tabindex="modelValue === o.label ? 0 : -1" :data-ink="modelValue === o.label || disabled || o.disabled ? undefined : ''" @click="pick(o)"
23
+ :style="{ height: 'calc(var(--control-h) - 6px)', padding: iconOnly ? '0 calc(var(--control-px) - 4px)' : '0 calc(var(--control-px) - 2px)', flex: fullWidth ? 1 : 'none', justifyContent: 'center', display: 'inline-flex', alignItems: 'center', gap: '6px', borderRadius: 'var(--radius-sm)', border: 'none', cursor: (disabled || o.disabled) ? 'not-allowed' : 'pointer', background: modelValue === o.label ? 'var(--bg-surface)' : 'transparent', boxShadow: modelValue === o.label ? '0 1px 2px rgba(0,0,0,.08)' : 'none', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: modelValue === o.label ? 'var(--text-heading)' : 'var(--ink, var(--text-secondary))', opacity: o.disabled && !disabled ? .45 : 1, whiteSpace: 'nowrap', transition: 'var(--t-hover)' }">
24
+ <Icon v-if="o.icon" :name="o.icon" :size="16" :style="tierIcon" /><template v-if="!iconOnly">{{ o.label }}</template>
25
25
  </button>
26
26
  </div>
27
27
  </template>
@@ -1,13 +1,15 @@
1
1
  import * as React from "react";
2
- /** Underline tabs (Import/Export). Active: blue text + 2px blue underline on hairline baseline. */
2
+ /** Underline tabs (Import/Export). Active: blue text + 2px blue underline on hairline baseline. The bar is the region's bar height (sm 32 · md 40 · lg 44). */
3
3
  export interface TabsProps {
4
4
  tabs?: string[];
5
5
  active?: string;
6
6
  onChange?: (tab: string) => void;
7
+ /** Size tier. Omit to inherit the enclosing region's tier (the default). */
8
+ size?: "sm" | "md" | "lg";
7
9
  style?: React.CSSProperties;
8
10
  }
9
11
  export declare function Tabs(props: TabsProps): JSX.Element;
10
- /** 12px compact underline tabs for panels (Node Info / Calc Rules / ...). */
12
+ /** Lighter underline tabs for panels (Node Info / Calc Rules / ...), regular weight; an sm region gives the compact 32px/12px look. */
11
13
  export declare function PanelTabs(props: TabsProps): JSX.Element;
12
- /** Text pill filter tabs; active gets a #f5f5f5 pill. */
14
+ /** Text pill filter tabs at control height; active gets a tinted pill. */
13
15
  export declare function PillTabs(props: TabsProps): JSX.Element;
@@ -1,14 +1,14 @@
1
1
  import React from "react";
2
2
 
3
- /** Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline. */
4
- export function Tabs({ tabs = [], active, onChange, style }) {
3
+ /** Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline. The bar is the region's bar height (sm 32 · md 40 · lg 44) with the tier's control text; omit `size` to inherit. */
4
+ export function Tabs({ tabs = [], active, onChange, size, style }) {
5
5
  return (
6
- <div style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border-control)", ...style }}>
6
+ <div role="tablist" data-size={size} style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border-control)", ...style }}>
7
7
  {tabs.map((t) => {
8
8
  const is = t === active;
9
9
  return (
10
- <button key={t} type="button" onClick={() => onChange && onChange(t)}
11
- style={{ background: "transparent", border: "none", cursor: "pointer", padding: "9px 16px", marginBottom: -1, borderBottom: is ? "2px solid var(--action-primary)" : "2px solid transparent", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: is ? "var(--action-primary)" : "var(--text-body)" }}>
10
+ <button key={t} type="button" role="tab" aria-selected={is} data-ink={is ? undefined : ""} onClick={() => onChange && onChange(t)}
11
+ style={{ background: "transparent", border: "none", cursor: "pointer", height: "var(--bar-h)", boxSizing: "border-box", padding: "0 var(--control-px)", marginBottom: -1, borderBottom: is ? "2px solid var(--action-primary)" : "2px solid transparent", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--action-primary)" : "var(--ink, var(--text-body))", whiteSpace: "nowrap" }}>
12
12
  {t}
13
13
  </button>
14
14
  );
@@ -17,15 +17,15 @@ export function Tabs({ tabs = [], active, onChange, style }) {
17
17
  );
18
18
  }
19
19
 
20
- /** Compact panel tabs (Node Info · Calc Rules · Output Fields · SQL Preview), 12px. */
21
- export function PanelTabs({ tabs = [], active, onChange, style }) {
20
+ /** Panel tabs (Node Info · Calc Rules · Output Fields · SQL Preview): a lighter underline tab bar at the region's bar height with regular-weight control text. Put the panel in an sm region for the compact 32px/12px look. */
21
+ export function PanelTabs({ tabs = [], active, onChange, size, style }) {
22
22
  return (
23
- <div style={{ display: "flex", borderBottom: "1px solid var(--border-subtle)", ...style }}>
23
+ <div role="tablist" data-size={size} style={{ display: "flex", borderBottom: "1px solid var(--border-subtle)", ...style }}>
24
24
  {tabs.map((t) => {
25
25
  const is = t === active;
26
26
  return (
27
- <button key={t} type="button" onClick={() => onChange && onChange(t)}
28
- style={{ background: "transparent", border: "none", cursor: "pointer", padding: "8px 12px", marginBottom: -1, borderBottom: is ? "2px solid var(--action-primary)" : "2px solid transparent", fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: is ? "var(--action-primary)" : "var(--text-secondary)" }}>
27
+ <button key={t} type="button" role="tab" aria-selected={is} data-ink={is ? undefined : ""} onClick={() => onChange && onChange(t)}
28
+ style={{ background: "transparent", border: "none", cursor: "pointer", height: "var(--bar-h)", boxSizing: "border-box", padding: "0 var(--control-px)", marginBottom: -1, borderBottom: is ? "2px solid var(--action-primary)" : "2px solid transparent", fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--action-primary)" : "var(--ink, var(--text-secondary))", whiteSpace: "nowrap" }}>
29
29
  {t}
30
30
  </button>
31
31
  );
@@ -34,15 +34,15 @@ export function PanelTabs({ tabs = [], active, onChange, style }) {
34
34
  );
35
35
  }
36
36
 
37
- /** Text pill filter tabs (For Review · To be Submitted · For Approval). Active = #f5f5f5 pill. */
38
- export function PillTabs({ tabs = [], active, onChange, style }) {
37
+ /** Text pill filter tabs (For Review · To be Submitted · For Approval). Active = tinted pill. Pills are control-height (sm 28 · md 32 · lg 40); omit `size` to inherit. */
38
+ export function PillTabs({ tabs = [], active, onChange, size, style }) {
39
39
  return (
40
- <div style={{ display: "flex", gap: 8, ...style }}>
40
+ <div role="tablist" data-size={size} style={{ display: "flex", gap: "var(--control-gap)", ...style }}>
41
41
  {tabs.map((t) => {
42
42
  const is = t === active;
43
43
  return (
44
- <button key={t} type="button" onClick={() => onChange && onChange(t)}
45
- style={{ background: is ? "var(--bg-active)" : "transparent", border: "none", cursor: "pointer", height: 28, padding: "0 11px", borderRadius: "var(--radius-md)", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: is ? "var(--text-heading)" : "var(--text-secondary)" }}>
44
+ <button key={t} type="button" role="tab" aria-selected={is} data-ink={is ? undefined : ""} data-wash={is ? undefined : ""} onClick={() => onChange && onChange(t)}
45
+ style={{ background: is ? "var(--bg-active)" : "var(--wash, transparent)", border: "none", cursor: "pointer", height: "var(--control-h)", padding: "0 var(--control-px)", borderRadius: "var(--radius-md)", fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", color: is ? "var(--text-heading)" : "var(--ink, var(--text-secondary))", whiteSpace: "nowrap" }}>
46
46
  {t}
47
47
  </button>
48
48
  );
@@ -1,11 +1,11 @@
1
1
  <script setup>
2
- // Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline.
3
- defineProps({ tabs: { type: Array, default: () => [] }, active: String, style: Object })
2
+ // Underline tabs on a hairline baseline (Import/Export). Active = blue text + 2px blue underline. The bar is the region's bar height (sm 32 · md 40 · lg 44) with the tier's control text; omit `size` to inherit.
3
+ defineProps({ tabs: { type: Array, default: () => [] }, active: String, size: String, style: Object })
4
4
  const emit = defineEmits(['change'])
5
5
  </script>
6
6
  <template>
7
- <div :style="{ display: 'flex', gap: 4, borderBottom: '1px solid var(--border-control)', ...style }">
8
- <button v-for="t in tabs" :key="t" type="button" @click="emit('change', t)"
9
- :style="{ background: 'transparent', border: 'none', cursor: 'pointer', padding: '9px 16px', marginBottom: -1, borderBottom: t === active ? '2px solid var(--action-primary)' : '2px solid transparent', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--text-base)', lineHeight: 'var(--leading-base)', letterSpacing: 'var(--tracking-base)', color: t === active ? 'var(--action-primary)' : 'var(--text-body)' }">{{ t }}</button>
7
+ <div role="tablist" :data-size="size" :style="{ display: 'flex', gap: '4px', borderBottom: '1px solid var(--border-control)', ...style }">
8
+ <button v-for="t in tabs" :key="t" type="button" role="tab" :aria-selected="t === active" :data-ink="t === active ? undefined : ''" @click="emit('change', t)"
9
+ :style="{ background: 'transparent', border: 'none', cursor: 'pointer', height: 'var(--bar-h)', boxSizing: 'border-box', padding: '0 var(--control-px)', marginBottom: '-1px', borderBottom: t === active ? '2px solid var(--action-primary)' : '2px solid transparent', fontFamily: 'var(--font-sans)', fontWeight: 'var(--weight-medium)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', color: t === active ? 'var(--action-primary)' : 'var(--ink, var(--text-body))', whiteSpace: 'nowrap' }">{{ t }}</button>
10
10
  </div>
11
11
  </template>
@@ -1,7 +1,9 @@
1
1
  import * as React from "react";
2
- /** list/grid segmented icon toggle (26px, r4, active #f5f5f5). */
2
+ /** list/grid icon toggle — two IconButtons at the region's tier (sm 28 · md 32 · lg 40), active gets the tinted wash. */
3
3
  export interface ViewToggleProps {
4
4
  value?: "list" | "grid";
5
+ /** Size tier. Omit to inherit the enclosing region's tier (the default). */
6
+ size?: "sm" | "md" | "lg";
5
7
  onChange?: (v: "list" | "grid") => void;
6
8
  style?: React.CSSProperties;
7
9
  }
@@ -1,12 +1,12 @@
1
1
  import React from "react";
2
2
  import { IconButton } from "../buttons/IconButton.jsx";
3
3
 
4
- /** Two-state list/grid icon toggle (palette header). */
5
- export function ViewToggle({ value = "grid", onChange, style }) {
4
+ /** Two-state list/grid icon toggle (palette header). Two IconButtons at the region's tier; omit `size` to inherit. */
5
+ export function ViewToggle({ value = "grid", onChange, size, style }) {
6
6
  return (
7
- <div style={{ display: "inline-flex", gap: 2, ...style }}>
8
- <IconButton icon="list" size="sm" active={value === "list"} onClick={() => onChange && onChange("list")} label="List view" />
9
- <IconButton icon="layout-grid" size="sm" active={value === "grid"} onClick={() => onChange && onChange("grid")} label="Grid view" />
7
+ <div data-size={size} style={{ display: "inline-flex", gap: 2, ...style }}>
8
+ <IconButton icon="list" active={value === "list"} onClick={() => onChange && onChange("list")} label="List view" />
9
+ <IconButton icon="layout-grid" active={value === "grid"} onClick={() => onChange && onChange("grid")} label="Grid view" />
10
10
  </div>
11
11
  );
12
12
  }
@@ -1,12 +1,12 @@
1
1
  <script setup>
2
2
  import IconButton from '../buttons/IconButton.vue'
3
- // Two-state list/grid icon toggle (palette header).
4
- defineProps({ modelValue: { type: String, default: 'grid' }, style: Object })
3
+ // Two-state list/grid icon toggle (palette header). Two IconButtons at the region's tier; omit `size` to inherit.
4
+ defineProps({ modelValue: { type: String, default: 'grid' }, size: String, style: Object })
5
5
  const emit = defineEmits(['update:modelValue'])
6
6
  </script>
7
7
  <template>
8
- <div :style="{ display: 'inline-flex', gap: 2, ...style }">
9
- <IconButton icon="list" size="sm" :active="modelValue === 'list'" label="List view" @click="emit('update:modelValue', 'list')" />
10
- <IconButton icon="layout-grid" size="sm" :active="modelValue === 'grid'" label="Grid view" @click="emit('update:modelValue', 'grid')" />
8
+ <div :data-size="size" :style="{ display: 'inline-flex', gap: '2px', ...style }">
9
+ <IconButton icon="list" :active="modelValue === 'list'" label="List view" @click="emit('update:modelValue', 'list')" />
10
+ <IconButton icon="layout-grid" :active="modelValue === 'grid'" label="Grid view" @click="emit('update:modelValue', 'grid')" />
11
11
  </div>
12
12
  </template>
@@ -1,4 +1,4 @@
1
- Tab systems: `Tabs` (13px underline — page level), `PanelTabs` (12px underline — config panel), `PillTabs` (pill filters), `ViewToggle` (list/grid icons).
1
+ Tab systems: `Tabs` (underline — page level), `PanelTabs` (lighter underline — config panel, put the panel in an sm region), `PillTabs` (pill filters), `ViewToggle` (list/grid icons). All read the region's size tier: bars are 32 / 40 / 44px, pills 24 / 32 / 36px.
2
2
 
3
3
  ```jsx
4
4
  <Tabs tabs={["Import","Export"]} active={tab} onChange={setTab}/>
package/keybricks.css ADDED
@@ -0,0 +1,4 @@
1
+ /* Consumer entry: tokens + the hover hooks that component inline styles read.
2
+ (hover.css stays outside styles.css so the design-system compiler does not register its state signals as tokens.) */
3
+ @import './styles.css';
4
+ @import './tokens/hover.css';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@keyfunc/keybricks-ds",
3
- "version": "1.0.4",
4
- "description": "Keybricks design system — 334 design tokens and 118 UI components in React and Vue 3, source-only.",
3
+ "version": "2.3.1",
4
+ "description": "Keybricks design system — design tokens, three size tiers and 117 UI components in React and Vue 3, source-only.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "sideEffects": [
@@ -13,7 +13,8 @@
13
13
  "default": "./components/index.js"
14
14
  },
15
15
  "./vue": "./components/_vue/index.mjs",
16
- "./styles.css": "./styles.css",
16
+ "./styles.css": "./keybricks.css",
17
+ "./keybricks.css": "./keybricks.css",
17
18
  "./tokens": {
18
19
  "types": "./tokens/tokens.d.ts",
19
20
  "default": "./tokens/tokens.js"
@@ -31,7 +32,9 @@
31
32
  "assets",
32
33
  "_scripts",
33
34
  "styles.css",
35
+ "keybricks.css",
34
36
  "readme.md",
37
+ "readme.zh-CN.md",
35
38
  "DESIGN.md",
36
39
  "INTEGRATION.md",
37
40
  "DEPLOY.md",