@keyfunc/keybricks-ds 2.1.1 → 2.4.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.
Files changed (280) hide show
  1. package/DEPLOY.md +20 -5
  2. package/DESIGN.md +148 -20
  3. package/INTEGRATION.md +97 -24
  4. package/SKILL.md +11 -11
  5. package/_adherence.oxlintrc.json +56 -24
  6. package/_scripts/build-index.mjs +15 -4
  7. package/assets/icons/icon-index.js +1 -1
  8. package/assets/icons/icon-index.json +1 -1
  9. package/assets/logos/datasource/dat.png +0 -0
  10. package/assets/logos/datasource/excel.png +0 -0
  11. package/assets/logos/datasource/ftp.png +0 -0
  12. package/assets/logos/datasource/hierarchy.png +0 -0
  13. package/assets/logos/datasource/hive.png +0 -0
  14. package/assets/logos/datasource/json.png +0 -0
  15. package/assets/logos/datasource/mariadb.png +0 -0
  16. package/assets/logos/datasource/mongodb.png +0 -0
  17. package/assets/logos/datasource/mysql.png +0 -0
  18. package/assets/logos/datasource/odbc.png +0 -0
  19. package/assets/logos/datasource/oracle.png +0 -0
  20. package/assets/logos/datasource/postgresql.png +0 -0
  21. package/assets/logos/datasource/rest-api.png +0 -0
  22. package/assets/logos/datasource/sap-alt.png +0 -0
  23. package/assets/logos/datasource/sap.png +0 -0
  24. package/assets/logos/datasource/soap.png +0 -0
  25. package/assets/logos/datasource/sql-server.png +0 -0
  26. package/components/_cards/accordion.card.html +1 -1
  27. package/components/_cards/action-chip.card.html +11 -14
  28. package/components/_cards/activity.card.html +2 -2
  29. package/components/_cards/alert.card.html +2 -2
  30. package/components/_cards/app-chrome.card.html +34 -22
  31. package/components/_cards/banner.card.html +1 -1
  32. package/components/_cards/breadcrumb.card.html +4 -4
  33. package/components/_cards/button-1-base.card.html +23 -26
  34. package/components/_cards/button-2-states.card.html +14 -12
  35. package/components/_cards/button-3-sizes-icons.card.html +20 -19
  36. package/components/_cards/button-4-group.card.html +14 -31
  37. package/components/_cards/canvas-zoom-controls.card.html +1 -1
  38. package/components/_cards/cards-indicators.card.html +1 -1
  39. package/components/_cards/charts-1-sparkline.card.html +4 -4
  40. package/components/_cards/charts-10-gauge.card.html +2 -2
  41. package/components/_cards/charts-11-funnel.card.html +2 -2
  42. package/components/_cards/charts-12-treemap.card.html +2 -2
  43. package/components/_cards/charts-14-radar.card.html +3 -3
  44. package/components/_cards/charts-15-distribution.card.html +2 -2
  45. package/components/_cards/charts-16-pareto.card.html +2 -2
  46. package/components/_cards/charts-17-candlestick.card.html +2 -2
  47. package/components/_cards/charts-18-sankey.card.html +2 -2
  48. package/components/_cards/charts-19-chord.card.html +2 -2
  49. package/components/_cards/charts-2-line.card.html +3 -3
  50. package/components/_cards/charts-20-sunburst.card.html +2 -2
  51. package/components/_cards/charts-21-worldmap.card.html +3 -3
  52. package/components/_cards/charts-22-gantt.card.html +2 -2
  53. package/components/_cards/charts-23-bar3d.card.html +2 -2
  54. package/components/_cards/charts-24-pie3d.card.html +2 -2
  55. package/components/_cards/charts-25-surface3d.card.html +2 -2
  56. package/components/_cards/charts-26-scatter3d.card.html +2 -2
  57. package/components/_cards/charts-27-ribbon3d.card.html +2 -2
  58. package/components/_cards/charts-3-bar.card.html +6 -6
  59. package/components/_cards/charts-4-barlist.card.html +2 -2
  60. package/components/_cards/charts-5-donut.card.html +2 -2
  61. package/components/_cards/charts-6-scatter.card.html +2 -2
  62. package/components/_cards/charts-7-heatmap.card.html +2 -2
  63. package/components/_cards/charts-8-waterfall.card.html +2 -2
  64. package/components/_cards/charts-9-bullet.card.html +3 -3
  65. package/components/_cards/charts-99-fullpage.card.html +1 -1
  66. package/components/_cards/checkbox.card.html +6 -3
  67. package/components/_cards/codeblock.card.html +2 -2
  68. package/components/_cards/combobox.card.html +6 -4
  69. package/components/_cards/context-menu.card.html +12 -5
  70. package/components/_cards/date-picker.card.html +8 -5
  71. package/components/_cards/diffvalue.card.html +2 -2
  72. package/components/_cards/divider.card.html +2 -2
  73. package/components/_cards/drawer.card.html +3 -3
  74. package/components/_cards/dropdown-menu.card.html +2 -2
  75. package/components/_cards/dropzone.card.html +5 -3
  76. package/components/_cards/empty-state.card.html +2 -2
  77. package/components/_cards/filter-bar.card.html +1 -1
  78. package/components/_cards/icon-button.card.html +14 -14
  79. package/components/_cards/icons-0-usage.card.html +88 -0
  80. package/components/_cards/icons-1-core.card.html +4 -4
  81. package/components/_cards/icons-2-feather.card.html +4 -4
  82. package/components/_cards/icons-3-unicons.card.html +3 -3
  83. package/components/_cards/icons-4-datasource.card.html +5 -0
  84. package/components/_cards/input.card.html +5 -5
  85. package/components/_cards/kbd.card.html +1 -1
  86. package/components/_cards/keyvalue.card.html +1 -1
  87. package/components/_cards/listrow.card.html +1 -1
  88. package/components/_cards/loading.card.html +2 -2
  89. package/components/_cards/log-viewer.card.html +2 -2
  90. package/components/_cards/modal.card.html +1 -1
  91. package/components/_cards/multi-select.card.html +6 -4
  92. package/components/_cards/number-stepper.card.html +9 -6
  93. package/components/_cards/pagination.card.html +6 -4
  94. package/components/_cards/people.card.html +2 -2
  95. package/components/_cards/pipeline-node.card.html +8 -8
  96. package/components/_cards/pipeline-palette.card.html +2 -2
  97. package/components/_cards/radio.card.html +12 -7
  98. package/components/_cards/search.card.html +6 -6
  99. package/components/_cards/segmented-control.card.html +19 -12
  100. package/components/_cards/select.card.html +7 -3
  101. package/components/_cards/slider.card.html +2 -2
  102. package/components/_cards/smart-table.card.html +3 -3
  103. package/components/_cards/spreadsheet.card.html +2 -2
  104. package/components/_cards/stepper.card.html +2 -2
  105. package/components/_cards/table.card.html +79 -17
  106. package/components/_cards/tabs.card.html +10 -5
  107. package/components/_cards/tag.card.html +6 -6
  108. package/components/_cards/textarea.card.html +1 -1
  109. package/components/_cards/timeline.card.html +3 -3
  110. package/components/_cards/toast.card.html +7 -5
  111. package/components/_cards/toggles.card.html +14 -9
  112. package/components/_cards/tooltip.card.html +3 -3
  113. package/components/_cards/tree.card.html +2 -2
  114. package/components/_shared/card-kit.css +25 -0
  115. package/components/_shared/card-kit.js +50 -0
  116. package/components/_shared/src-buttons.js +1 -1
  117. package/components/_shared/src-charts.js +1 -1
  118. package/components/_shared/src-data.js +1 -1
  119. package/components/_shared/src-display.js +1 -1
  120. package/components/_shared/src-feedback.js +1 -1
  121. package/components/_shared/src-forms.js +1 -1
  122. package/components/_shared/src-icons.js +1 -1
  123. package/components/_shared/src-navigation.js +1 -1
  124. package/components/_shared/src-tabs.js +1 -1
  125. package/components/_shared/view-source.js +12 -12
  126. package/components/_vue/index.mjs +10 -0
  127. package/components/buttons/ActionChip.d.ts +1 -1
  128. package/components/buttons/Button.d.ts +1 -1
  129. package/components/buttons/Button.jsx +1 -1
  130. package/components/buttons/Button.vue +1 -1
  131. package/components/buttons/IconButton.d.ts +1 -1
  132. package/components/buttons/IconButton.jsx +5 -3
  133. package/components/buttons/IconButton.vue +3 -2
  134. package/components/charts/Bar3D.jsx +1 -1
  135. package/components/charts/Bar3D.vue +2 -2
  136. package/components/charts/BarChart.jsx +3 -3
  137. package/components/charts/BarChart.vue +6 -6
  138. package/components/charts/BarList.jsx +3 -3
  139. package/components/charts/BarList.vue +3 -3
  140. package/components/charts/BoxPlot.vue +2 -2
  141. package/components/charts/BulletChart.jsx +5 -5
  142. package/components/charts/BulletChart.vue +5 -5
  143. package/components/charts/CandlestickChart.vue +3 -3
  144. package/components/charts/ChartKit.jsx +4 -3
  145. package/components/charts/ChartTooltip.vue +1 -1
  146. package/components/charts/ChordChart.jsx +1 -1
  147. package/components/charts/ChordChart.vue +2 -2
  148. package/components/charts/DonutChart.jsx +1 -1
  149. package/components/charts/DonutChart.vue +2 -2
  150. package/components/charts/FunnelChart.jsx +3 -3
  151. package/components/charts/FunnelChart.vue +4 -4
  152. package/components/charts/GanttChart.vue +1 -1
  153. package/components/charts/GaugeChart.jsx +2 -2
  154. package/components/charts/GaugeChart.vue +2 -2
  155. package/components/charts/HeatmapChart.jsx +1 -1
  156. package/components/charts/HeatmapChart.vue +1 -1
  157. package/components/charts/Histogram.jsx +2 -2
  158. package/components/charts/Histogram.vue +4 -4
  159. package/components/charts/LineChart.vue +2 -2
  160. package/components/charts/ParetoChart.jsx +1 -1
  161. package/components/charts/ParetoChart.vue +3 -3
  162. package/components/charts/Pie3D.jsx +1 -1
  163. package/components/charts/Pie3D.vue +2 -2
  164. package/components/charts/PlotGrid.vue +1 -1
  165. package/components/charts/RadarChart.vue +1 -1
  166. package/components/charts/Ribbon3D.jsx +1 -1
  167. package/components/charts/Ribbon3D.vue +2 -2
  168. package/components/charts/SankeyChart.jsx +1 -1
  169. package/components/charts/SankeyChart.vue +2 -2
  170. package/components/charts/Scatter3D.vue +1 -1
  171. package/components/charts/ScatterChart.jsx +1 -1
  172. package/components/charts/ScatterChart.vue +3 -3
  173. package/components/charts/Sparkline.jsx +1 -1
  174. package/components/charts/Sparkline.vue +1 -1
  175. package/components/charts/SunburstChart.vue +1 -1
  176. package/components/charts/Surface3D.jsx +1 -1
  177. package/components/charts/Surface3D.vue +2 -2
  178. package/components/charts/TreemapChart.jsx +1 -1
  179. package/components/charts/TreemapChart.vue +2 -2
  180. package/components/charts/WaterfallChart.jsx +1 -1
  181. package/components/charts/WaterfallChart.vue +5 -4
  182. package/components/charts/WorldMap.jsx +4 -4
  183. package/components/charts/WorldMap.vue +5 -5
  184. package/components/data/DiffValue.d.ts +1 -0
  185. package/components/data/DiffValue.jsx +1 -1
  186. package/components/data/DiffValue.vue +1 -1
  187. package/components/data/KeyValue.d.ts +1 -1
  188. package/components/data/KeyValue.jsx +2 -2
  189. package/components/data/KeyValue.vue +2 -2
  190. package/components/data/Pagination.jsx +2 -2
  191. package/components/data/Pagination.vue +1 -1
  192. package/components/data/SmartTable.jsx +5 -5
  193. package/components/data/SmartTable.vue +6 -6
  194. package/components/data/Spreadsheet.jsx +5 -5
  195. package/components/data/Spreadsheet.vue +6 -6
  196. package/components/data/Table.d.ts +58 -4
  197. package/components/data/Table.jsx +153 -15
  198. package/components/data/Table.vue +105 -15
  199. package/components/data/data.prompt.md +1 -1
  200. package/components/display/Avatar.jsx +2 -2
  201. package/components/display/Avatar.vue +1 -1
  202. package/components/display/AvatarGroup.vue +1 -1
  203. package/components/display/Badge.d.ts +4 -1
  204. package/components/display/Badge.jsx +10 -5
  205. package/components/display/IconTile.vue +9 -4
  206. package/components/display/Kbd.d.ts +1 -1
  207. package/components/display/Kbd.jsx +1 -1
  208. package/components/display/Kbd.vue +1 -1
  209. package/components/feedback/ActivityItem.jsx +1 -1
  210. package/components/feedback/ContextMenu.d.ts +3 -2
  211. package/components/feedback/ContextMenu.jsx +8 -4
  212. package/components/feedback/ContextMenu.vue +9 -6
  213. package/components/feedback/Menu.d.ts +1 -1
  214. package/components/feedback/Modal.jsx +1 -1
  215. package/components/feedback/Modal.vue +1 -1
  216. package/components/feedback/Timeline.vue +2 -2
  217. package/components/feedback/feedback.prompt.md +1 -1
  218. package/components/forms/Combobox.d.ts +1 -1
  219. package/components/forms/DatePicker.d.ts +1 -1
  220. package/components/forms/Input.d.ts +1 -1
  221. package/components/forms/Input.jsx +2 -2
  222. package/components/forms/Input.vue +1 -1
  223. package/components/forms/MultiSelect.d.ts +1 -1
  224. package/components/forms/NumberStepper.d.ts +1 -1
  225. package/components/forms/SearchInput.d.ts +1 -1
  226. package/components/forms/Select.d.ts +1 -1
  227. package/components/forms/Select.jsx +1 -1
  228. package/components/forms/Select.vue +1 -1
  229. package/components/forms/Slider.jsx +1 -1
  230. package/components/forms/Slider.vue +1 -1
  231. package/components/forms/Switch.jsx +3 -3
  232. package/components/forms/Switch.vue +11 -8
  233. package/components/forms/Textarea.vue +1 -1
  234. package/components/forms/input-base.js +1 -1
  235. package/components/icons/Icon.jsx +17 -1
  236. package/components/icons/Icon.prompt.md +2 -0
  237. package/components/icons/Icon.vue +1 -1
  238. package/components/icons/icon-paths.js +15 -0
  239. package/components/index.d.ts +1 -0
  240. package/components/index.js +5 -4
  241. package/components/navigation/Breadcrumb.jsx +3 -7
  242. package/components/navigation/Breadcrumb.vue +2 -8
  243. package/components/navigation/SidePanel.d.ts +22 -0
  244. package/components/navigation/SidePanel.jsx +23 -0
  245. package/components/navigation/SidePanel.vue +21 -0
  246. package/components/navigation/Sidebar.d.ts +23 -7
  247. package/components/navigation/Sidebar.jsx +38 -56
  248. package/components/navigation/Sidebar.vue +40 -44
  249. package/components/navigation/TopBar.d.ts +28 -3
  250. package/components/navigation/TopBar.jsx +54 -7
  251. package/components/navigation/TopBar.vue +26 -8
  252. package/components/navigation/Tree.jsx +1 -1
  253. package/components/navigation/Tree.vue +9 -4
  254. package/components/navigation/UserMenu.vue +27 -0
  255. package/components/navigation/chrome-tones.js +22 -0
  256. package/components/navigation/nav-model.js +26 -0
  257. package/components/navigation/navigation.prompt.md +2 -0
  258. package/components/navigation/theme-store.js +9 -0
  259. package/components/tabs/CountBadge.vue +12 -0
  260. package/components/tabs/PanelTabs.vue +7 -3
  261. package/components/tabs/PillTabs.vue +8 -4
  262. package/components/tabs/SegmentedControl.d.ts +5 -3
  263. package/components/tabs/SegmentedControl.jsx +6 -4
  264. package/components/tabs/SegmentedControl.vue +4 -3
  265. package/components/tabs/Tabs.d.ts +14 -4
  266. package/components/tabs/Tabs.jsx +35 -20
  267. package/components/tabs/Tabs.vue +7 -3
  268. package/components/tabs/ViewToggle.d.ts +1 -1
  269. package/components/tabs/tabs.prompt.md +2 -2
  270. package/package.json +2 -2
  271. package/readme.md +10 -9
  272. package/readme.zh-CN.md +8 -7
  273. package/tokens/alpha.css +3 -1
  274. package/tokens/colors.css +1 -1
  275. package/tokens/dark.css +1 -1
  276. package/tokens/layout.css +8 -5
  277. package/tokens/tokens.d.ts +24 -0
  278. package/tokens/tokens.js +42 -6
  279. package/tokens/tokens.json +97 -11
  280. package/tokens/typography.css +26 -9
