@keyfunc/keybricks-ds 2.6.0 → 2.8.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 (178) hide show
  1. package/DEPLOY.md +3 -3
  2. package/DESIGN.md +21 -5
  3. package/INTEGRATION.md +35 -4
  4. package/_adherence.oxlintrc.json +56 -11
  5. package/_ds_bundle.js +2153 -216
  6. package/_scripts/build-index.mjs +1 -1
  7. package/_src/icon-index.js +1 -1
  8. package/{components/feedback → _vue-services}/MESSAGE_SERVICES.md +2 -2
  9. package/_vue-services/_internal/MessageBoxView.vue +150 -0
  10. package/{components/feedback → _vue-services}/_internal/service-utils.js +0 -12
  11. package/_vue-services/message.js +87 -0
  12. package/assets/icons/icon-index.json +1 -1
  13. package/changelog.js +21 -2
  14. package/components/_cards/accordion.card.html +1 -1
  15. package/components/_cards/action-chip.card.html +1 -1
  16. package/components/_cards/activity.card.html +1 -1
  17. package/components/_cards/alert.card.html +1 -1
  18. package/components/_cards/app-chrome.card.html +1 -1
  19. package/components/_cards/banner.card.html +1 -1
  20. package/components/_cards/breadcrumb.card.html +1 -1
  21. package/components/_cards/button-1-base.card.html +5 -2
  22. package/components/_cards/button-2-states.card.html +5 -5
  23. package/components/_cards/button-3-sizes-icons.card.html +2 -2
  24. package/components/_cards/button-4-group.card.html +2 -2
  25. package/components/_cards/button-5-ai.card.html +34 -0
  26. package/components/_cards/canvas-zoom-controls.card.html +1 -1
  27. package/components/_cards/cards-indicators.card.html +1 -1
  28. package/components/_cards/charts-1-sparkline.card.html +1 -1
  29. package/components/_cards/charts-10-gauge.card.html +1 -1
  30. package/components/_cards/charts-11-funnel.card.html +1 -1
  31. package/components/_cards/charts-12-treemap.card.html +1 -1
  32. package/components/_cards/charts-14-radar.card.html +1 -1
  33. package/components/_cards/charts-15-distribution.card.html +1 -1
  34. package/components/_cards/charts-16-pareto.card.html +1 -1
  35. package/components/_cards/charts-17-candlestick.card.html +1 -1
  36. package/components/_cards/charts-18-sankey.card.html +1 -1
  37. package/components/_cards/charts-19-chord.card.html +1 -1
  38. package/components/_cards/charts-2-line.card.html +1 -1
  39. package/components/_cards/charts-20-sunburst.card.html +1 -1
  40. package/components/_cards/charts-21-worldmap.card.html +1 -1
  41. package/components/_cards/charts-22-gantt.card.html +1 -1
  42. package/components/_cards/charts-23-bar3d.card.html +1 -1
  43. package/components/_cards/charts-24-pie3d.card.html +1 -1
  44. package/components/_cards/charts-25-surface3d.card.html +1 -1
  45. package/components/_cards/charts-26-scatter3d.card.html +1 -1
  46. package/components/_cards/charts-27-ribbon3d.card.html +1 -1
  47. package/components/_cards/charts-3-bar.card.html +1 -1
  48. package/components/_cards/charts-4-barlist.card.html +1 -1
  49. package/components/_cards/charts-5-donut.card.html +1 -1
  50. package/components/_cards/charts-6-scatter.card.html +1 -1
  51. package/components/_cards/charts-7-heatmap.card.html +1 -1
  52. package/components/_cards/charts-8-waterfall.card.html +1 -1
  53. package/components/_cards/charts-9-bullet.card.html +1 -1
  54. package/components/_cards/charts-99-fullpage.card.html +1 -1
  55. package/components/_cards/checkbox.card.html +1 -1
  56. package/components/_cards/codeblock.card.html +1 -1
  57. package/components/_cards/combobox.card.html +1 -1
  58. package/components/_cards/context-menu.card.html +1 -1
  59. package/components/_cards/date-picker.card.html +1 -1
  60. package/components/_cards/diffvalue.card.html +1 -1
  61. package/components/_cards/divider.card.html +1 -1
  62. package/components/_cards/drawer.card.html +1 -1
  63. package/components/_cards/dropdown-menu.card.html +1 -1
  64. package/components/_cards/dropzone.card.html +1 -1
  65. package/components/_cards/empty-state.card.html +1 -1
  66. package/components/_cards/filter-bar.card.html +1 -1
  67. package/components/_cards/icon-button.card.html +1 -1
  68. package/components/_cards/icons-0-usage.card.html +2 -2
  69. package/components/_cards/icons-1-core.card.html +1 -1
  70. package/components/_cards/icons-2-feather.card.html +1 -1
  71. package/components/_cards/icons-2b-lucide.card.html +1 -1
  72. package/components/_cards/icons-3-unicons.card.html +1 -1
  73. package/components/_cards/icons-4-datasource.card.html +1 -1
  74. package/components/_cards/input.card.html +1 -1
  75. package/components/_cards/kbd.card.html +5 -7
  76. package/components/_cards/keyvalue.card.html +1 -1
  77. package/components/_cards/listrow.card.html +1 -1
  78. package/components/_cards/loading.card.html +1 -1
  79. package/components/_cards/log-viewer.card.html +1 -1
  80. package/components/_cards/modal.card.html +8 -2
  81. package/components/_cards/multi-select.card.html +1 -1
  82. package/components/_cards/number-stepper.card.html +1 -1
  83. package/components/_cards/pagination.card.html +1 -1
  84. package/components/_cards/people.card.html +1 -1
  85. package/components/_cards/pipeline-node.card.html +1 -1
  86. package/components/_cards/pipeline-palette.card.html +1 -1
  87. package/components/_cards/radio.card.html +1 -1
  88. package/components/_cards/relative-time-picker.card.html +1 -1
  89. package/components/_cards/search-global.card.html +72 -0
  90. package/components/_cards/search.card.html +1 -1
  91. package/components/_cards/segmented-control.card.html +1 -1
  92. package/components/_cards/select.card.html +1 -1
  93. package/components/_cards/slider.card.html +1 -1
  94. package/components/_cards/smart-table.card.html +1 -1
  95. package/components/_cards/spreadsheet.card.html +1 -1
  96. package/components/_cards/stepper.card.html +1 -1
  97. package/components/_cards/table.card.html +10 -1
  98. package/components/_cards/tabs.card.html +1 -1
  99. package/components/_cards/tag.card.html +1 -1
  100. package/components/_cards/textarea.card.html +1 -1
  101. package/components/_cards/timeline.card.html +1 -1
  102. package/components/_cards/toast.card.html +11 -1
  103. package/components/_cards/toggles.card.html +1 -1
  104. package/components/_cards/tooltip.card.html +1 -1
  105. package/components/_cards/tree.card.html +22 -1
  106. package/components/_vue/index.mjs +2 -0
  107. package/components/buttons/Button.d.ts +14 -5
  108. package/components/buttons/Button.jsx +45 -8
  109. package/components/buttons/Button.vue +40 -38
  110. package/components/buttons/Button.vue.d.ts +4 -1
  111. package/components/buttons/ai-button.js +54 -0
  112. package/components/buttons/buttons.prompt.md +7 -2
  113. package/components/data/Table.d.ts +5 -0
  114. package/components/data/Table.jsx +10 -5
  115. package/components/data/Table.vue +9 -3
  116. package/components/data/data.prompt.md +2 -0
  117. package/components/data/row-open.js +13 -0
  118. package/components/display/Kbd.d.ts +3 -1
  119. package/components/display/Kbd.jsx +8 -3
  120. package/components/display/Kbd.vue +7 -3
  121. package/components/display/display.prompt.md +3 -1
  122. package/components/feedback/Modal.d.ts +65 -7
  123. package/components/feedback/Modal.jsx +52 -22
  124. package/components/feedback/Modal.vue +24 -6
  125. package/components/feedback/Toast.vue +7 -7
  126. package/components/feedback/ToastStack.vue +37 -4
  127. package/components/feedback/feedback.prompt.md +6 -0
  128. package/components/feedback/modal-behavior.js +50 -0
  129. package/components/forms/GlobalSearch.d.ts +83 -0
  130. package/components/forms/GlobalSearch.jsx +172 -0
  131. package/components/forms/GlobalSearch.vue +161 -0
  132. package/components/forms/forms.prompt.md +7 -0
  133. package/components/forms/global-search.js +161 -0
  134. package/components/icons/Icon.d.ts +2 -0
  135. package/components/icons/Icon.jsx +14 -6
  136. package/components/icons/Icon.vue +11 -4
  137. package/components/icons/icon-paths.js +4 -2
  138. package/components/index.d.ts +1 -0
  139. package/components/index.js +1 -0
  140. package/components/navigation/TopBar.d.ts +9 -3
  141. package/components/navigation/TopBar.jsx +5 -7
  142. package/components/navigation/TopBar.vue +5 -6
  143. package/components/navigation/Tree.d.ts +5 -1
  144. package/components/navigation/Tree.jsx +9 -7
  145. package/components/navigation/Tree.vue +7 -6
  146. package/components/navigation/navigation.prompt.md +2 -0
  147. package/covers.js +4 -2
  148. package/gallery.html +1 -1
  149. package/guidelines/brand-logo.html +1 -1
  150. package/guidelines/colors-schemes.html +1 -1
  151. package/guidelines/colors-transparency.html +1 -1
  152. package/guidelines/foundations-borders.html +1 -1
  153. package/guidelines/foundations-chrome.html +1 -1
  154. package/guidelines/foundations-motion.html +1 -1
  155. package/guidelines/foundations-size-tiers.html +1 -1
  156. package/guidelines/foundations-spacing.html +1 -1
  157. package/guidelines/interaction-states.html +1 -1
  158. package/guidelines/type-extended.html +1 -1
  159. package/guidelines/type-mono.html +1 -1
  160. package/guidelines/type-scale.html +1 -1
  161. package/guidelines/type-weights.html +1 -1
  162. package/index.html +10 -10
  163. package/package.json +7 -6
  164. package/readme.md +4 -4
  165. package/readme.zh-CN.md +4 -4
  166. package/site-nav.js +1 -1
  167. package/styles.css +1 -0
  168. package/tokens/ai.css +17 -0
  169. package/tokens/colors.css +1 -1
  170. package/tokens/tokens.d.ts +28 -0
  171. package/tokens/tokens.js +47 -5
  172. package/tokens/tokens.json +123 -5
  173. package/components/feedback/_internal/MessageBoxView.vue +0 -237
  174. package/components/feedback/_internal/MessageView.vue +0 -73
  175. package/components/feedback/message.js +0 -68
  176. /package/{components/feedback → _vue-services}/message-box.d.ts +0 -0
  177. /package/{components/feedback → _vue-services}/message-box.js +0 -0
  178. /package/{components/feedback → _vue-services}/message.d.ts +0 -0