package/DEPLOY.md CHANGED
@@ -55,11 +55,11 @@ deploys the documentation site. Watch it under *Build → Pipelines*.
55
55
  **5. Cut the first release.**
56
56
 
57
57
  ```bash
58
- git tag v2.1.1 && git push --tags
58
+ git tag v2.4.0 && git push --tags
59
59
  ```
60
60
 
61
61
  That tag runs `generated:check` → `version:check` → `npm publish`. Confirm under *Deploy →
62
- Package Registry*: `@keyfunc/keybricks-ds` 2.1.1.
62
+ Package Registry*: `@keyfunc/keybricks-ds` 2.4.0.
63
63
 
64
64
  **6. Hand developers two things:** the Pages URL, and the `.npmrc` snippet in §4 below.
65
65
 
@@ -96,7 +96,7 @@ Published (`files` in `package.json`): `components/`, `tokens/`, `assets/`, `_sc
96
96
  > that mode — Vue apps on a git dependency should deep-import
97
97
  > `@keyfunc/keybricks-ds/components/<group>/<Name>.vue`, which is the recommended path anyway.
98
98
 
99
- Not published: `guidelines/`, `ui_kits/`, `templates/`, `index.html`, `gallery.html`,
99
+ Not published: `guidelines/`, `index.html`, `gallery.html`,
100
100
  `_ds_bundle.js`. Those are the documentation site — they go to Pages, not into every
101
101
  `node_modules`.
102
102
 
@@ -112,7 +112,7 @@ import tokens from '@keyfunc/keybricks-ds/tokens.json' // cross-
112
112
  ```
113
113
 
114
114
  Deep imports are the better default in Vue and in any app that cares about tree-shaking —
115
- a barrel of 122 exports asks the bundler to prove each one is unused.
115
+ a barrel of 129 exports asks the bundler to prove each one is unused.
116
116
 
117
117
  ## 3. Publishing (maintainers)
118
118
 
@@ -130,6 +130,12 @@ git push && git push --tags
130
130
  `.gitlab-ci.yml` then runs: `generated:check` → `version:check` (tag must equal
131
131
  `package.json` version) → `npm publish` → `pages`.
132
132
 
133
+ **Changelog.** Every release gets an entry at the top of `changelog.js` (version, ISO date, and
134
+ items tagged `new` / `improved` / `fixed` / `breaking` / `removed`, each in English, Chinese and
135
+ Japanese). The documentation site renders it as the *Changelog* section under Overview. While a
136
+ version is still being built its entry carries `status: "unreleased"`; on release, drop the status
137
+ and set the date. Migration details stay in `INTEGRATION.md`; the changelog is the short summary.
138
+
133
139
  **Versioning policy.** A token's *value* changing is a minor; a token being *renamed or
134
140
  removed* is a major, because consumer code references `var(--name)` directly. Adding a
135
141
  component or a prop is a minor. Changing a component's default appearance is a major —
@@ -156,7 +162,7 @@ GitLab injects `CI_JOB_TOKEN` — use that instead and no secret is stored anywh
156
162
  **Install — straight from git** (no registry, no publish; works today)
157
163
 
158
164
  ```json
159
- "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.1.1"
165
+ "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.4.0"
160
166
  ```
161
167
 
162
168
  Because the package has no build step, a git dependency needs no `prepare` script — npm
@@ -202,3 +208,12 @@ consuming app to fail CI on the two rules that break theming:
202
208
 
203
209
  Both are the same rule stated twice: components read the semantic layer, and only the
204
210
  semantic layer. That is what makes dark mode cost nothing.
211
+
212
+ ## Runtime checks
213
+
214
+ `_tests/` holds browser pages that exercise the real components: `react-runtime.html` (the compiled
215
+ bundle), `table-selection.html` (Table loaded from source: checkbox spacing at every width, code chips, two-line rows, sorting), `vue-runtime.html` (the `.vue` files, loaded with vue3-sfc-loader), `cards-interaction*.html`
216
+ (clicks through the documentation demos) and `icon-rules.html` (the Keybricks glyphs against the drawing rules). Serve the repo root (`npx serve .`), open a page and read the
217
+ console — every line starts with PASS or FAIL. Run them after changing a component in either framework.
218
+ `measure-cards.html` is a tool, not a test: it measures each documentation page at its card width so the
219
+ `viewport` sizes in the cards, `site-nav.js` and `gallery.html` can be kept in step.
package/DESIGN.md CHANGED
@@ -84,7 +84,7 @@ Never put `--success` (the solid) behind text — use the `-bg` / `-text` pair.
84
84
  Series walk `--series-1…10` in order; signed values are ALWAYS `--chart-pos` / `--chart-neg`
85
85
  (diverging bars, waterfall bridges, deltas, auto sparklines); totals and combo overlay lines are
86
86
  `--chart-total`; guides are dashed `--chart-guide`. Lines are straight or monotone-cubic — never
87
- a spline that overshoots a real value. Numbers are `--font-mono`, compact-formatted. Every chart
87
+ a spline that overshoots a real value. Numbers are `--font-sans` with tabular figures, compact-formatted. Every chart
88
88
  answers a hover at every size: a tile-tier chart drops its axes and legend, never its tooltip.
89
89
  Geography is data, not a drawing — country outlines come from Natural Earth via d3-geo.
90
90
  3D charts are presentation, not analysis: plain SVG painter’s-algorithm rendering, one upper-left
@@ -99,7 +99,7 @@ feedback colors mean **severity**. Do not mix the two vocabularies.
99
99
 
100
100
  ## Typography
101
101
 
102
- `--font-sans` is Inter. `--font-mono` is Menlo. There is no third family. Under
102
+ `--font-sans` is Inter. `--font-mono` is Menlo, and it is for code only: code blocks, logs, inline code in the docs, and config codes (`FIN_CURRENCY_DEFAULT`), which render as a code chip — Menlo at `--text-code` (12px; 11px in sm; Latin, so not bumped in CJK) on `--bg-inset` with a hairline border (`code: true` on a Table column). Everything else in the interface — IDs, amounts, chart numbers, keyboard keys — is `--font-sans`; numbers that must line up add `font-variant-numeric: tabular-nums`. There is no third family. Under
103
103
  `lang="zh" | "ja" | "ko"` the sans stack continues into the system CJK face (PingFang SC /
104
104
  Hiragino / Apple SD Gothic Neo on macOS, Microsoft YaHei / Yu Gothic UI / Malgun Gothic on
105
105
  Windows, Noto Sans CJK elsewhere); Latin glyphs stay Inter.
@@ -138,19 +138,144 @@ and menu row is the tier's control text; a `Badge` or `Tag` is its own small obj
138
138
  exception. In content, a secondary annotation (a timestamp beside a name, a count beside a label)
139
139
  may be `--text-xs`. Never put a 14px label and a 12px control on the same baseline.
140
140
 
141
+ ### Count badges on tabs and segments
142
+
143
+ A `Tabs`, `PanelTabs` or `PillTabs` tab, or a `SegmentedControl` option, may carry `count` (`{ label: "Submission", count: 3 }`).
144
+ It renders 6px right of the label as a small full-radius badge: `--count-h` tall (sm 16 · md 18 · lg 20),
145
+ 6px sides, **12px tabular figures in the UI font** (digits are Latin, so the size is not bumped in CJK).
146
+ The fill is the alpha wash `--neutral-alpha-8` — it darkens whatever it sits on by the same step, so the
147
+ badge reads on a white tab, on the #f5f5f5 active pill and in dark mode alike (a solid `--bg-hover` vanished on
148
+ the active pill). Selected is told from unselected by the text alone: `--text-heading` vs `--text-body` —
149
+ never `--text-secondary`, which fails 4.5:1 on a grey fill at 12px. Under the blue active underline tab the
150
+ badge stays neutral, so the blue is only the tab's own label and line. A count of 0 or none draws nothing; `showZero` (on the control, or per option) draws a muted
151
+ 0 so a filter set keeps its shape. The selected value is still matched by label — a count is decoration,
152
+ never identity. Counts never appear in `iconOnly` segments.
153
+
154
+ ### App chrome
155
+
156
+ The shell is `Sidebar` + optional `SidePanel` + `TopBar`, all 56px at the top edge. The rail is 240px (64px
157
+ collapsed), with a 56px brand head without a rule, a 2px-gap list of 36px items and a pinned footer
158
+ (Management, Knowledge Base) above a version line. Items that open a panel (`trailing: true`) carry a
159
+ 14px chevron; while a panel is open the rail collapses to its 64px icon form and the panel docks beside
160
+ it at 240px, in the **same tone**. Tones: `recessed` (default — grey rail, the active item is a white tile
161
+ with a hairline ring), `flush` (white rail), `contrast` (rail scoped to the dark theme) and `custom`
162
+ (dark scope on one of ten `SIDEBAR_COLORS`). Pick one tone per product and pass it to both
163
+ `Sidebar` and `SidePanel`. The top bar holds the bare search on the left and, on the right, the dark
164
+ AI Assistant button, notifications, help and the user trigger, which opens `UserMenu` (identity,
165
+ appearance switch, rows).
166
+
167
+ ### Menus: action vs single choice
168
+
169
+ `ContextMenu` and `Menu` serve two kinds of list, and the row spacing says which one it is.
170
+
171
+ - **Action menu** (Edit · Duplicate · Delete): no item is selected. Rows are flush (`gap: 0`); only the
172
+ hovered row is filled.
173
+ - **Single-choice menu** (section switcher, language picker): pass `selected: true` on the current item. It
174
+ gets a `--bg-hover` fill and `--weight-medium` `--text-heading` — **no checkmark**, the fill is the
175
+ mark. Rows are announced as `menuitemradio` with `aria-checked`. As soon as any item is selected the
176
+ rows are spaced **2px apart** (`gap: 2px`), the same rhythm as `Sidebar`, `Tree` and `DocTree`, so a
177
+ hovered row's fill never runs into the selected row's fill.
178
+
179
+ Dividers keep their 4px top and bottom margin in both kinds, independent of the row gap. Don't mix the
180
+ two: a menu that both switches state and runs actions puts the actions after a divider, and the choice
181
+ rows still carry `selected`.
182
+
141
183
  ### Table headers