@@ -6,7 +6,8 @@ export interface TreeItem {
6
6
  /** Row text; `label` is accepted as an alias */
7
7
  title?: string;
8
8
  label?: string;
9
- icon?: string;
9
+ /** Glyph name; false = no glyph on this row and no space kept for one — the text follows the expand arrow (e.g. a "Documents" root). Works with showIcon on. */
10
+ icon?: string | false;
10
11
  /** Leaf glyph hue: orange | green | purple | blue | teal | gray */
11
12
  hue?: string;
12
13
  /** Right-aligned count */
@@ -37,6 +38,8 @@ export interface TreeDropInfo {
37
38
  * Nested tree view: expand/collapse, single or multiple selection, cascading checkboxes with
38
39
  * indeterminate parents, disabled nodes, connector lines, async loading, search highlight,
39
40
  * drag to move, keyboard navigation.
41
+ * Follows the size tier of its region (data-size): row height --control-h (sm 28 · md 32 · lg 40), text --control-text / --control-leading /
42
+ * --control-tracking (sm 12px, 13px in CJK · md 14px), glyph --control-icon − 1px (sm 13 · md 15). md looks exactly as before.
40
43
  */
41
44
  export interface TreeProps {
42
45
  items?: TreeItem[];
@@ -63,6 +66,7 @@ export interface TreeProps {
63
66
  multiple?: boolean;
64
67
  /** false = rows only expand, never select */
65
68
  selectable?: boolean;
69
+ /** Glyph before each title (default true); a node with icon: false skips it either way */
66
70
  showIcon?: boolean;
67
71
  /** Draw connector lines instead of plain indentation */
68
72
  showLine?: boolean;
@@ -154,7 +154,7 @@ function Row({ item, state, cfg, api }) {
154
154
  onKeyDown={(e) => api.keyDown(e, item)}
155
155
  onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
156
156
  style={{
157
- position: "relative", minHeight: "var(--h-tree-item)", borderRadius: "var(--radius-md)", display: "flex", alignItems: "center", gap: 6,
157
+ position: "relative", minHeight: "var(--control-h)", borderRadius: "var(--radius-md)", display: "flex", alignItems: "center", gap: 6,
158
158
  padding: cfg.showLine ? "0 8px 0 2px" : "5px 8px", paddingLeft: cfg.showLine ? 2 : 8 + depth * INDENT, boxSizing: "border-box",
159
159
  cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.45 : 1,
160
160
  background: dropAt === "inside" ? "var(--soft-bg)" : selected ? "var(--bg-active)" : hover && !disabled ? "var(--bg-hover)" : "transparent",
@@ -169,12 +169,12 @@ function Row({ item, state, cfg, api }) {
169
169
  <Checkbox checked={checked} indeterminate={half} disabled={disabled || node.disableCheckbox} tabIndex={-1} onChange={() => api.check(key)} />
170
170
  </span>
171
171
  ) : null}
172
- {cfg.showIcon ? (
172
+ {cfg.showIcon && node.icon !== false ? (
173
173
  <span style={{ color: branch ? "var(--text-muted)" : docHues[node.hue || "gray"], display: "inline-flex", flexShrink: 0 }}>
174
- <Icon name={node.icon || (branch ? (open ? "folder-open" : "folder") : "file-text")} size={15} />
174
+ <Icon name={node.icon || (branch ? (open ? "folder-open" : "folder") : "file-text")} size={15} style={{ width: "calc(var(--control-icon) - 1px)", height: "calc(var(--control-icon) - 1px)" }} />
175
175
  </span>
176
176
  ) : null}
177
- <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", fontWeight: selected ? "var(--weight-medium)" : "var(--weight-regular)", color: disabled ? "var(--text-muted)" : "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
177
+ <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", letterSpacing: "var(--control-tracking)", fontWeight: selected ? "var(--weight-medium)" : "var(--weight-regular)", color: disabled ? "var(--text-muted)" : "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
178
178
  <Highlight text={titleOf(node)} query={cfg.searchValue} />
179
179
  </span>
180
180
  {node.tag ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", lineHeight: 1, padding: "2px 5px", borderRadius: "var(--radius-sm)", background: "var(--bg-inset)", color: "var(--text-secondary)", flexShrink: 0 }}>{node.tag}</span> : null}
@@ -182,7 +182,7 @@ function Row({ item, state, cfg, api }) {
182
182
  {cfg.rowActions && !disabled ? <span style={{ marginLeft: node.count != null ? 6 : "auto", display: "flex", gap: 2, opacity: hover ? 1 : 0, transition: "var(--t-hover)" }} onClick={(e) => e.stopPropagation()}>{cfg.rowActions(node)}</span> : null}
183
183
  </div>
184
184
  {open && loading && !kids.length ? (
185
- <div style={{ paddingLeft: 8 + (depth + 1) * INDENT + 14, fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", color: "var(--text-muted)", height: "var(--h-tree-item)", display: "flex", alignItems: "center" }}>Loading…</div>
185
+ <div style={{ paddingLeft: 8 + (depth + 1) * INDENT + 14, fontFamily: "var(--font-sans)", fontSize: "var(--text-xs)", color: "var(--text-muted)", height: "var(--control-h)", display: "flex", alignItems: "center" }}>Loading…</div>
186
186
  ) : null}
187
187
  </>
188
188
  );
@@ -193,7 +193,9 @@ function Row({ item, state, cfg, api }) {
193
193
  * (with indeterminate parents and `checkStrictly` opt-out), disabled nodes and disabled
194
194
  * checkboxes, connector lines, async child loading, search highlighting, drag to move,
195
195
  * and full keyboard navigation. Node shape: { key, title, icon, hue, count, tag, children,
196
- * disabled, disableCheckbox, selectable, checkable, isLeaf }.
196
+ * disabled, disableCheckbox, selectable, checkable, isLeaf }. icon: false drops that row's glyph (no gap kept), e.g. a root.
197
+ * Follows the size tier of its region: row --control-h (sm 28 · md 32 · lg 40), text --control-text / -leading / -tracking,
198
+ * glyph --control-icon − 1px (md 15, as before).
197
199
  */
198
200
  export function Tree({
199
201
  items = [], treeData,
@@ -356,7 +358,7 @@ export function Tree({
356
358
  <div role="tree" aria-multiselectable={multiple || undefined} style={{ display: "flex", flexDirection: "column", gap: showLine ? 0 : 1, minWidth: 0, ...style }}>
357
359
  <style>{"@keyframes kb-tree-spin{to{transform:rotate(360deg)}}"}</style>
358
360
  {rows.length === 0 ? (
359
- <div style={{ padding: "10px 8px", fontFamily: "var(--font-sans)", fontSize: "var(--text-base)", color: "var(--text-muted)" }}>No matching items</div>
361
+ <div style={{ padding: "10px 8px", fontFamily: "var(--font-sans)", fontSize: "var(--control-text)", lineHeight: "var(--control-leading)", color: "var(--text-muted)" }}>No matching items</div>
360
362
  ) : rows.map((r) => <Row key={r.key} item={r} state={state} cfg={cfg} api={api} />)}
361
363
  </div>
362
364
  );
@@ -4,7 +4,8 @@ import Icon from '../icons/Icon.vue'
4
4
  import Checkbox from '../forms/Checkbox.vue'
5
5
  // Nested tree view: expand/collapse, single or multiple selection, cascading checkboxes with
6
6
  // indeterminate parents (checkStrictly opts out), disabled nodes, connector lines, async
7
- // loadData, search highlight, drag to move, keyboard navigation.
7
+ // loadData, search highlight, drag to move, keyboard navigation. A node with icon: false has no glyph and keeps no gap for one.
8
+ // Follows the size tier of its region: row --control-h (sm 28 · md 32 · lg 40), text --control-text / -leading / -tracking, glyph --control-icon − 1px (md 15).
8
9
  const docHues = { orange: 'var(--cat-transform)', green: 'var(--cat-source)', purple: 'var(--cat-merge)', blue: 'var(--info-fg)', teal: 'var(--cat-output)', gray: 'var(--text-muted)' }
9
10
  const INDENT = 18
10
11
  // Insert marker (reorder before / after): a 2px --action-primary line with a 6px dot at its left end, drawn between rows.
@@ -235,7 +236,7 @@ const dropAt = k => (drop.value && drop.value.key === k ? drop.value.pos : null)
235
236
  @click="rowClick(row.n)" @contextmenu="onCtx($event, row.key)" @keydown="keyDown($event, row)"
236
237
  :class="{ 'is-disabled': row.n.disabled }"
237
238
  :style="{
238
- position: 'relative', minHeight: 'var(--h-tree-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: '6px',
239
+ position: 'relative', minHeight: 'var(--control-h)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: '6px',
239
240
  padding: showLine ? '0 8px 0 2px' : '5px 8px', paddingLeft: showLine ? '2px' : (8 + row.depth * INDENT) + 'px', boxSizing: 'border-box',
240
241
  cursor: row.n.disabled ? 'not-allowed' : 'pointer', opacity: row.n.disabled ? 0.45 : 1,
241
242
  background: dropAt(row.key) === 'inside' ? 'var(--soft-bg)' : selected.includes(row.key) ? 'var(--bg-active)' : 'transparent',
@@ -260,10 +261,10 @@ const dropAt = k => (drop.value && drop.value.key === k ? drop.value.pos : null)
260
261
  <Checkbox :checked="view.full.has(row.key)" :indeterminate="view.half.has(row.key)"
261
262
  :disabled="row.n.disabled || row.n.disableCheckbox" :tabindex="-1" @change="check(row.key)" />
262
263
  </span>
263
- <span v-if="showIcon" :style="{ color: isBranch(row.n) ? 'var(--text-muted)' : docHues[row.n.hue || 'gray'], display: 'inline-flex', flexShrink: 0 }">
264
- <Icon :name="row.n.icon || (isBranch(row.n) ? (openKeys.includes(row.key) ? 'folder-open' : 'folder') : 'file-text')" :size="15" />
264
+ <span v-if="showIcon && row.n.icon !== false" :style="{ color: isBranch(row.n) ? 'var(--text-muted)' : docHues[row.n.hue || 'gray'], display: 'inline-flex', flexShrink: 0 }">
265
+ <Icon :name="row.n.icon || (isBranch(row.n) ? (openKeys.includes(row.key) ? 'folder-open' : 'folder') : 'file-text')" :size="15" :style="{ width: 'calc(var(--control-icon) - 1px)', height: 'calc(var(--control-icon) - 1px)' }" />
265
266
  </span>
266
- <span :style="{ fontFamily: 'var(--font-sans)', fontSize: 'var(--text-base)', lineHeight: 'var(--leading-base)', fontWeight: selected.includes(row.key) ? 'var(--weight-medium)' : 'var(--weight-regular)', color: row.n.disabled ? 'var(--text-muted)' : 'var(--text-heading)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }">
267
+ <span :style="{ fontFamily: 'var(--font-sans)', fontSize: 'var(--control-text)', lineHeight: 'var(--control-leading)', letterSpacing: 'var(--control-tracking)', fontWeight: selected.includes(row.key) ? 'var(--weight-medium)' : 'var(--weight-regular)', color: row.n.disabled ? 'var(--text-muted)' : 'var(--text-heading)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }">
267
268
  <template v-for="(p, i) in parts(titleOf(row.n))" :key="i"><mark v-if="p.hit" style="background:var(--soft-bg);color:var(--info-fg);font-weight:var(--weight-medium);padding:0;border-radius:2px">{{ p.t }}</mark><template v-else>{{ p.t }}</template></template>
268
269
  </span>
269
270
  <span v-if="row.n.tag" style="font-family:var(--font-sans);font-size:var(--text-xs);line-height:1;padding:2px 5px;border-radius:var(--radius-sm);background:var(--bg-inset);color:var(--text-secondary);flex-shrink:0">{{ row.n.tag }}</span>
@@ -271,7 +272,7 @@ const dropAt = k => (drop.value && drop.value.key === k ? drop.value.pos : null)
271
272
  <!-- row actions: #row-actions="{ node }" slot, or rowActions(node) returning a VNode; shown on hover / focus -->
272
273
  <span v-if="(rowActions || $slots['row-actions']) && !row.n.disabled" class="kb-tree-actions" @click.stop :style="{ marginLeft: row.n.count != null ? '6px' : 'auto', display: 'flex', gap: '2px', flexShrink: 0 }"><slot name="row-actions" :node="row.n"><Cell v-if="rowActions" :v="rowActions(row.n)" /></slot></span>
273
274
  </div>
274
- <div v-if="!rows.length" style="padding:10px 8px;font-family:var(--font-sans);font-size:var(--text-base);color:var(--text-muted)">No matching items</div>
275
+ <div v-if="!rows.length" style="padding:10px 8px;font-family:var(--font-sans);font-size:var(--control-text);line-height:var(--control-leading);color:var(--text-muted)">No matching items</div>
275
276
  </div>
276
277
  </template>
277
278
  <style scoped>
@@ -22,3 +22,5 @@ applyStoredTheme(); // call once at app start
22
22
  ```
23
23
 
24
24
  App chrome: `<Sidebar tone="recessed" version="Version 2.4.0" onSelect={…}/>` (items default to `KEYBRICKS_NAV`, footer to `KEYBRICKS_NAV_FOOTER`; `trailing: true` items open a `<SidePanel title="Documents" onClose={…}>` docked beside the rail — same `tone`) and `<TopBar user={{ name, email }} userMenu={<UserMenu … theme={t} onThemeChange={setT}/>}/>`.
25
+
26
+ `Tree` follows the size tier of its region (`data-size`): sm 28px rows / 12px text (13px CJK), md 32px / 14px, lg 40px. A node with `icon: false` draws no glyph and keeps no gap for one — use it for a root such as "Documents".
package/covers.js CHANGED
@@ -12,10 +12,11 @@ window.KB_COVERS = (function () {
12
12
  "action-chip": [1, (h, K) => row(h, 8, [h(K.ActionChip, { tone: "info" }, "Mark as New"), h(K.ActionChip, null, "Skip")])],
13
13
  "activity": [.85, (h, K) => h("div", { style: { width: 250 } }, h(K.ActivityItem, { icon: "upload", title: "Import finished", meta: "2 min ago" }), h(K.ActivityItem, { icon: "check", title: "Run completed", meta: "1 h ago" }))],
14
14
  "alert": [.8, (h, K) => h("div", { style: { width: 280 } }, h(K.Alert, { tone: "info", title: "Mapping saved" }, "3 fields were updated."))],
15
- "app-chrome": [.5, (h, K) => h("div", { style: { display: "flex", height: 260, width: 480, border: "1px solid var(--border-card)", borderRadius: "var(--radius-md)", overflow: "hidden" } }, h(K.Sidebar, { logo: "assets/keybricks-logo.png", active: "Home", items: [{ icon: "house", label: "Home" }, { icon: "file-text", label: "Documents", trailing: true }, { icon: "database", label: "Data Integration" }], footerItems: [{ icon: "settings", label: "Management", trailing: true }], style: { width: 180 } }), h("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", background: "var(--bg-app)" } }, h("div", { style: { height: 56, background: "var(--bg-surface)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", justifyContent: "flex-end", padding: "0 16px" } }, h(K.Button, { variant: "dark", icon: "ai" }, "AI Assistant"))))],
15
+ "app-chrome": [.5, (h, K) => h("div", { style: { display: "flex", height: 260, width: 480, border: "1px solid var(--border-card)", borderRadius: "var(--radius-md)", overflow: "hidden" } }, h(K.Sidebar, { logo: "assets/keybricks-logo.png", active: "Home", items: [{ icon: "house", label: "Home" }, { icon: "file-text", label: "Documents", trailing: true }, { icon: "database", label: "Data Integration" }], footerItems: [{ icon: "settings", label: "Management", trailing: true }], style: { width: 180 } }), h("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", background: "var(--bg-app)" } }, h("div", { style: { height: 56, background: "var(--bg-surface)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", padding: "0 16px" } }, h("div", { style: { display: "flex", alignItems: "center", gap: 8, height: 32, padding: "0 6px 0 10px", borderRadius: "var(--radius-md)", background: "var(--bg-inset)", color: "var(--text-muted)", fontFamily: "var(--font-sans)", fontSize: "var(--text-base)" } }, h(K.Icon, { name: "search", size: 16 }), h("span", { style: { paddingRight: 24 } }, "Search"), h(K.Kbd, { keys: ["mod", "K"] })))))],
16
16
  "banner": [.7, (h, K) => h("div", { style: { width: 340 } }, h(K.Banner, { tone: "warning", title: "Scheduled maintenance tonight", action: "Details" }))],
17
17
  "breadcrumb": [1, (h, K) => h(K.Breadcrumb, { items: ["Home", "Pipelines", "Import"] })],
18
18
  "button-1-base": [1, (h, K) => row(h, 8, [h(K.Button, { variant: "primary" }, "Save"), h(K.Button, { variant: "outline" }, "Cancel")])],
19
+ "button-5-ai": [1, (h, K) => h(K.Button, { variant: "ai" }, "Ask Prophet AI")],
19
20
  "button-4-group": [1, (h, K) => h(K.ButtonGroup, null, h(K.Button, { variant: "outline" }, "Day"), h(K.Button, { variant: "outline" }, "Week"), h(K.Button, { variant: "outline" }, "Month"))],
20
21
  "button-2-states": [1, (h, K) => row(h, 8, [h(K.Button, { variant: "primary", pressed: true }, "Pressed"), h(K.Button, { variant: "primary", disabled: true }, "Disabled")])],
21
22
  "button-3-sizes-icons": [1, (h, K) => row(h, 8, [h("div", { "data-size": "sm" }, h(K.Button, { variant: "outline", icon: "plus" }, "Add")), h(K.Button, { variant: "outline", icon: "plus" }, "Add"), h("div", { "data-size": "lg" }, h(K.Button, { variant: "outline", icon: "plus" }, "Add"))])],
@@ -36,7 +37,7 @@ window.KB_COVERS = (function () {
36
37
  "icon-button": [1.2, (h, K) => row(h, 4, [h(K.IconButton, { icon: "pencil-line", label: "Edit" }), h(K.IconButton, { icon: "copy", label: "Copy" }), h(K.IconButton, { icon: "ellipsis", label: "More" })])],
37
38
  "input": [1, (h, K) => h("div", { style: { width: 220 } }, h(K.Input, { value: "FIN_CURRENCY_DEFAULT", onChange: () => {} }))],
38
39
  "keyvalue": [.9, (h, K) => h("div", { style: { width: 240 } }, h(K.KeyValueList, { rows: [{ label: "Source", value: "Oracle EBS" }, { label: "Rows", value: "12,480" }, { label: "Status", value: "Ready" }] }))],
39
- "kbd": [1.3, (h, K) => h(K.Kbd, { keys: ["⌘", "K"] })],
40
+ "kbd": [1.3, (h, K) => h(K.Kbd, { keys: ["mod", "K"] })],
40
41
  "listrow": [.8, (h, K) => h("div", { style: { width: 280 } }, h(K.ListRow, { icon: "database", title: "Oracle EBS", meta: "Last sync 2 min ago" }))],
41
42
  "loading": [1, (h, K) => row(h, 16, [h(K.Spinner), h("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, h(K.Skeleton, { width: 140, height: 12 }), h(K.Skeleton, { width: 100, height: 12 }))])],
42
43
  "log-viewer": [.7, (h, K) => h("div", { style: { width: 320 } }, h(K.LogViewer, { lines: ["[14:30] Task started: Import", "[14:30] Reading ledger.csv", "[14:31] 12,480 rows written"], height: 90 }))],
@@ -49,6 +50,7 @@ window.KB_COVERS = (function () {
49
50
  "pipeline-palette": [.5, (h, K) => h(K.IconTile, { icon: "database", hue: "source" })],
50
51
  "radio": [1, (h, K) => col(h, 10, [h(K.Radio, { checked: true, label: "Overwrite" }), h(K.Radio, { checked: false, label: "Append" })])],
51
52
  "search": [1, (h, K) => h("div", { style: { width: 220 } }, h(K.SearchInput, { placeholder: "Search pipelines" }))],
53
+ "search-global": [.42, (h, K) => h(K.GlobalSearch, { inline: true, prompts: ["Which entity had the largest YoY revenue change in Q3?", "Explain how the FX model translates currencies"], recentSearches: ["revenue bridge", "FX rates"] })],
52
54
  "segmented-control": [1, (h, K) => h(K.SegmentedControl, { options: ["Grid", "List", "Board"], value: "Grid" })],
53
55
  "relative-time-picker": [1, (h, K) => h("div", { style: { width: 220 } }, h(K.RelativeTimePicker, { value: { amount: 24, unit: "Hour" } }))],
54
56
  "select": [1, (h, K) => h("div", { style: { width: 200 } }, h(K.Select, { options: ["Monthly", "Quarterly"], value: "Monthly" }))],
package/gallery.html CHANGED
@@ -32,7 +32,7 @@ h2:first-child{margin-top:0}
32
32
  <body>
33
33
  <header>
34
34
  <h1>Keybricks Design System</h1>
35
- <p class="sub">121 components in React and Vue 3, on one token layer. Every card below is the real component, not a screenshot.</p>
35
+ <p class="sub">122 components in React and Vue 3, on one token layer. Every card below is the real component, not a screenshot.</p>
36
36
  <div class="bar">
37
37
  <input type="search" id="q" placeholder="Filter components…" autocomplete="off">
38
38
  <span class="count" id="count"></span>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Brand" viewport="700x170" name="Logo & Wordmark" subtitle="Blue cube bitmap + Inter 600 wordmark, −0.609px tracking" -->
1
+ <!-- @dsCard group="Brand" viewport="700x162" name="Logo & Wordmark" subtitle="Blue cube bitmap + Inter 600 wordmark, −0.609px tracking" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-surface);display:flex;gap:12px;box-sizing:border-box}.p{flex:1;border:1px solid var(--border-card);border-radius:10px;display:flex;align-items:center;justify-content:center;gap:10px;height:128px}.p.dark{background:var(--neutral-950)}.wm{font-weight:600;font-size:15px;letter-spacing:-.609px;color:var(--text-primary)}.dark .wm{color:#fff}.cap{position:absolute;font-size:var(--text-xs)}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Colors" viewport="700x800" name="Schemes" subtitle="Sets that work together — surface, text, border, accent" -->
1
+ <!-- @dsCard group="Colors" viewport="700x783" name="Schemes" subtitle="Sets that work together — surface, text, border, accent" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <script src="_color-lab.js"></script>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Colors" viewport="700x490" name="Transparency" subtitle="Alpha scale — the number is the opacity" -->
1
+ <!-- @dsCard group="Colors" viewport="700x478" name="Transparency" subtitle="Alpha scale — the number is the opacity" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <script src="_color-lab.js"></script>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Foundations" viewport="700x190" name="Borders & Shadows" subtitle="Hairlines carry the UI; shadows only on canvas nodes" -->
1
+ <!-- @dsCard group="Foundations" viewport="700x176" name="Borders & Shadows" subtitle="Hairlines carry the UI; shadows only on canvas nodes" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-app);display:grid;grid-template-columns:repeat(4,1fr);gap:10px;box-sizing:border-box}.c{background:var(--bg-surface);border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:8px;justify-content:space-between}.n{font-size:var(--text-xs);font-weight:500;color:var(--text-heading)}.u{font-size:var(--text-xs);font-family:var(--font-sans);font-variant-numeric:tabular-nums;color:var(--text-muted)}.sw{height:56px;border-radius:10px;background:var(--bg-inset)}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Foundations" viewport="700x180" name="App Chrome Dimensions" subtitle="Fixed panel widths & bar heights" -->
1
+ <!-- @dsCard group="Foundations" viewport="700x164" name="App Chrome Dimensions" subtitle="Fixed panel widths & bar heights" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-app);box-sizing:border-box}.wrap{border:1px solid var(--border-card);border-radius:10px;overflow:hidden;display:flex;height:130px;font-size:var(--text-xs);font-family:var(--font-sans);font-variant-numeric:tabular-nums;color:var(--text-muted)}.cell{display:flex;align-items:center;justify-content:center;box-sizing:border-box}.col{display:flex;flex-direction:column;flex:1}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Foundations" viewport="700x170" name="Motion" subtitle="120/160/240ms · ease-out — hover, rise, pulse, spin" -->
1
+ <!-- @dsCard group="Foundations" viewport="700x152" name="Motion" subtitle="120/160/240ms · ease-out — hover, rise, pulse, spin" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-surface);display:grid;grid-template-columns:repeat(4,1fr);gap:10px;box-sizing:border-box}
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Foundations" viewport="700x1340" name="Size Tiers" subtitle="sm 28 · md 32 · lg 40 — one tier per region, never mixed in a row; CJK one step larger at sm" -->
1
+ <!-- @dsCard group="Foundations" viewport="700x1335" name="Size Tiers" subtitle="sm 28 · md 32 · lg 40 — one tier per region, never mixed in a row; CJK one step larger at sm" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Foundations" viewport="700x170" name="Spacing" subtitle="4px family · page 24×32 · card 21 · section gap 24 · gaps 8 inside a group, 12/16/24 between groups" -->
1
+ <!-- @dsCard group="Foundations" viewport="700x138" name="Spacing" subtitle="4px family · page 24×32 · card 21 · section gap 24 · gaps 8 inside a group, 12/16/24 between groups" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-app);box-sizing:border-box}.bars{display:flex;gap:14px;align-items:flex-end}.b{display:flex;flex-direction:column;gap:5px;align-items:center}.b i{display:block;background:var(--soft-bg);border:1px solid var(--soft-border);border-radius:3px}.b span{font-size:var(--text-xs);font-family:var(--font-sans);font-variant-numeric:tabular-nums;color:var(--text-muted)}.note{margin-top:12px;font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-muted)}.note b{color:var(--text-heading);font-weight:500}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Foundations" viewport="700x570" name="Interaction States" subtitle="The five states every control carries — and where each one is defined" -->
1
+ <!-- @dsCard group="Foundations" viewport="700x552" name="Interaction States" subtitle="The five states every control carries — and where each one is defined" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Type" viewport="700x440" name="Display Scale" subtitle="Display sizes 24–60 — tracking follows the same size→tracking curve" -->
1
+ <!-- @dsCard group="Type" viewport="700x388" name="Display Scale" subtitle="Display sizes 24–60 — tracking follows the same size→tracking curve" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:14px 16px;font-family:var(--font-sans);background:var(--bg-surface);box-sizing:border-box}.r{display:grid;grid-template-columns:150px 1fr 200px;gap:12px;align-items:baseline;padding:7px 0;border-bottom:1px solid var(--border-subtle)}.m{font-size:var(--text-xs);font-family:var(--font-sans);font-variant-numeric:tabular-nums;color:var(--text-muted)}.u{font-size:var(--text-xs);color:var(--text-secondary);text-align:right}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Type" viewport="700x170" name="Mono / Code Only" subtitle="Menlo for code blocks, logs, inline code and config-code chips — IDs and amounts stay in Inter with tabular figures" -->
1
+ <!-- @dsCard group="Type" viewport="700x187" name="Mono / Code Only" subtitle="Menlo for code blocks, logs, inline code and config-code chips — IDs and amounts stay in Inter with tabular figures" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-app);display:flex;gap:12px;box-sizing:border-box}.p{flex:1;min-width:0;border:1px solid var(--border-card);border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:8px}.cap{font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-muted)}.codeblk{background:var(--bg-inset);border-radius:8px;padding:8px 10px;font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-primary);white-space:pre}.log{background:var(--bg-inset);border-radius:8px;padding:8px 10px;font-family:var(--font-mono);font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-secondary);display:flex;flex-direction:column}.ui{font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-primary);font-variant-numeric:tabular-nums;display:flex;flex-direction:column}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Type" viewport="700x450" name="Type Scale" subtitle="Inter — the 14px scale: 12 captions · 14 body and controls · 16 section titles · 20 page titles; CJK one step larger below 14" -->
1
+ <!-- @dsCard group="Type" viewport="700x408" name="Type Scale" subtitle="Inter — the 14px scale: 12 captions · 14 body and controls · 16 section titles · 20 page titles; CJK one step larger below 14" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:14px 16px;font-family:var(--font-sans);background:var(--bg-surface);box-sizing:border-box}.r{display:grid;grid-template-columns:150px 1fr 190px;gap:12px;align-items:baseline;padding:5px 0;border-bottom:1px solid var(--border-subtle)}.m{font-size:var(--text-xs);font-family:var(--font-sans);font-variant-numeric:tabular-nums;color:var(--text-muted)}.u{font-size:var(--text-xs);color:var(--text-secondary);text-align:right}</style></head>
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Type" viewport="700x280" name="Inter Weights" subtitle="300 numerals · 400 body · 500 UI-medium · 600 titles — 500 becomes 600 in Chinese, Japanese and Korean" -->
1
+ <!-- @dsCard group="Type" viewport="700x264" name="Inter Weights" subtitle="300 numerals · 400 body · 500 UI-medium · 600 titles — 500 becomes 600 in Chinese, Japanese and Korean" -->
2
2
  <!DOCTYPE html>
3
3
  <html><head><meta charset="utf-8"><script src="../components/_shared/frame-theme.js"></script><link rel="stylesheet" href="../styles.css"><link rel="stylesheet" href="../tokens/hover.css">
4
4
  <style>body{margin:0;padding:16px;font-family:var(--font-sans);background:var(--bg-surface);display:grid;grid-template-columns:repeat(4,1fr);gap:10px;align-content:start;box-sizing:border-box}.w{border:1px solid var(--border-card);border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:2px}.w b{font-size:var(--text-xl);line-height:var(--leading-xl);letter-spacing:var(--tracking-xl);color:var(--text-primary)}.w span{font-size:var(--text-xs);line-height:var(--leading-xs);color:var(--text-secondary)}</style></head>
package/index.html CHANGED
@@ -113,7 +113,7 @@ section{margin-bottom:52px;scroll-margin-top:78px}
113
113
  .cl-new{background:var(--info-bg);color:var(--info-fg)}
114
114
  .cl-improved{background:var(--bg-hover);color:var(--text-body)}
115
115
  .cl-fixed{background:var(--success-bg);color:var(--success-text)}
116
- .cl-breaking{background:var(--danger-bg);color:var(--danger-text)}
116
+ .cl-breaking{background:var(--danger-bg);color:var(--danger-text)}.cl-rule{background:var(--warning-bg);color:var(--warning-text)}
117
117
  .cl-removed{background:var(--bg-hover);color:var(--text-secondary)}
118
118
  @media (max-width:720px){.cl-rel{grid-template-columns:minmax(0,1fr);gap:10px}.cl-head{flex-direction:row;align-items:baseline;gap:10px}}
119
119
 
@@ -176,7 +176,7 @@ section{margin-bottom:52px;scroll-margin-top:78px}
176
176
  const GROUPS=[["Brand","品牌","ブランド"],["Colors","颜色","カラー"],["Type","字体排印","タイポグラフィ"],["Foundations","基础规范","基盤仕様"],["Components","组件","コンポーネント"],["Charts","图表","チャート"],["Icons","图标库","アイコン"]];
177
177
 
178
178
  const S={
179
- brandsub:["Design System · v2.5.1","设计系统 · v2.5.1","デザインシステム · v2.5.1"],
179
+ brandsub:["Design System · v2.8.0","设计系统 · v2.8.0","デザインシステム · v2.8.0"],
180
180
  doc_readme:["Readme","说明文档","ドキュメント"],
181
181
  doc_design:["DESIGN.md","下载 DESIGN.md","DESIGN.md"],
182
182
  doc_integration:["Integration","接入指南","導入ガイド"],
@@ -196,9 +196,9 @@ filter_ph:["Filter…","筛选…","絞り込み…"],
196
196
  ov_eyebrow:["Overview","总览","概要"],
197
197
  ov_title:["Keybricks Design System","Keybricks 设计系统","Keybricks デザインシステム"],
198
198
  ov_lede:[
199
- "The design language of the Keybricks EPM platform: a near-monochrome, high-density enterprise UI built on one token layer, one action blue, and 121 components shipped for React and Vue 3. Every card on this page is the live component, rendered from the same source the product imports.",
200
- "Keybricks 企业绩效管理平台的设计语言:近乎单色、高密度的企业级界面,构建在同一套 token 之上,只有一个强调蓝,121 个组件同时提供 React 与 Vue 3 版本。本页每张卡片都是实时渲染的真实组件,与产品引用的是同一份源码。",
201
- "Keybricks EPM プラットフォームのデザイン言語:ほぼモノクロで高密度なエンタープライズ UI を、単一のトークン層と 1 色のアクションブルーで構築。121 個のコンポーネントを React と Vue 3 で提供します。本ページのカードはすべて、製品と同じソースから描画された実物のコンポーネントです。"],
199
+ "The design language of the Keybricks EPM platform: a near-monochrome, high-density enterprise UI built on one token layer, one action blue, and 122 components shipped for React and Vue 3. Every card on this page is the live component, rendered from the same source the product imports.",
200
+ "Keybricks 企业绩效管理平台的设计语言:近乎单色、高密度的企业级界面,构建在同一套 token 之上,只有一个强调蓝,122 个组件同时提供 React 与 Vue 3 版本。本页每张卡片都是实时渲染的真实组件,与产品引用的是同一份源码。",
201
+ "Keybricks EPM プラットフォームのデザイン言語:ほぼモノクロで高密度なエンタープライズ UI を、単一のトークン層と 1 色のアクションブルーで構築。122 個のコンポーネントを React と Vue 3 で提供します。本ページのカードはすべて、製品と同じソースから描画された実物のコンポーネントです。"],
202
202
  st_components:["Components","组件","コンポーネント"],
203
203
  st_icons:["Icons","图标","アイコン"],
204
204
  st_charts:["Chart types","图表类型","チャート種類"],
@@ -209,7 +209,7 @@ d_readme_x:["What the system is, in full — content voice, visual foundations,
209
209
  d_design:["DESIGN.md","DESIGN.md","DESIGN.md"],
210
210
  d_design_x:["The rules file for AI coding agents: absolute values, interaction states, an explicit do-not list.","给 AI 编程代理读的规则文件:绝对数值、交互状态、明确的禁止事项。","AI コーディングエージェント向けのルールファイル:絶対値、インタラクション状態、禁止事項。"],
211
211
  d_integration:["INTEGRATION.md","INTEGRATION.md","INTEGRATION.md"],
212
- d_integration_x:["Three steps to first paint, size tiers, import paths for all 121 components, token reference, versioning.","三步跑通首屏,尺寸层级,121 个组件的引入路径、token 速查、版本策略。","初回描画までの 3 ステップ、サイズ階層、全 121 コンポーネントの import パス、トークン早見表、バージョン方針。"],
212
+ d_integration_x:["Three steps to first paint, size tiers, import paths for all 122 components, token reference, versioning.","三步跑通首屏,尺寸层级,122 个组件的引入路径、token 速查、版本策略。","初回描画までの 3 ステップ、サイズ階層、全 122 コンポーネントの import パス、トークン早見表、バージョン方針。"],
213
213
  d_gallery:["gallery.html","gallery.html","gallery.html"],
214
214
  d_gallery_x:["Every card as a filterable thumbnail grid — the fastest way to find a component.","全部卡片的可筛选缩略图网格 — 找组件最快的入口。","全カードをフィルター可能なサムネイル一覧で — コンポーネントを最速で探せます。"],
215
215
  open_full:["open full size","查看原尺寸","原寸で開く"],
@@ -254,7 +254,7 @@ function renderOverview(){
254
254
  hero.appendChild(make("p","lede",S.ov_lede));
255
255
  s.appendChild(hero);
256
256
  const stats=document.createElement("div");stats.className="stats";
257
- [["121",S.st_components],["1,610",S.st_icons],["27",S.st_charts],["10",S.st_tokens],["React · Vue 3",S.st_fw]].forEach(([n,k])=>{
257
+ [["122",S.st_components],["1,610",S.st_icons],["27",S.st_charts],["10",S.st_tokens],["React · Vue 3",S.st_fw]].forEach(([n,k])=>{
258
258
  const d=document.createElement("div");d.className="stat";
259
259
  const nn=document.createElement("div");nn.className="n";nn.textContent=n;
260
260
  if(/[A-Za-z]/.test(n))nn.style.fontSize="var(--text-md)",nn.style.lineHeight="var(--leading-num)",nn.style.fontWeight="var(--weight-medium)";
@@ -347,7 +347,7 @@ function settleOn(target){
347
347
  }
348
348
 
349
349
  /* ---------- changelog (data: changelog.js) ---------- */
350
- const CL_TAGS={new:["New","新增","新規"],improved:["Improved","改进","改善"],fixed:["Fixed","修复","修正"],breaking:["Breaking","不兼容变更","互換性のない変更"],removed:["Removed","移除","削除"]};
350
+ const CL_TAGS={new:["New","新增","新規"],improved:["Improved","改进","改善"],fixed:["Fixed","修复","修正"],breaking:["Breaking","不兼容变更","互換性のない変更"],rule:["Team rule","团队规则","チームルール"],removed:["Removed","移除","削除"]};
351
351
  function renderChangelog(){
352
352
  const s=document.createElement("section");s.id="changelog";
353
353
  s.appendChild(make("h2","cl-title",S.nav_changelog));
@@ -472,7 +472,7 @@ function fit(f){
472
472
  const scale=avail<f.__w?avail/f.__w:1;
473
473
  const w=scale<1?f.__w:avail;
474
474
  let h=f.__h;
475
- try{const d=f.contentDocument;if(d&&d.documentElement)h=Math.max(h,d.documentElement.scrollHeight);}catch(e){}
475
+ try{const d=f.contentDocument,b=d&&d.body;if(b){const cs=d.defaultView.getComputedStyle(b);h=Math.max(h,Math.ceil(b.getBoundingClientRect().height+parseFloat(cs.marginTop)+parseFloat(cs.marginBottom)));}}catch(e){}
476
476
  f.style.width=w+"px";f.style.height=h+"px";
477
477
  f.style.transform=scale<1?"scale("+scale+")":"none";
478
478
  wrap.style.height=Math.round(h*scale)+"px";
@@ -488,7 +488,7 @@ function loadFrame(f){
488
488
  if(f.__ph)f.__ph.remove();
489
489
  pushTheme(f);fit(f);
490
490
  [120,400,1000,2000].forEach(d=>setTimeout(()=>{pushTheme(f);fit(f);},d));
491
- try{new f.contentWindow.ResizeObserver(()=>fit(f)).observe(f.contentDocument.documentElement);}catch(err){}
491
+ try{new f.contentWindow.ResizeObserver(()=>fit(f)).observe(f.contentDocument.body);}catch(err){}
492
492
  });
493
493
  f.src=f.dataset.src;f.removeAttribute("data-src");
494
494
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@keyfunc/keybricks-ds",
3
- "version": "2.6.0",
4
- "description": "Keybricks design system — design tokens, three size tiers and 121 UI components in React and Vue 3, source-only.",
3
+ "version": "2.8.0",
4
+ "description": "Keybricks design system — design tokens, three size tiers and 122 UI components in React and Vue 3, source-only.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "sideEffects": [
@@ -14,12 +14,12 @@
14
14
  },
15
15
  "./vue": "./components/_vue/index.mjs",
16
16
  "./vue/message": {
17
- "types": "./components/feedback/message.d.ts",
18
- "default": "./components/feedback/message.js"
17
+ "types": "./_vue-services/message.d.ts",
18
+ "default": "./_vue-services/message.js"
19
19
  },
20
20
  "./vue/message-box": {
21
- "types": "./components/feedback/message-box.d.ts",
22
- "default": "./components/feedback/message-box.js"
21
+ "types": "./_vue-services/message-box.d.ts",
22
+ "default": "./_vue-services/message-box.js"
23
23
  },
24
24
  "./styles.css": "./keybricks.css",
25
25
  "./keybricks.css": "./keybricks.css",
@@ -39,6 +39,7 @@
39
39
  "tokens",
40
40
  "assets",
41
41
  "_scripts",
42
+ "_vue-services",
42
43
  "styles.css",
43
44
  "keybricks.css",
44
45
  "readme.md",
package/readme.md CHANGED
@@ -34,7 +34,7 @@ One product: the Keybricks web app (desktop, 1512×~860 design size). Key surfac
34
34
  - **Backgrounds & imagery**: no photography, no illustration. The pipeline canvas is #fafafa with a subtle dot/curve grid; chart areas use soft blue gradient fills. Only bitmap: the cube logo.
35
35
  - **States**: every interactive element carries five states beyond rest. **Hover** moves the fill one step (`--bg-hover` wash on ghost items, `--action-primary-hover` on solid buttons, `--soft-hover` on tinted ones); controls whose colours are inline get it from the hover hooks in `tokens/hover.css`. **Press** moves it a second step: Button and IconButton use explicit tokens (`--action-primary-active`, `--action-dark-active`, `--bg-press`, `--soft-active`, `--danger-active`, `--danger-soft-active`) and opt out of the global layer with `data-press="own"`; every other control — nav rows, tree items, menu items, chips, tabs, list rows, option rows, palette tiles — gets press from the one global rule in `tokens/interaction.css` (`filter: var(--press-filter)` on `:active`, which multiplies whatever wash hover is already showing, and brightens rather than darkens in dark mode). No scale transforms, no shadow shifts; text-only buttons drop to 70% opacity instead. **Keyboard focus** is also global: a 2px `--focus-border` outline at 2px offset on `:focus-visible` only, so a mouse click never draws it. **Selected/active** is persistent, not transient: active nav = `--bg-active` pill + heading-weight text; selected node = blue border + ring. **Disabled** is 55% opacity (50% on icon buttons) with the default cursor.
36
36
  - **Motion**: kept minimal by design (see Motion below) — 120–160ms ease-out on hover/selection, nothing bouncy or far-traveling.
37
- - **Layout chrome**: left sidebar 240px (collapsible to a 64px icon rail), 56px top bar (search left; black "AI Assistant" pill, bell, help and the user menu right), sidebar tones recessed (grey, default) · flush · contrast · custom, optional 240px secondary panel (Documents tree, pipeline palette), 400px right config panel, 250px bottom data-preview drawer.
37
+ - **Layout chrome**: left sidebar 240px (collapsible to a 64px icon rail), 56px top bar (GlobalSearch left — ⌘K / Ctrl K, Prophet AI hand-off; bell, help and the user menu right), sidebar tones recessed (grey, default) · flush · contrast · custom, optional 240px secondary panel (Documents tree, pipeline palette), 400px right config panel, 250px bottom data-preview drawer.
38
38
  - **Cards**: white, radius 10, hairline border, 21px padding, 14px/500 title — never elevated.
39
39
  - **Density**: high; table rows 32 (sm) · 40 (md) · 44 (lg); header cells the same size as body cells in weight 600, sentence case; amount cells at the row's size with tabular figures; config codes as 12px code chips.
40
40
 
@@ -56,8 +56,8 @@ One product: the Keybricks web app (desktop, 1512×~860 design size). Key surfac
56
56
  ## Dark mode
57
57
  - Apply with `<html data-theme="dark">`; every component reads semantic aliases only, so nothing else changes. Toggle it live in the UI kit from the top bar or the sidebar's **Dark Mode** item (persisted to `localStorage("kb-theme")`). `applyStoredTheme()` restores it at app start.
58
58
  - **Primary blue in dark**: on the #0a0a0a canvas the light-theme blue reads murky, and a brighter #2b7fff cannot carry white 14px type (3.8:1, below AA). Dark mode therefore uses **`#1f6feb`** — 4.3:1 against the canvas, 4.6:1 for its white label, both passing AA, in the same hue family (~214°) one step lower in luminance. The light theme keeps `#155dfc`.
59
- - **Other shifts**: four surface steps (#0a0a0a app / #161616 surface / #1d1d1d raised / #1f1f1f inset); borders `rgba(255,255,255,.09)`; the dark "AI Assistant" pill inverts to light-on-dark (`--action-dark-fg`); category and status tints become low-alpha washes of the same hues; tooltips invert; shadows deepen rather than glow.
60
- - **Foreground on filled surfaces**: text and icons sitting on a saturated fill use `--on-accent`, which stays white in both themes; the neutral "AI Assistant" pill uses `--action-dark-fg`, which inverts with the theme. Never use `--text-inverse` for this — it is the inverse of body text and flips to near-black on dark backgrounds.
59
+ - **Other shifts**: four surface steps (#0a0a0a app / #161616 surface / #1d1d1d raised / #1f1f1f inset); borders `rgba(255,255,255,.09)`; the dark pill (`Button variant="dark"`) inverts to light-on-dark (`--action-dark-fg`); category and status tints become low-alpha washes of the same hues; tooltips invert; shadows deepen rather than glow.
60
+ - **Foreground on filled surfaces**: text and icons sitting on a saturated fill use `--on-accent`, which stays white in both themes; the neutral dark pill uses `--action-dark-fg`, which inverts with the theme. Never use `--text-inverse` for this — it is the inverse of body text and flips to near-black on dark backgrounds.
61
61
  - **Status**: the dark palette is an original derivation of the light one, validated for contrast rather than copied from a dark-theme design. Confirm it against your intended dark spec before production use.
62
62
  - **Authoring rule**: never reference `--neutral-*` / `--blue-*` directly in a component. Use the semantic layer (`--bg-surface`, `--bg-raised`, `--text-body`, `--border-card`, `--track`, `--soft-bg`, `--info-bg`, `--on-accent`, `--port-border`, `--dropzone-border`, `--ring-surface`, `--tooltip-bg`, …) so both themes work for free.
63
63
 
@@ -69,7 +69,7 @@ One product: the Keybricks web app (desktop, 1512×~860 design size). Key surfac
69
69
 
70
70
  **For developers integrating this system**
71
71
  - `DESIGN.md` — the rules file for AI coding agents: absolute token values, interaction states, an explicit "do not" list, and voice. Point Claude Code / Cursor / Copilot at this before they generate UI.
72
- - `INTEGRATION.md` — the integration guide: three steps to first paint, the full 121-component index with import paths, token reference, dark mode, interaction states, versioning.
72
+ - `INTEGRATION.md` — the integration guide: three steps to first paint, the full 122-component index with import paths, token reference, dark mode, interaction states, versioning.
73
73
  - `DEPLOY.md` — running the system on GitLab: what ships in the package and what stays on Pages, the entry points, the release flow, and the bundler config each consumer needs.
74
74
  - `index.html` · `gallery.html` — the documentation site: the browsable system and the filterable thumbnail grid, both deployed to GitLab Pages by CI.
75
75
  - `package.json` · `.gitlab-ci.yml` · `_scripts/` — makes the system an installable package: a version tag publishes to the GitLab Package Registry, the default branch redeploys the docs site, and `npm run check` fails the pipeline if the generated tokens or barrels drift from source.
package/readme.zh-CN.md CHANGED
@@ -36,7 +36,7 @@ Keybricks 是面向财务团队的企业绩效管理(EPM)平台:文档与
36
36
  - **背景与图像**:不用摄影图,不用插画。管道画布为 #fafafa 底配淡淡的点状 / 曲线网格;图表区域用柔和的蓝色渐变填充。唯一的位图是立方体 Logo。
37
37
  - **交互状态**:每个可交互元素在静默态之外都有五种状态。**悬停**让填充加深一档(幽灵按钮类元素用 `--bg-hover`,实心按钮用 `--action-primary-hover`,浅色底按钮用 `--soft-hover`);颜色写在内联样式里的控件,悬停效果来自 `tokens/hover.css` 中的悬停钩子。**按下**再加深一档:Button 与 IconButton 使用专门的 token(`--action-primary-active`、`--action-dark-active`、`--bg-press`、`--soft-active`、`--danger-active`、`--danger-soft-active`),并通过 `data-press="own"` 退出全局层;其余所有控件——导航行、树节点、菜单项、标签、标签页、列表行、选项行、面板磁贴——由 `tokens/interaction.css` 中的一条全局规则提供按下态(`:active` 时加上 `filter: var(--press-filter)`,在悬停底色之上再叠加一档,深色模式下方向为提亮)。不做缩放,不改阴影;纯文字按钮改为降到 70% 不透明度。**键盘聚焦**同样是全局的:仅在 `:focus-visible` 时绘制 2px `--focus-border` 描边(偏移 2px),鼠标点击不会出现。**选中 / 激活**是持续态而非瞬时态:激活的导航项 = `--bg-active` 胶囊 + 标题字重;选中的节点 = 蓝色边框 + 光环。**禁用**为 55% 不透明度(图标按钮 50%),使用默认光标。
38
38
  - **动效**:刻意克制(见下方"动效"一节)——悬停 / 选中 120–160ms 缓出,不弹跳,不大幅位移。
39
- - **布局框架**:左侧边栏 240px(可收起为 64px 图标栏);顶栏 56px(左侧搜索,右侧铃铛 + 黑色 "AI Assistant" 胶囊);可选的 240px 二级面板(文档树、管道组件面板);右侧配置面板 400px;底部数据预览抽屉 250px。
39
+ - **布局框架**:左侧边栏 240px(可收起为 64px 图标栏);顶栏 56px(左侧全局搜索 GlobalSearch,⌘K / Ctrl K 唤起、可转交方知;右侧铃铛、帮助和用户菜单);可选的 240px 二级面板(文档树、管道组件面板);右侧配置面板 400px;底部数据预览抽屉 250px。
40
40
  - **卡片**:白底、10px 圆角、细边框、21px 内边距、14px / 500 字重标题——从不使用投影抬高。
41
41
  - **密度**:高密度;表格行高 32(sm)· 40(md)· 44(lg);表头与单元格同字号、字重 600、句首大写;金额单元格与所在行同字号、同字体,只加等宽数字(tabular figures);配置代码用 12px 代码标签。等宽字体只用于代码。
42
42
 
@@ -58,8 +58,8 @@ Keybricks 是面向财务团队的企业绩效管理(EPM)平台:文档与
58
58
  ## 深色模式
59
59
  - 在 `<html>` 上加 `data-theme="dark"` 即可;所有组件只读取语义别名,其他什么都不用改。可在 UI kit 的顶栏或侧边栏 **Dark Mode** 项实时切换(持久化到 `localStorage("kb-theme")`)。应用启动时调用 `applyStoredTheme()` 恢复。
60
60
  - **深色模式主色**:在 #0a0a0a 画布上,浅色主题的蓝色显得浑浊,而更亮的 #2b7fff 又无法承载 14px 白色文字(3.8:1,未达 AA)。因此深色模式使用 **`#1f6feb`**——与画布对比 4.3:1,白色文字对比 4.6:1,均达 AA,与浅色主题同属约 214° 色相,亮度低一档。浅色主题保持 `#155dfc`。
61
- - **其他差异**:四级表面层次(#0a0a0a 应用层 / #161616 表面层 / #1d1d1d 浮起层 / #1f1f1f 内嵌层);边框 `rgba(255,255,255,.09)`;深色 "AI Assistant" 胶囊反转为浅底深字(`--action-dark-fg`);分类色与状态色变为同色相的低透明度色块;提示气泡反色;阴影加深而不是发光。
62
- - **填充色上的前景色**:位于饱和色填充之上的文字与图标使用 `--on-accent`,两套主题下都是白色;中性色的 "AI Assistant" 胶囊使用 `--action-dark-fg`,随主题反转。这里绝不能用 `--text-inverse`——它是正文颜色的反色,在深色背景上会变成近黑色。
61
+ - **其他差异**:四级表面层次(#0a0a0a 应用层 / #161616 表面层 / #1d1d1d 浮起层 / #1f1f1f 内嵌层);边框 `rgba(255,255,255,.09)`;深色胶囊按钮(`Button variant="dark"`)反转为浅底深字(`--action-dark-fg`);分类色与状态色变为同色相的低透明度色块;提示气泡反色;阴影加深而不是发光。
62
+ - **填充色上的前景色**:位于饱和色填充之上的文字与图标使用 `--on-accent`,两套主题下都是白色;中性色的深色胶囊按钮使用 `--action-dark-fg`,随主题反转。这里绝不能用 `--text-inverse`——它是正文颜色的反色,在深色背景上会变成近黑色。
63
63
  - **成熟度**:深色调色板是从浅色体系独立推导而来的,做过对比度验证,但并非照搬现成的深色设计稿。正式上线前,请与团队预期的深色规范核对。
64
64
  - **开发规范**:组件中绝不直接引用 `--neutral-*` / `--blue-*`。一律使用语义层(`--bg-surface`、`--bg-raised`、`--text-body`、`--border-card`、`--track`、`--soft-bg`、`--info-bg`、`--on-accent`、`--port-border`、`--dropzone-border`、`--ring-surface`、`--tooltip-bg` 等),这样两套主题自动生效。
65
65
 
@@ -71,7 +71,7 @@ Keybricks 是面向财务团队的企业绩效管理(EPM)平台:文档与
71
71
 
72
72
  **开发团队接入入口**
73
73
  - `DESIGN.md` —— 给 AI 编程代理读的规则文件:绝对数值、交互状态、明确的"禁止"清单、文案语气。让 Claude Code / Cursor / Copilot 在生成界面前先读它。
74
- - `INTEGRATION.md` —— 接入指南:三步跑通首屏、全部 121 个组件的清单与引入路径、token 速查、深色模式、交互状态、版本策略。
74
+ - `INTEGRATION.md` —— 接入指南:三步跑通首屏、全部 122 个组件的清单与引入路径、token 速查、深色模式、交互状态、版本策略。
75
75
  - `DEPLOY.md` —— 在 GitLab 上运行本系统:包里发布什么、什么留在 Pages 上、入口点、发布流程、各消费方需要的构建配置。
76
76
  - `index.html` · `gallery.html` —— 文档站:可浏览的系统主页与可筛选的缩略图网格,均由 CI 部署到 GitLab Pages。
77
77
  - `package.json` · `.gitlab-ci.yml` · `_scripts/` —— 让本系统成为可安装的包:打版本 tag 即发布到 GitLab Package Registry,默认分支更新即重新部署文档站,生成的 token 或入口文件与源码不一致时 `npm run check` 会让流水线失败。