142
184
 
143
185
  A header cell is the **same size as its data cells**, weight 600, `--text-secondary`, sentence
144
186
  case, no letter-spacing. The header is set apart by `--bg-table-header`, never by caps or a
145
- heavier rule. Mono columns (`mono: true`) keep the row's size in `--font-mono` with tabular
146
- figures — codes and amounts are never a point smaller than the words beside them.
187
+ heavier rule. Amount and ID columns (`mono: true`) keep the row's size, font and colour and add
188
+ only tabular figures; config-code columns (`code: true`) use the code chip — codes and amounts are never a point smaller than the words beside them.
189
+
190
+ ### Sortable headers
191
+
192
+ Mark a column `sortable: true` and its header gets a sort button: a muted sm `IconButton` at the
193
+ **right end of the header cell** — the same edge as a two-line row's `⋯`, so the two line up. The label
194
+ keeps its alignment (left, or right for number columns, where it sits 4px before the button).
195
+
196
+ - **Unsorted** — the button appears only while the header is hovered (or holds keyboard focus), icon
197
+ `arrow-up`. It keeps its space while hidden, so the label never shifts.
198
+ - **Click** cycles ascending (`arrow-up`) → descending (`arrow-down`) → unsorted. The tooltip names the
199
+ next step: *Sort ascending* · *Sort descending* · *Clear sorting*.
200
+ - **Sorted** — the button stays without hover and the label turns `--text-heading`; the header carries
201
+ `aria-sort`.
202
+ - **One column at a time.** Clicking another column's button starts it at ascending and clears the first.
203
+ - A long label truncates; the button never shrinks. With `resizable` the button sits inside the cell
204
+ padding, left of the divider, so the two never overlap.
205
+ - Action columns (row ⋯, checkboxes) are never `sortable`, so they show no button.
206
+
207
+ API: `sort` / `onSortChange` control it (`{ key, direction: "asc" | "desc" }` or `null`; Vue
208
+ `v-model:sort`, `@sort-change`); `defaultSort` seeds it uncontrolled. The table reorders rows itself —
209
+ numbers (commas allowed) numerically, text by locale with numeric collation, empty values last — unless
210
+ the column passes `compare(a, b, rowA, rowB)` or the table sets `manualSort` (rows arrive sorted from
211
+ the server). Selection indices and `onRowMore` always refer to the original `rows` order.
212
+
213
+ ### Two-line name rows
214
+
215
+ The name column of a document list (folders, models, sheets) is a **two-line title cell**:
216
+ `columns: [{ key: "name", label: "Name", width: 300, twoLine: true }, …]`. Left to right:
217
+
218
+ 1. an `IconTile kind="row"` tinted by the row's `hue` (`source` · `join` · `transform` · `merge` ·
219
+ `output`; `neutral` is the grey tile for folders and containers);
220
+ 2. two lines of text — the **title** in the tier's control text, `--text-heading`, regular weight, and the
221
+ **description** in `--text-xs`, `--text-secondary`. Each is one line and truncates with an ellipsis. Give the column a `width`; in a tight table it
222
+ shrinks to `minWidth` (default 180px) before the other columns give way;
223
+ 3. an sm `⋯` `IconButton` on the right (`onRowMore(row, index, event)`; Vue `@row-more`; `more: false` hides it).
224
+
225
+ An optional 14px **mark** sits right after the title: `mark: "favorite"` is a filled star in `--warning`;
226
+ `{ icon, color, label }` draws any 14px outline icon. Fields default to the row keys `icon`, `hue`,
227
+ `description`, `mark`; pass `twoLine: { icon, hue, description, mark }` with field names or
228
+ `(row, index) => value` accessors to read them from elsewhere.
229
+
230
+ The header stays the tier's bar height; only body rows grow. Every other cell stays vertically centred
231
+ and unchanged. All measures are `--title-cell-*` tier tokens:
232
+
233
+ | | sm | md | lg |
234
+ | --- | --- | --- | --- |
235
+ | Icon tile (`--title-cell-tile`, `-tile-r`) | 28 · r8 | **32 · r8** | 40 · r10 |
236
+ | Icon in the tile (`--title-cell-icon`) | 14 | 16 | 20 |
237
+ | Tile → text (`--title-cell-tile-gap`) | 8 | 12 | 12 |
238
+ | Title | 12 / 16 (13 / 18 CJK) | 14 / 20 | 14 / 20 |
239
+ | Description | 12 / 16 (13 / 18 CJK) | 12 / 16 (13 / 18 CJK) | 12 / 16 (13 / 18 CJK) |
240
+ | Title → description (`--title-cell-gap`) | 2 | 2 | 4 |
241
+ | Row padding top and bottom (`--title-cell-py`) | 8 | 10 | 14 |
242
+ | **Row height** (Latin / CJK) | **50 / 54** | **58 / 60** | **68 / 70** |
243
+ | Header | 36 | 40 | 48 |
244
+ | `⋯` button | sm 28 | sm 28 | sm 28 |
245
+
246
+ **Opening a row.** Pass `onRowOpen(row, index, event)` (Vue `@row-open`) and the icon tile and the title open
247
+ the row: both get the hand cursor, and the title is a keyboard target (Enter / Space). The ⋯ button and the
248
+ expand arrow never open the row. Without the callback nothing in the cell looks clickable.
249
+
250
+ **Tree rows.** Set `tree` on the table and nest rows through `children` — or set `hasChildren: true` on a
251
+ row whose children you load when it opens. The two-line column then indents **24px per level** and reserves a
252
+ **20px arrow slot + 4px** before the tile, so a child's arrow sits exactly under its parent's tile and leaf
253
+ rows line up with folders. The arrow is a muted `chevron-right` (tier icon size) that turns down when
254
+ open, with the `--overlay-hover` wash on hover; rows carry `aria-level` and `aria-expanded`. Expansion
255
+ is `expandedKeys` / `onExpandChange(row, expanded, keys)` (Vue `v-model:expandedKeys`, `@expand-change`),
256
+ or `defaultExpandedKeys` uncontrolled; `rowKey` names the key field (default `id`). Sorting reorders
257
+ siblings only — children stay under their parent. Every index the table reports (selection, `onRowMore`,
258
+ `onRowOpen`) is the row's depth-first position over all rows, expanded or not, so it never moves when the
259
+ user sorts or expands; for a flat table that is simply its position in `rows`.
260
+
261
+ **Labels.** The table draws six words itself — the sort tooltips, ⋯, and the arrow's expand / collapse.
262
+ `labels: { sortAsc, sortDesc, sortClear, more, expand, collapse }` translates them; missing keys fall
263
+ back to English. Pass them in the product's language — a Chinese table with English tooltips is a bug.
264
+
265
+ In sm the title and description are the same size, so the description is told apart by colour alone —
266
+ use sm two-line rows only where the list is dense and short labels are expected.
147
267
 
148
268
  ### Chinese, Japanese and Korean
149
269
 
150
270
  Han, kana and Hangul have no capitals and no italics, so emphasis is weight. Under
151
- `:lang(zh|ja|ko)` the tokens change for you: `--weight-medium` becomes **600** (Microsoft
152
- YaHei, Meiryo, Yu Gothic UI and Malgun Gothic ship no 500 face, so 500 silently renders as
153
- Regular on Windows) and every `--tracking-*` is **0**. CJK text is never smaller than the Latin
271
+ `:lang(zh|ja|ko)` the tokens change for you: `--weight-medium` and `--weight-semibold` both become
272
+ **500** — square glyphs carry more strokes, so PingFang 600 next to Inter 500 reads a full step bolder —
273
+ and every `--tracking-*` is **0**. (Microsoft YaHei, Meiryo, Yu Gothic UI and Malgun Gothic ship no 500
274
+ face, so on Windows these render Regular; size, colour and the header fill keep the hierarchy.) Below 14px CJK is one step larger than
275
+ Latin — `--text-xs` 13px (leading 18) and `--text-2xs` 12px — so no square glyph renders under
276
+ 12px; chart numerals read `--text-2xs-mono` and stay 11px. Text sized from geometry (switch inside text, avatar initials) is floored at `--text-glyph-min`: 11px, 12px in CJK. Inside an sm region `--weight-medium`
277
+ is 400 for CJK, because bold strokes merge at 13px. Simplified and Traditional Chinese, Japanese
278
+ and Korean get the same rule. CJK text is never smaller than the Latin
154
279
  text beside it, never letter-spaced and never transformed; a CJK table header or section label
155
280
  is emphasised by weight alone. Set `lang` on `<html>`, or on the region when one panel switches
156
281
  language — every component re-reads `--font-sans`, so a per-region switch works.
@@ -175,18 +300,19 @@ so two controls that share a row can never disagree. `md` is the default on `:ro
175
300
 
176
301
  | Token | sm | md | lg | Used by |
177
302
  | --- | --- | --- | --- | --- |
178
- | `--control-h` | 24 | **32** | 36 | buttons, inputs, selects, search, steppers, segmented controls, chips, pagination items, menu rows |
179
- | `--control-text` | 12 | **14** | 14 | text in controls and their labels, table cells |
303
+ | `--control-h` | 28 | **32** | 40 | buttons, inputs, selects, search, steppers, segmented controls, chips, pagination items, menu rows |
304
+ | `--control-text` | 12 (13 CJK) | **14** | 14 | text in controls and their labels, table cells |
180
305
  | `--control-icon` | 14 | 16 | 16 | icon inside a control |
181
306
  | `--control-px` | 8 | 12 | 16 | horizontal padding of a text control or button |
182
307
  | `--control-gap` | 8 | 8 | 8 | inside one group: label → its control, button → button |
183
308
  | `--group-gap` | 12 | 16 | 24 | between groups in one bar: field → next field |
184
- | `--bar-h` | 32 | 40 | 44 | toolbar, filter bar, tab bar, table row, list row |
185
- | `--bar-card-h` | 40 | 48 | 52 | a bar inside a bordered card (table toolbar, pagination) |
309
+ | `--bar-h` | 36 | 40 | 48 | toolbar, filter bar, tab bar, table row, list row |
310
+ | `--bar-card-h` | 44 | 48 | 56 | a bar inside a bordered card (table toolbar, pagination) |
186
311
  | `--edge-pad` | 12 | 16 | 16 | card edge → first control or cell |
187
312
  | `--cell-px` | 8 | 12 | 16 | horizontal padding of a table cell |
188
313
  | `--check-size` | 14 | 16 | 16 | checkbox and radio box |
189
314
  | `--tag-h` | 20 | 24 | 28 | `Tag` |
315
+ | `--count-h` | 16 | 18 | 20 | count badge beside a segment / pill label |
190
316
  | `--switch-w` × `--switch-h` | 28 × 16 | 36 × 20 | 44 × 24 | `Switch` track |
191
317
 
192
318
  Where each tier belongs:
@@ -198,18 +324,18 @@ Where each tier belongs:
198
324
 
199
325
  Rules:
200
326
 
201
- - **One tier per row.** Never a 24px icon button beside a 32px input.
327
+ - **One tier per row.** Never a 28px icon button beside a 32px input.
202
328
  - **Nothing interactive is smaller than 24px.** The former `xs` sizes and `dense` props map to `sm`.
203
329
  - A per-control `size` prop only stamps `data-size` on that control. Use it for a control that
204
330
  stands alone in its band — never to "fix" one control inside a bar.
205
331
  - Text inside a control is `--control-text`, not `--text-xs` because it looks tidier.
206
- - `--h-button` and `--h-input` are aliases of `--control-h`; `--h-button-sm` is 24px. Prefer the
332
+ - `--h-button` and `--h-input` are aliases of `--control-h`; `--h-button-sm` is 28px. Prefer the
207
333
  tier tokens in new code.
208
334
 
209
335
  ### Button emphasis — pick the variant, never the size
210
336
 
211
337
  The tier says how dense a region is; the **variant** says how important an action is. Never
212
- shrink a button to make it feel lighter: a 24px button beside 32px controls and 14px text reads
338
+ shrink a button to make it feel lighter: a 28px button beside 32px controls and 14px text reads
213
339
  as a mistake on a calm page, and the tier rule above forbids it anyway. Reach for a quieter
214
340
  variant instead.
215
341
 
@@ -267,7 +393,9 @@ Nothing bounces. Nothing slides more than a few pixels. Keyframes available:
267
393
 
268
394
  - **Hover** — every pointer target answers it, one step at a time:
269
395
  filled and boxed buttons, menu rows, list rows, nav and tree items, segments → one surface step
270
- (`--bg-hover`, `--action-primary-hover`, `--soft-hover`); field boxes (inputs, selects, date,
396
+ (`--bg-hover`, `--action-primary-hover`, `--soft-hover`); a borderless `IconButton` → the alpha
397
+ overlay `--overlay-hover` (press `--overlay-press`), because it sits on white rows, grey table headers
398
+ and grey bars alike and a solid `--bg-hover` disappears on `--bg-table-header`; field boxes (inputs, selects, date,
271
399
  combobox, multi-select, search, stepper) → border `--border-control` to `--border-strong`;
272
400
  text-only controls (inactive tabs, legend items, clear ×, copy) → ink to `--text-heading`;
273
401
  table body rows → `--bg-inset`; checkbox and radio rings → `--text-muted`; switch tracks →
@@ -320,22 +448,22 @@ The list that prevents the most rework. These are absolute.
320
448
  - **Do not mix size tiers in one row.** The region declares `data-size`; the controls inherit. A
321
449
  `size` prop on one control inside a bar is a bug, not a fix.
322
450
  - **Do not shrink, letter-space or uppercase Chinese, Japanese or Korean text.** Under `lang`
323
- the emphasis weight is 600 and tracking is 0 — that is the whole CJK rule.
451
+ the emphasis and heading weight is 500 (medium 400 at sm), tracking is 0, and sizes under 14px step up by one — that is the whole CJK rule.
324
452
  - **Do not put dark text on a saturated fill.** `--on-accent` (white) is the only option,
325
453
  in both themes — this is why the dark-mode primary button keeps white text.
326
454
  - **Do not scale or shift elements on press.** Press is a color step only.
327
455
  - **Do not show a drop indicator where the drop is impossible.** No half-row boxes on a
328
456
  container, no insert rules on a node that can't take children.
329
457
  - **Do not build a new primitive when one exists.** Check the component index in
330
- `INTEGRATION.md` first — there are 117.
331
- - **Do not use emoji as icons.** Use `<Icon name="..." />` (362 glyphs) or `<Unicon>` (1,206).
458
+ `INTEGRATION.md` first — there are 120.
459
+ - **Do not use emoji as icons.** Use `<Icon name="..." />` (330 glyphs) or `<Unicon>` (1,206).
332
460
  - **Do not invent new component variants.** If `Button` lacks the variant you want, that is a
333
461
  design-system request, not a local override.
334
462
  - **Do not stack two primary buttons.** One primary action per view; everything else is
335
463
  `outline`, `ghost`, or `text`.
336
464
  - **Do not use full-uppercase text.** Table headers and section labels are sentence case, weight
337
- 600, tracking 0 — the same size as the text they label. (The 10px eyebrows in this site's own
338
- card chrome are documentation furniture, not a component pattern.)
465
+ 600, tracking 0 — the same size as the text they label. (This site's own card labels follow the
466
+ same rule: 12px, sentence case.)
339
467
  - **Do not animate anything longer than 360ms** or with a bounce/elastic easing.
340
468
 
341
469
  ---
package/INTEGRATION.md CHANGED
@@ -31,7 +31,7 @@ Not using a registry yet? A git dependency works with no publishing at all — t
31
31
  has no build step, so npm can use the checkout as-is:
32
32
 
33
33
  ```json
34
- "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.1.1"
34
+ "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.4.0"
35
35
  ```
36
36
 
37
37
  **Source-only package.** `.jsx` and `.vue` files are published as authored, so your
@@ -98,7 +98,7 @@ import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
98
98
  ```
99
99
 
100
100
  That is the whole integration. The `data-size="lg"` on the form is the size tier — every control
101
- inside it is 36px tall; leave it off and they are the app default, 32px (see *Size tiers* below).
101
+ inside it is 40px tall; leave it off and they are the app default, 32px (see *Size tiers* below).
102
102
  Everything below is reference material.
103
103
 
104
104
  ---
@@ -136,9 +136,9 @@ properties — `--control-h`, `--control-text`, `--control-icon`, `--control-px`
136
136
  A **region** sets them with one attribute:
137
137
 
138
138
  ```html
139
- <div data-size="sm">…</div> <!-- 24px controls · 12px text · 32px rows — dense grids, pipeline nodes -->
139
+ <div data-size="sm">…</div> <!-- 28px controls · 12px text (13px CJK) · 36px rows — dense grids, pipeline nodes -->
140
140
  <div data-size="md">…</div> <!-- 32px controls · 14px text · 40px rows — the app default (:root) -->
141
- <div data-size="lg">…</div> <!-- 36px controls · 14px text · 44px rows — dialogs, short forms -->
141
+ <div data-size="lg">…</div> <!-- 40px controls · 14px text · 48px rows — dialogs, short forms -->
142
142
  ```
143
143
 
144
144
  Put `data-size` on the toolbar, filter bar, form, table or panel and leave the controls' `size`
@@ -162,7 +162,7 @@ Text, weight and tracking follow the tier through `--control-text` / `--control-
162
162
  weight becomes 600 and all tracking is 0 — nothing to configure. `DESIGN.md` has the full token
163
163
  table and the rules behind it.
164
164
 
165
- ## Component index (117 components)
165
+ ## Component index (120 components)
166
166
  Import path is `@keyfunc/keybricks-ds/components/<group>/<Name>.jsx` (React) or `.vue` (Vue 3).
167
167
  Every component has a sibling `.d.ts` with its full props contract, and each group has a
168
168
  `.prompt.md` with usage notes.
@@ -180,8 +180,11 @@ components (`Input.jsx` exports `Input` and `Textarea`; `Badge.jsx` exports `Bad
180
180
  cannot export values, so on the Vue side every such secondary is its own file with a default
181
181
  export — `Textarea.vue`, `IconTile.vue`, `StatusBadge.vue`, `Tooltip.vue`, `ToastStack.vue`, `Port.vue`, `PortLabel.vue`, `ChartLegend.vue`, `ChartTooltip.vue`, `PlotGrid.vue`, `XLabels.vue`, `ButtonGroup.vue`, `StatCard.vue`, `Toast.vue`,
182
182
  `Spinner.vue`, `PageHeading.vue`, and so on — always named exactly as the React export.
183
- Shared non-component values live in plain modules: `forms/input-base.js` (`inputBase`),
184
- `pipeline/pipeline-catalog.js` (`PIPELINE_CATALOG`), `pipeline/port-skin.js` (`portSkin`), `px.js` (`px`), `icons/icon-paths.js`.
183
+ Shared non-component values live in plain modules: `navigation/nav-model.js` (`KEYBRICKS_NAV`),
184
+ `navigation/theme-store.js` (`applyStoredTheme`), `pipeline/pipeline-catalog.js` (`PIPELINE_CATALOG`),
185
+ `icons/icon-paths.js`, `icons/feather-paths.js` — all five are also exported from
186
+ `@keyfunc/keybricks-ds/vue` — plus the internal helpers `forms/input-base.js` (`inputBase`),
187
+ `pipeline/port-skin.js` (`portSkin`) and `px.js` (`px`).
185
188
 
186
189
  ```js
187
190
  // React
@@ -235,7 +238,9 @@ import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
235
238
  | Component | What it's for |
236
239
  | --- | --- |
237
240
  | `Sidebar` | The app's primary nav: collapsible sections, active state, footer items. `KEYBRICKS_NAV` is the product's real nav tree. |
241
+ | `SidePanel` | 240px panel docked beside the sidebar (Documents, Management), in the rail's tone. |
238
242
  | `TopBar` | Global header — search, notifications, theme toggle, avatar. |
243
+ | `UserMenu` | Account menu from the top bar's user trigger: identity, appearance switch, rows. |
239
244
  | `PageHeading` | Page title with optional subtitle and right-aligned actions. |
240
245
  | `PageToolbar` | Secondary bar under the heading: filters, view toggles, bulk actions. |
241
246
  | `Breadcrumb` | Path trail; collapses to an ellipsis dropdown past `maxItems`. |
@@ -246,9 +251,10 @@ import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
246
251
  ### `tabs/` — switching views
247
252
  | Component | What it's for |
248
253
  | --- | --- |
249
- | `Tabs` | Page-level underline tabs. |
250
- | `PanelTabs` | Compact tabs inside a detail panel or drawer. |
251
- | `PillTabs` | Filter/status tabs as pills. |
254
+ | `Tabs` | Page-level underline tabs; `{ label, count }` adds a count badge. |
255
+ | `PanelTabs` | Compact tabs inside a detail panel or drawer; `{ label, count }` adds a count badge. |
256
+ | `PillTabs` | Filter/status tabs as pills; `{ label, count }` adds a count badge. |
257
+ | `CountBadge` | The count badge beside a segment / pill label (`--count-h`, 12px tabular figures); used by `SegmentedControl` and `PillTabs`, exported for custom filter bars. |
252
258
  | `SegmentedControl` | Switches views of the same data, applies instantly — not a saved form value (`RadioGroup`) and not page navigation (`Tabs`). Reads the size tier, `icon` per option, `iconOnly`, per-option or whole-control `disabled`, `fullWidth`. ← → keyboard. |
253
259
  | `ViewToggle` | List/grid icon toggle. |
254
260
 
@@ -287,7 +293,7 @@ import Textarea from '@keyfunc/keybricks-ds/components/forms/Textarea.vue'
287
293
  ### `icons/` — iconography
288
294
  | Component | What it's for |
289
295
  | --- | --- |
290
- | `Icon` | 362 stroke glyphs (the product's own set plus all of Feather). `<Icon name="download" size={16} />` |
296
+ | `Icon` | 330 stroke glyphs: the 83-glyph core set plus all of Feather (on a shared name the core glyph wins). `<Icon name="download" size={16} />` |
291
297
  | `Unicon` | 1,206 additional Unicons line glyphs, loaded from CDN. Use when `Icon` has no match. |
292
298
 
293
299
  ### `pipeline/` — the data-pipeline editor
@@ -487,7 +493,7 @@ a migration note in the release. Token renames are major because your own code r
487
493
  Pin a minor range and update deliberately:
488
494
 
489
495
  ```json
490
- "@keyfunc/keybricks-ds": "~2.1.1"
496
+ "@keyfunc/keybricks-ds": "~2.4.0"
491
497
  ```
492
498
 
493
499
  ### Migrating from 1.x to 2.0
@@ -513,6 +519,85 @@ Pin a minor range and update deliberately:
513
519
  - **Tokens outside CSS.** `tokens.json` / `tokens.js` / `tokens.d.ts` gained the tier tokens
514
520
  (`--control-*`, `--bar-h`, `--group-gap`, …) — 352 light tokens in all (2.0.2 adds `--danger-soft-hover`).
515
521
 
522
+ ### 2.4.0
523
+
524
+ - **App Chrome matches the product.** `Sidebar`: 56px brand head without a rule, `--text-md` brand, a 2px-gap list, `trailing: true` items with a chevron (they open a side panel), Collapse / Expand item (chevron-left / panel-left), pinned footer and an optional `version` line. New `tone` prop — `"recessed"` (grey rail, active item a white tile with a hairline ring; **the new default**), `"flush"` (the old white look), `"contrast"` (dark-scoped rail), `"custom"` + `color` (`SIDEBAR_COLORS` or any hex). `KEYBRICKS_NAV` is the product's nav (Home … Task Execution); new `KEYBRICKS_NAV_FOOTER` (Management, Knowledge Base) is the default footer (was Help / Settings / Dark Mode) and `KEYBRICKS_MGMT` holds the Management panel groups. To keep the old look pass `tone="flush"` and your own `footerItems`.
525
+ - **Data-source logos:** 17 logo images (databases, SAP, protocols, file types) in `assets/logos/datasource/<id>.png`, 500×500 PNG, listed on the new *Data Source Logos* icons page. They are plain images, not `Icon` glyphs — use them with `<img>`.
526
+ - **New `SidePanel`**: the 240px panel docked beside the sidebar (Documents, Management), same tone as the rail, opens from 0 width with a fade; 56px header with title, actions and close.
527
+ - **`TopBar`**: dark **AI Assistant** (`ai` icon) first, then notifications and help `IconButton`s, then a user trigger (`user={{ name, email }}`) that opens a menu. The bell is no longer `lg`. **New `UserMenu`**: avatar, name, email, an Appearance row (icon-only light / dark / system) and menu rows.
528
+
529
+ - **`ContextMenu` / `Menu` single-choice state.** Items accept `selected: true` (section switcher, language picker): `--bg-hover` fill, `--weight-medium` `--text-heading`, no checkmark; rows become `menuitemradio` with `aria-checked`. When any item is selected the rows are spaced 2px apart (as in `Sidebar`, `Tree`, `DocTree`); action menus with nothing selected keep flush rows. Dividers keep 4px above and below.
530
+
531
+ - **Docs:** new *Icon Usage* page at the top of Icons (monochrome vs coloured glyphs: IconTile hues, Tree/DocTree document hues, status, marks). The documentation site itself now follows the system rules — neutral selected segments, sentence-case labels, sm-tier toolbar controls, 32px Sidebar-spec nav rows.
532
+ ### 2.3.2
533
+
534
+ - **Counts on `Tabs`, `PanelTabs`, `PillTabs` and `SegmentedControl`.** Tabs / options accept `{ label, count?, showZero? }`; a count renders as a `CountBadge` 6px right of the label — `--count-h` tall (new tier token: sm 16 · md 18 · lg 20), 6px sides, full radius, 12px tabular figures; fill `--neutral-alpha-8` on any surface, text `--text-body`, `--text-heading` when selected. 0 or no count hides it; `showZero` (control or option) draws a muted 0. Selection is still matched by label. `CountBadge` is exported (React `Tabs.jsx`, Vue `CountBadge.vue`).
535
+ - Additive only.
536
+
537
+ ### 2.3.1
538
+
539
+ - **`Table` row open, tree rows and labels.** `onRowOpen(row, index, event)` (Vue `@row-open`) makes the icon tile and title of a two-line cell open the row (hand cursor; Enter / Space on the title). `tree` with nested `children` (or `hasChildren` for lazy rows) indents the two-line column 24px per level with an expand arrow — `expandedKeys` / `defaultExpandedKeys` / `onExpandChange(row, expanded, keys)` (Vue `v-model:expandedKeys`, `@expand-change`), `rowKey` (default `id`); sorting reorders siblings only. `labels: { sortAsc, sortDesc, sortClear, more, expand, collapse }` translates every word the table draws (English by default). Indices reported by selection and callbacks are depth-first over all rows — unchanged for flat tables.
540
+ - Additive only: flat tables, existing props and indices behave exactly as in 2.3.0.
541
+
542
+ ### 2.3.0
543
+
544
+ - **sm and lg size tiers.** sm controls are **28px** (was 24) with 36px rows and bars (was 32);
545
+ lg controls are **40px** (was 36) with 48px rows (was 44); md is unchanged. 24px sat at the
546
+ floor of the industry range and left the segmented control's segments 18px tall; 36 was only
547
+ 4px above md, where Ant Design, Fluent 2, Primer and shadcn all step to 40. sm text stays 12px
548
+ for Latin. Layouts built on the tier tokens follow automatically; anything you sized by hand to
549
+ sit beside an sm or lg control should be re-checked.
550
+ - **CJK small sizes are one step larger.** Under `lang="zh" | "ja" | "ko"` (Simplified and
551
+ Traditional Chinese alike) `--text-xs` / `--text-sm` are 13px with 18px leading and
552
+ `--text-2xs` is 12px, so no CJK text renders below 12px. 14px and up are unchanged. In sm
553
+ regions the CJK medium weight is 400. Outside sm, CJK `--weight-medium` and `--weight-semibold` are both 500 (they were 600): at the same number, CJK glyphs read heavier than Latin, so 600 looked a step bolder than English and erased the difference between labels and headers. On Windows (no 500 face in YaHei / Meiryo / Malgun) both render Regular. Chart numerals use the new `--text-2xs-mono`
554
+ (11px in every language).
555
+ - `Table` selection: the checkbox now sits in the first column's leading space instead of a column of its own. Both sides of the checkbox now equal the edge padding (16px; 12px in sm), so the box sits evenly between the card edge and the first column's text and stays aligned with card titles and toolbars. Before, the gap was 40px and grew with the table width when columns declared widths (up to ~120px). If you styled the old selection cell (`td:first-child` holding only the checkbox), move that styling to the first data cell.
556
+ - **`Table` two-line name rows**: a `twoLine` column renders an `IconTile` (kind "row", tinted by `hue`; `neutral` = grey), a title over a description (each one line, truncated), an optional 14px mark (`"favorite"` = filled star in `--warning`) and a trailing sm `⋯` (`onRowMore(row, index, event)`, Vue `@row-more`). md rows are 58px (sm 50 · lg 68; CJK 54 · 60 · 70); the header keeps the bar height. New tier tokens `--title-cell-py`, `--title-cell-gap`, `--title-cell-tile`, `--title-cell-icon`, `--title-cell-tile-r`, `--title-cell-tile-gap`. `IconTile kind="row"` is now tinted when you pass `hue` (unchanged without it), adds `hue="neutral"` and an `iconStyle` prop.
557
+ - **`Table` sortable headers**: `sortable: true` on a column adds a muted sm sort button at the header cell's right end (in line with a two-line row's `⋯`) — on hover while unsorted (`arrow-up`), kept while sorted (`arrow-up` / `arrow-down`, label `--text-heading`, `aria-sort`). Click cycles ascending → descending → none; one column at a time; tooltips *Sort ascending* / *Sort descending* / *Clear sorting*. New props `sort`, `defaultSort`, `onSortChange` (Vue `v-model:sort`, `@sort-change`), `manualSort`; column `compare`. Selection indices keep referring to the original `rows` order.
558
+ - `IconButton` hover and press are now alpha overlays (`--overlay-hover`, `--overlay-press`) instead of the solid `--bg-hover` / `--bg-press`. On white they are the same colour as before; on a grey surface (table header, toolbar) the hover is now visible instead of matching the background. `--overlay-press` is 12% (was 8%, unused) and the dark theme gets its own overlay values (8% / 16%).
559
+ - **Fix — `Table` `code` columns:** only text and number values get the code chip; an element in the cell (a `Skeleton` while loading, a link) renders as is. Before, a loading row in a code column drew a chip around the skeleton and grew to about 50px.
560
+ - **Two AI glyphs join the core icon set**: `ai` (rounded frame, open at the top-right, with a large and a small four-point star) and `ai-sparkles` (a large and a small four-point star). Both are traced from the reference glyphs and redrawn to the core-set rules: stroke 2 with no fill, integer endpoints, at least 2px clear between separate elements. The core set is 83 glyphs; `Icon` resolves 330 names. Search terms: ai, assistant, copilot, agent, intelligent, generative, sparkles, magic.
561
+ - `Pagination`: page items and prev/next lose their border (GitHub Primer / Atlassian style). The current page takes the neutral selected fill (`--bg-active`, weight 600) instead of the action blue — it is a state, not an action; the others are plain until hovered. Size is unchanged — items stay control-height (32px at md).
562
+ - The monospace font is now for code only (`CodeBlock`, `LogViewer`, code in the docs). `Table`/`SmartTable` `mono` columns, `KeyValue` and `DiffValue` `mono`, `Spreadsheet` numbers and formula bar, `Kbd`, the `Input`/`Textarea` counter, the `Slider` value and every chart number now use `--font-sans` with tabular figures; `mono` columns also take the normal text colour. The `mono` props and the `--text-2xs-mono` token keep their names. Config codes get a new column option, `code: true`: a code chip — Menlo at the new `--text-code` / `--leading-code` (12/18px, 11/16px in sm, not bumped in CJK) on `--bg-inset` with a hairline border. Switch config-code columns from `mono` to `code`.
563
+ - `Table` column separators (the resize handles in the header) are one step darker: new token `--border-split` — `#D4D4D4` light, `#404040` dark (was `--border-control`, #E5E5E5 / #333333). Hover and drag still turn them blue.
564
+ - New tokens: `--text-2xs-mono` and `--text-glyph-min` (11px, 12px in CJK) — the floor for text that is sized from geometry: `Switch` inside/knob text and `Avatar` initials no longer drop to 9–10px. `--h-button-sm` is 28px.
565
+ - Removed the `ui_kits/keybricks-app` product recreation and the `templates/web-app` starter: the
566
+ production designs now live in their own projects. No component or token is affected.
567
+ - **Fix — React entry:** `applyStoredTheme` was documented but missing from
568
+ `@keyfunc/keybricks-ds` (the barrel generator skipped lower-case names). It is exported now.
569
+ - **Fix — Vue entry:** `KEYBRICKS_NAV` and `applyStoredTheme` existed for Vue only as comments.
570
+ They now live in `navigation/nav-model.js` and `navigation/theme-store.js`, which React re-exports
571
+ and `@keyfunc/keybricks-ds/vue` exports directly, along with `PIPELINE_CATALOG`, `VUE_ICON_PATHS`
572
+ and `FEATHER_PATHS` — one source for both frameworks.
573
+ - **Fixes — Vue matched to React** (found by a token-by-token and prop-by-prop audit of every
574
+ React/Vue pair): `Tree` keyboard focus ring uses `--focus-border` (was `--focus-ring`) and now
575
+ accepts `treeData`, `expandedKeys`, `selectedKeys`, `checkedKeys`; `Switch` accepts
576
+ `inlinePrompt`; `Timeline` title and meta carry their line-height and tracking (CJK meta now
577
+ gets its 18px leading); `Spreadsheet` column headers carry `--tracking-xs`; `SmartTable` URL
578
+ cells use `--link`; `FunnelChart` bands animate width; `WaterfallChart` shows the hover band.
579
+ `BulletChart` range bands use `--neutral-alpha-12` in both frameworks (theme-aware; was a
580
+ hard-coded black in Vue and an undefined token in React).
581
+ - Sidebar nav model (`KEYBRICKS_NAV`): Reconciliation uses the `reconciliation` icon and
582
+ Consolidation the `consolidation` icon; the Management › Reconciliation entry no longer reuses
583
+ `network`.
584
+ - Component cards share one specimen layout (label column, 12px sentence-case labels) and every
585
+ size-tier demo shows a Latin row and a CJK row.
586
+
587
+ ### 2.2.0
588
+
589
+ - **Eleven Keybricks glyphs join the core icon set** — `<Icon name="journal" />` in React and
590
+ Vue alike. Modules: `reconciliation`, `consolidation`, `journal`, `event`, `view-tree`.
591
+ Actions: `drilldown`, `add-below`, `copy-data`, `task-execution`, `time-future`,
592
+ `time-restatement`. Each was checked against the core-set drawing rules, now written down in
593
+ the Iconography section of `readme.md`; six were redrawn to meet them (paths inside 2–22,
594
+ integer coordinates, 2px between separate elements, rx 1 on small rects, true circular
595
+ corners). The core set is now 81 glyphs; with Feather, `Icon` resolves 328 names.
596
+ - Two submitted glyphs were already in the library and were not duplicated: *hierarchy* is
597
+ `layers` and *change* is Feather's `repeat`. Both words now find them in the icon search.
598
+ - The docs gave the icon total as 362. That counted the 40 names Feather shares with the core
599
+ set twice; the number of distinct names is now 328.
600
+
516
601
  ### 2.1.1
517
602
 
518
603
  - **Chart series palette replaced** (`--series-1…8`, light and dark). One lightness band, a chroma
@@ -570,18 +655,6 @@ Pin a minor range and update deliberately:
570
655
 
571
656
  Release mechanics, the CI pipeline and the Pages site are documented in `DEPLOY.md`.
572
657
 
573
- ## Templates
574
-
575
- A template is a ready-made screen you copy into a new project as a starting point, rather than a
576
- component you import. Each lives in `templates/<slug>/`.
577
-
578
- | Template | What you get |
579
- | --- | --- |
580
- | `templates/web-app/` | The full app shell: sidebar with the real nav model, top bar, page heading, stat tiles and a data table. |
581
-
582
- Copy the folder, then edit one line — the `base` in `ds-base.js` — to point at wherever the design
583
- system sits relative to the copied page.
584
-
585
658
  ## Getting help
586
659
 
587
660
  - **Documentation site** — the GitLab Pages build: `index.html` for the browsable system
package/SKILL.md CHANGED
@@ -4,30 +4,30 @@ description: Use this skill to generate well-branded interfaces and assets for K
4
4
  user-invocable: true
5
5
  ---
6
6
 
7
- Read the README.md file within this skill, and explore the other available files. This skill's documentation is bilingual (English / 中文)。
7
+ Read the readme.md file within this skill, and explore the other available files. This skill's documentation is bilingual (English / 中文)。
8
8
 
9
9
  Key facts / 关键信息: Keybricks is a near-monochrome, hairline-bordered, 14px-Inter enterprise UI with one action blue (#155dfc, dark mode #1f6feb), five node-category hues, and a signature node-pipeline editor.
10
10
  (Keybricks 是一个近乎单色、细边框、以 14px Inter 为主的企业级界面,仅有一个强调蓝(浅色 #155dfc / 深色 #1f6feb)、五种节点分类色,以及标志性的数据管道编辑器。)
11
- Tokens live in `tokens/*.css` (linked via `styles.css`, includes `tokens/dark.css` for dark mode and `tokens/motion.css` for motion); React components in `components/<group>/` (each with a `.d.ts` contract and `.prompt.md` usage note); full-screen recreations in `ui_kits/keybricks-app/`.
12
- (设计令牌位于 `tokens/*.css`(经 `styles.css` 汇总,含深色模式 `tokens/dark.css` 与动效 `tokens/motion.css`);React 组件位于 `components/<分组>/`(各附 `.d.ts` 类型定义与 `.prompt.md` 用法说明);完整界面复刻位于 `ui_kits/keybricks-app/`。)
11
+ Tokens live in `tokens/*.css` (linked via `styles.css`, includes `tokens/dark.css` for dark mode and `tokens/motion.css` for motion); React and Vue 3 components in `components/<group>/` (each React file with a `.d.ts` contract; each group with a `.prompt.md` usage note).
12
+ (设计令牌位于 `tokens/*.css`(经 `styles.css` 汇总,含深色模式 `tokens/dark.css` 与动效 `tokens/motion.css`);React 与 Vue 3 组件位于 `components/<分组>/`(React 文件附 `.d.ts` 类型定义,每个分组附 `.prompt.md` 用法说明)。)
13
13
 
14
14
  If creating visual artifacts (slides, mocks, throwaway prototypes, etc), copy assets out and create static HTML files for the user to view. If working on production code, you can copy assets and read the rules here to become an expert in designing with this brand.
15
15
 
16
16
  If the user invokes this skill without any other guidance, ask them what they want to build or design, ask some questions, and act as an expert designer who outputs HTML artifacts _or_ production code, depending on the need.
17
17
 
18
18
  Rules of thumb / 要点速览:
19
- - Inter 14px/400 is the default; 500 for nav/headings/labels; 600 for node & panel titles and table headers; 300 only for big numerals. Menlo for codes, data cells, logs — at the row's own size. In Chinese/Japanese/Korean, 500 becomes 600 and tracking is 0.
20
- (Inter 14px/常规 为默认;500 用于导航/标题/标签;600 用于节点与面板标题及表头;300 仅用于大号数字。代码/数据/日志用 Menlo,与所在行同字号。中/日/韩文中 500 改为 600,字距为 0。)
21
- - One size tier per region: `data-size="sm" | "md" | "lg"` = 24 / 32 / 36px controls. Set it on the bar, form, table or dialog; controls inherit. Never mix heights or text sizes in one row; nothing interactive under 24px.
22
- (每个区域只用一档尺寸:`data-size="sm" | "md" | "lg"` 对应 24 / 32 / 36px 控件。设在工具栏、表单、表格或对话框上,控件自动继承。同一行不混用高度或字号;可交互元素不小于 24px。)
19
+ - Inter 14px/400 is the default; 500 for nav/headings/labels; 600 for node & panel titles and table headers; 300 only for big numerals. Menlo only for code — CodeBlock, LogViewer and config-code chips; amounts and IDs stay in Inter with tabular figures. In Chinese/Japanese/Korean, 500 and 600 both become 500, tracking is 0, and text below 14px is one step larger (12→13, 11→12).
20
+ (Inter 14px/常规 为默认;500 用于导航/标题/标签;600 用于节点与面板标题及表头;300 仅用于大号数字。Menlo 只用于代码——代码块、日志和配置代码标签;金额与编号仍用 Inter 等宽数字。中/日/韩文中 500 与 600 都改为 500(同字重下方块字更显粗),字距为 0,14px 以下的字号比英文大一档(12→13、11→12)。)
21
+ - One size tier per region: `data-size="sm" | "md" | "lg"` = 28 / 32 / 40px controls (rows and bars 36 / 40 / 48). Set it on the bar, form, table or dialog; controls inherit. Never mix heights or text sizes in one row; nothing interactive under 24px.
22
+ (每个区域只用一档尺寸:`data-size="sm" | "md" | "lg"` 对应 28 / 32 / 40px 控件(行与工具栏 36 / 40 / 48)。设在工具栏、表单、表格或对话框上,控件自动继承。同一行不混用高度或字号;可交互元素不小于 24px。)
23
23
  - Backgrounds: app #fafafa, surfaces white, hairline borders rgba(229,229,229,.6); shadows only on canvas nodes.
24
24
  (背景:应用层 #fafafa,卡片层白色,细边框;仅画布节点有阴影。)
25
25
  - One blue CTA per view; ghost text buttons beside it. Color only for meaning (category hues, status).
26
26
  (每个界面只有一个蓝色主按钮,旁边配文字按钮;颜色只用于表达含义。)
27
- - Icons: Lucide stroke set via the Icon component — never emoji, never hand-drawn SVG.
28
- (图标统一用 Icon 组件封装的 Lucide 线性图标集——禁止 emoji,禁止手绘 SVG。)
29
- - Radii: 4 controls · 8 buttons/inputs · 10 cards · 14/16 tiles & nodes · full circles.
30
- (圆角:4px 控件、8px 按钮/输入框、10px 卡片、14/16px 图标块与节点、端口/胶囊全圆角。)
27
+ - Icons: the Icon component — Lucide stroke glyphs plus the Keybricks glyphs drawn to the same rules (`ai`, `ai-sparkles`, module icons) — never emoji, never ad-hoc SVG.
28
+ (图标统一用 Icon 组件:Lucide 线性图标,加上按同一规范绘制的 Keybricks 图标(`ai`、`ai-sparkles`、模块图标)——禁止 emoji,禁止临时手绘 SVG。)
29
+ - Radii: 4 checkboxes · 8 buttons/inputs/row icon tiles · 10 cards · 14/16 tiles & nodes · full circles.
30
+ (圆角:4px 复选框、8px 按钮/输入框/行内图标块、10px 卡片、14/16px 图标块与节点、端口/胶囊全圆角。)
31
31
  - Copy: Title Case labels, imperative verb-first buttons ("Run Test", "Mark as New"), terse technical vocabulary.
32
32
  (文案:标签用词首大写,按钮用祈使动词开头,术语简洁精确。)
33
33
  - Dark mode: set `<html data-theme="dark">`. Style only via semantic tokens (`--bg-surface`, `--text-body`, `--border-card`, `--track`, `--soft-bg`, `--info-bg`, `--on-accent`, `--ring-surface`) — never raw `--neutral-*`/`--blue-*` — and both themes work automatically.