@keyfunc/keybricks-ds 2.4.8 → 2.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DEPLOY.md CHANGED
@@ -55,7 +55,7 @@ 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.4.8 && git push --tags
58
+ git tag v2.4.10 && git push --tags
59
59
  ```
60
60
 
61
61
  That tag runs `generated:check` → `version:check` → `npm publish`. Confirm under *Deploy →
@@ -90,15 +90,18 @@ and `npm pack` both produce it via the `prepack` hook; CI does it explicitly. Re
90
90
  is a normal committed file.
91
91
 
92
92
  Published (`files` in `package.json`): `components/`, `tokens/`, `assets/`, `_scripts/`,
93
- `styles.css`, `keybricks.css` (the `styles.css` export: tokens + `tokens/hover.css`), the four `.md` guides plus `readme.zh-CN.md`, `_adherence.oxlintrc.json`.
93
+ `styles.css`, `keybricks.css` (the `styles.css` export: tokens + `tokens/hover.css`), the four `.md` guides plus `readme.zh-CN.md`, `_adherence.oxlintrc.json` —
94
+ and, as text for AI coding agents in a consuming app, the documentation pages: `index.html`, `gallery.html`, `guidelines/`, `changelog.js`, `site-nav.js`, `covers.js`
95
+ (the component cards are already under `components/_cards/`).
94
96
 
95
97
  > Installing from a **git tag** skips `prepack`, so `@keyfunc/keybricks-ds/vue` is absent in
96
98
  > that mode — Vue apps on a git dependency should deep-import
97
99
  > `@keyfunc/keybricks-ds/components/<group>/<Name>.vue`, which is the recommended path anyway.
98
100
 
99
- Not published: `guidelines/`, `index.html`, `gallery.html`,
100
- `_ds_bundle.js`. Those are the documentation site — they go to Pages, not into every
101
- `node_modules`.
101
+ Not published: `_ds_bundle.js` — the compiled copy of every component that the documentation pages run on.
102
+ It repeats each component in compiled form (read through `window.KeybricksDesignSystem_…`, never how an app imports it), adds ~1.8 MB to every install,
103
+ and would mislead an agent searching the package. So the pages ship as readable source but do not open from `node_modules`;
104
+ to view them, use the Pages site (§5). Apps always `import { … } from '@keyfunc/keybricks-ds'`.
102
105
 
103
106
  ## 2. Entry points
104
107
 
@@ -184,7 +187,7 @@ GitLab injects `CI_JOB_TOKEN` — use that instead and no secret is stored anywh
184
187
  **Install — straight from git** (no registry, no publish; works today)
185
188
 
186
189
  ```json
187
- "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.4.8"
190
+ "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.4.10"
188
191
  ```
189
192
 
190
193
  Because the package has no build step, a git dependency needs no `prepare` script — npm
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.4.8"
34
+ "@keyfunc/keybricks-ds": "git+ssh://git@gitlab.epm2demo.cn/Felix/keybricks-ds.git#v2.4.10"
35
35
  ```
36
36
 
37
37
  **Source-only package.** `.jsx` and `.vue` files are published as authored, so your
@@ -521,6 +521,16 @@ Pin a minor range and update deliberately:
521
521
  - **Tokens outside CSS.** `tokens.json` / `tokens.js` / `tokens.d.ts` gained the tier tokens
522
522
  (`--control-*`, `--bar-h`, `--group-gap`, …) — 352 light tokens in all (2.0.2 adds `--danger-soft-hover`).
523
523
 
524
+ ### 2.4.10
525
+
526
+ - **The npm package carries the documentation pages** — `index.html`, `gallery.html`, `guidelines/`, `changelog.js`, `site-nav.js`, `covers.js` — as readable text for AI coding agents in your app (the component cards were already under `components/_cards/`). `_ds_bundle.js` stays out: it is the compiled copy the pages run on, so the pages do not open from `node_modules` — view them on the Pages site. Apps still `import { … } from '@keyfunc/keybricks-ds'`.
527
+
528
+ ### 2.4.9
529
+
530
+ - **Inter is hosted locally.** `tokens/fonts.css` loads the WOFF2 files shipped in the package instead of Google Fonts — weights 300–700, italic 400, `font-display: swap`, as before. The stylesheet entry points are unchanged.
531
+ - The fonts and their SIL Open Font License 1.1 live in `assets/fonts/inter/`. Your bundler must resolve the relative font URLs in the CSS and emit the font files, served from the app's own origin; if you deploy the CSS as-is, keep `tokens/` and `assets/` side by side. CSP `font-src 'self'` is enough — no external domain to allow.
532
+ - Takes effect once the app installs this version and redeploys its front-end assets.
533
+
524
534
  ### 2.4.8
525
535
 
526
536
  (2.4.7 on `main` was a version-number bump only.)
@@ -0,0 +1,92 @@
1
+ Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION AND CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,13 @@
1
+ # Inter 本地字体
2
+
3
+ 来源:[Inter 官方 v4.1](https://github.com/rsms/inter/releases/tag/v4.1)。
4
+ 从该版本的 `docs/font-files/` 下载原始 WOFF2,未修改字体内容。
5
+ 许可证:[SIL Open Font License 1.1](./LICENSE.txt),随字体一同分发。
6
+
7
+ `tokens/fonts.css` 通过相对路径加载字体,应用部署后不再请求 Google Fonts。
8
+ 常规字体声明 300–700 字重,斜体声明 400 字重,与原在线字体配置保持一致。
9
+
10
+ | 文件 | 字节数 | SHA-256 |
11
+ | --- | ---: | --- |
12
+ | `InterVariable.woff2` | 352240 | `693b77d4f32ee9b8bfc995589b5fad5e99adf2832738661f5402f9978429a8e3` |
13
+ | `InterVariable-Italic.woff2` | 387976 | `e564f652916db6c139570fefb9524a77c4d48f30c92928de9db19b6b5c7a262a` |
package/changelog.js ADDED
@@ -0,0 +1,91 @@
1
+ /* Keybricks changelog — the source for the Changelog section of index.html. Newest first.
2
+ Each release: v, date (ISO, "" when not recorded), status ("unreleased" until it is tagged), items.
3
+ Each item: tag (new | improved | fixed | breaking | removed) and the text as [en, zh, ja].
4
+ INTEGRATION.md keeps the full migration notes; this list is the short, reader-facing summary. */
5
+ window.KB_CHANGELOG = [
6
+ { v: "2.4.10", date: "2026-10-28", items: [
7
+ { tag: "improved", t: ["The npm package now includes the documentation pages (<code>index.html</code>, <code>gallery.html</code>, <code>guidelines/</code>) as text that AI coding agents in your app can read. To view them, use the documentation site.", "npm 包现在包含文档网页(<code>index.html</code>、<code>gallery.html</code>、<code>guidelines/</code>),业务项目里的 AI 编程助手可以直接读取。浏览网页请继续使用文档站。", "npm パッケージにドキュメントページ(<code>index.html</code>、<code>gallery.html</code>、<code>guidelines/</code>)を同梱。アプリ側の AI コーディングエージェントがテキストとして読める。閲覧はドキュメントサイトで。"] },
8
+ ] },
9
+ { v: "2.4.9", date: "2026-10-28", items: [
10
+ { tag: "fixed", t: ["Inter fonts are bundled as local WOFF2 assets, removing the Google Fonts request in offline and CSP-restricted environments.", "Inter 字体改为随包分发的本地 WOFF2 资源,移除 Google Fonts 请求,适用于离线及 CSP 受限环境。", "Inter をローカル WOFF2 として同梱し、オフライン環境と CSP 制限環境での Google Fonts リクエストを解消。"] }
11
+ ] },
12
+ { v: "2.4.8", date: "2026-10-26", items: [
13
+ { tag: "new", t: ["<code>Table</code> <code>pinSelected</code>: checked rows move to the top. Two styles — a grey band with a divider, or <code>\"labels\"</code> with group rows “Selected · n” (with Clear) and “Others · n”.", "<code>Table</code> 新增 <code>pinSelected</code>:勾选的行置顶。两种样式——灰色底加分隔线,或 <code>\"labels\"</code> 分组标签(“Selected · n”带 Clear,以及 “Others · n”)。", "<code>Table</code> に <code>pinSelected</code> を追加:チェックした行を先頭へ。グレーの帯と区切り線、または <code>\"labels\"</code> のグループ行(「Selected · n」と Clear、「Others · n」)の 2 種類。"] },
14
+ { tag: "new", t: ["<code>Table</code> locked rows: <code>isRowDisabled(row, index)</code> disables a row's checkbox, <code>disabledReason</code> is its tooltip. Select-all skips locked rows; with <code>pinSelected=\"labels\"</code> they form an “Unavailable · n” group.", "<code>Table</code> 新增锁定行:<code>isRowDisabled(row, index)</code> 禁用该行勾选框,<code>disabledReason</code> 为提示文字。全选会跳过锁定行;配合 <code>pinSelected=\"labels\"</code> 时锁定行单独成 “Unavailable · n” 一组。", "<code>Table</code> にロック行を追加:<code>isRowDisabled(row, index)</code> で行のチェックボックスを無効化、<code>disabledReason</code> がツールチップ。全選択はロック行を除外し、<code>pinSelected=\"labels\"</code> では「Unavailable · n」グループになる。"] },
15
+ { tag: "breaking", t: ["With <code>isRowDisabled</code>, use the third argument of <code>onToggle(\"all\", checked, next)</code> — the selection after Select-all or Clear, locked rows untouched.", "使用 <code>isRowDisabled</code> 时,请用 <code>onToggle(\"all\", checked, next)</code> 的第三个参数——全选或清除后的选中结果,锁定行保持不变。", "<code>isRowDisabled</code> を使う場合は <code>onToggle(\"all\", checked, next)</code> の第 3 引数を使用:全選択/クリア後の選択結果(ロック行はそのまま)。"] },
16
+ { tag: "new", t: ["<code>SmartTable</code> and <code>Spreadsheet</code>: drag a column header's right edge to resize it (<code>resizable</code>, on by default).", "<code>SmartTable</code> 和 <code>Spreadsheet</code> 可拖动列头右边缘调整列宽(<code>resizable</code>,默认开启)。", "<code>SmartTable</code> と <code>Spreadsheet</code> で列ヘッダーの右端をドラッグして列幅を変更(<code>resizable</code>、既定でオン)。"] },
17
+ { tag: "fixed", t: ["<code>Table</code> column resize follows the cursor, and <code>onColumnResize</code> fires on every drag whether or not you pass <code>columnWidths</code>.", "<code>Table</code> 拖动列宽时与鼠标位置一致;无论是否传入 <code>columnWidths</code>,每次拖动都会触发 <code>onColumnResize</code>。", "<code>Table</code> の列幅ドラッグがカーソルに追従。<code>columnWidths</code> の有無にかかわらず、ドラッグのたびに <code>onColumnResize</code> が呼ばれる。"] },
18
+ { tag: "improved", t: ["<code>Switch</code> has two sizes: sm 28×16, md and lg 32×18. Text inside the pill is never covered by the knob. <code>Tag</code> and count badges also keep the md size at lg.", "<code>Switch</code> 只保留两种尺寸:sm 28×16,md 和 lg 32×18;开关里的文字不再被圆点挡住。<code>Tag</code> 和计数小标在 lg 下也沿用 md 尺寸。", "<code>Switch</code> は 2 サイズに:sm 28×16、md・lg 32×18。内側のテキストがノブに隠れない。<code>Tag</code> とカウントバッジも lg では md サイズ。"] },
19
+ { tag: "improved", t: ["Table card: every common cell type — Badge, Tag, Avatar, progress, Sparkline, Switch, Select, Input, DatePicker — with sizes per tier.", "Table 卡片补充常用单元格类型:Badge、Tag、Avatar、进度条、Sparkline、Switch、Select、Input、DatePicker,并列出各尺寸。", "Table カードに主なセル種別を追加:Badge、Tag、Avatar、進捗、Sparkline、Switch、Select、Input、DatePicker と各サイズ。"] },
20
+ { tag: "improved", t: ["The table code chip has a darker background. New icon <code>ownership</code>; <code>dimension-intercompany</code> redrawn.", "表格 code chip 底色加深。新增图标 <code>ownership</code>,重绘 <code>dimension-intercompany</code>。", "テーブルのコードチップの背景を濃く。アイコン <code>ownership</code> を追加、<code>dimension-intercompany</code> を描き直し。"] },
21
+ { tag: "fixed", t: ["<code>Breadcrumb</code> trails with repeated names (“Workflow › Workflow”) now show every level.", "<code>Breadcrumb</code> 路径中有重名时(如 “Workflow › Workflow”)现在每一级都会显示。", "<code>Breadcrumb</code> で同名の階層(「Workflow › Workflow」)もすべて表示。"] },
22
+ ] },
23
+ { v: "2.4.6", date: "2026-10-25", items: [
24
+ { tag: "new", t: ["75 business glyphs join the core icon set, named as the product uses them: <code>dimension-*</code>, modules such as <code>modeling</code>, <code>analytics</code>, <code>expense_control-*</code>, <code>profile-*</code>, plus <code>rules-*</code> (sheet frame) and <code>task-*</code> (clipboard frame). Each has English and Chinese search tags.", "75 个业务图标加入核心图标集,名称与产品一致:<code>dimension-*</code>、<code>modeling</code>、<code>analytics</code>、<code>expense_control-*</code>、<code>profile-*</code> 等模块图标,以及 <code>rules-*</code>(草纸框)和 <code>task-*</code>(剪贴板框)。每个图标都有中英文搜索标签。", "75 個の業務アイコンをコアセットに追加。名前はプロダクトと同じ:<code>dimension-*</code>、<code>modeling</code>、<code>analytics</code>、<code>expense_control-*</code>、<code>profile-*</code> などのモジュール、<code>rules-*</code>(シート枠)と <code>task-*</code>(クリップボード枠)。各アイコンに英語・中国語の検索タグ付き。"] },
25
+ { tag: "removed", t: ["<code>sparkles</code> leaves the core set — use <code>ai-sparkles</code> for AI actions. The dark-mode toggle now shows <code>sun</code>.", "<code>sparkles</code> 移出核心集,AI 操作请用 <code>ai-sparkles</code>。深色模式切换按钮改为显示 <code>sun</code>。", "<code>sparkles</code> をコアセットから削除。AI 操作には <code>ai-sparkles</code> を使用。ダークモード切替は <code>sun</code> を表示。"] },
26
+ { tag: "improved", t: ["<code>box</code> is now <code>model</code>; <code>box</code> still works as a legacy alias.", "<code>box</code> 更名为 <code>model</code>;<code>box</code> 仍作为旧名兼容。", "<code>box</code> は <code>model</code> に改名。<code>box</code> も旧名として引き続き使用可。"] },
27
+ ] },
28
+ { v: "2.4.4", date: "2026-10-24", items: [
29
+ { tag: "improved", t: ["<code>Tree</code> with <code>reorder</code> now reorders files too: a file's top half means before, its bottom half after. The insert marker is a 2px line with a dot, drawn between rows from the target's indent, so you can see which level the item lands on.", "<code>Tree</code> 开启 <code>reorder</code> 后文件之间也能排序:文件上半部分表示插到前面,下半部分插到后面。插入标记是一条带圆点的 2px 线,画在两行之间,从目标的缩进处开始,能看出会落在哪一层。", "<code>Tree</code> の <code>reorder</code> でファイル同士の並べ替えも可能に:ファイルの上半分は前へ、下半分は後ろへ。挿入マーカーは行間に引くドット付きの 2px 線で、ターゲットのインデントから始まるため、どの階層に入るかが分かる。"] },
30
+ ] },
31
+ { v: "2.4.3", date: "2026-10-23", items: [
32
+ { tag: "improved", t: ["<code>SmartTable</code> freezes its edges like <code>Spreadsheet</code>: the header row stays while the body scrolls, the row-number column stays while scrolling sideways, the corner holds on both axes — at every tier and density.", "<code>SmartTable</code> 像 <code>Spreadsheet</code> 一样冻结边缘:纵向滚动时表头不动,横向滚动时行号列不动,左上角单元格两个方向都固定——所有尺寸和密度都适用。", "<code>SmartTable</code> が <code>Spreadsheet</code> と同様にエッジを固定:縦スクロールでヘッダー行、横スクロールで行番号列が留まり、左上のセルは両軸で固定 — すべてのサイズと密度で。"] },
33
+ ] },
34
+ { v: "2.4.2", date: "2026-10-23", items: [
35
+ { tag: "new", t: ["<code>RelativeTimePicker</code>: filter by how long ago (minutes to months, or any time) — a field-shaped trigger with a small dialog and a live “From” preview. Contributed by the app team and brought onto the system rules.", "<code>RelativeTimePicker</code>:按「多久以前」筛选(分钟到月,或不限时间)——字段样式的触发器加小弹层,实时显示起始时间。由业务团队贡献,已按系统规范整理。", "<code>RelativeTimePicker</code>:「どれくらい前」で絞り込み(分〜月、または無制限)。フィールド型トリガーと小さなダイアログ、開始時刻のライブプレビュー付き。アプリチームの貢献をシステムのルールに合わせて整理。"] },
36
+ ] },
37
+ { v: "2.4.1", date: "2026-10-23", items: [
38
+ { tag: "new", t: ["<code>SmartTable</code> row density: <code>compact</code> rows are 28px at sm — the Spreadsheet's cell height — beside the 36px default. Switch it from the new <b>Row height</b> menu in the toolbar.", "<code>SmartTable</code> 新增行密度:<code>compact</code> 在 sm 下行高 28px,与 Spreadsheet 单元格一致;默认仍是 36px。工具栏新增「行高」菜单可切换。", "<code>SmartTable</code> に行密度を追加:<code>compact</code> は sm で 28px(Spreadsheet のセルと同じ高さ)、デフォルトは 36px のまま。ツールバーの新しい「行の高さ」メニューで切り替え。"] },
39
+ ] },
40
+ { v: "2.4.0", date: "2026-10-22", items: [
41
+ { tag: "breaking", t: ["<code>Sidebar</code> matches the product: grey <code>recessed</code> rail by default (pass <code>tone=\"flush\"</code> for the old white look), 2px gaps, trailing chevrons, Management / Knowledge Base footer and a version line.", "<code>Sidebar</code> 与产品一致:默认灰色 <code>recessed</code> 侧栏(旧的白色样式用 <code>tone=\"flush\"</code>),行距 2px、右侧箭头、底部为 Management / Knowledge Base,并显示版本号。", "<code>Sidebar</code> を製品に合わせました:既定はグレーの <code>recessed</code>(従来の白は <code>tone=\"flush\"</code>)、行間 2px、右矢印、フッターは Management / Knowledge Base、バージョン表示。"] },
42
+ { tag: "new", t: ["Data Source Logos page: 17 logo images (databases, SAP, protocols, file types) in <code>assets/logos/datasource/</code>.", "数据源图标页:17 张图标图片(数据库、SAP、协议与文件类型),位于 <code>assets/logos/datasource/</code>。", "データソースロゴページ:17 枚のロゴ画像(データベース・SAP・プロトコル・ファイル形式)、<code>assets/logos/datasource/</code> に格納。"] },
43
+ { tag: "new", t: ["Sidebar tones: <code>recessed</code>, <code>flush</code>, <code>contrast</code> and <code>custom</code> with ten rail colours.", "侧边栏色调:<code>recessed</code>、<code>flush</code>、<code>contrast</code>,以及带 10 种颜色的 <code>custom</code>。", "サイドバーのトーン:<code>recessed</code>・<code>flush</code>・<code>contrast</code>、10 色の <code>custom</code>。"] },
44
+ { tag: "new", t: ["<code>SidePanel</code> (Documents, Management) and <code>UserMenu</code> with an appearance switch; <code>TopBar</code> adds help and the user trigger.", "新增 <code>SidePanel</code>(文档、管理)和带外观切换的 <code>UserMenu</code>;<code>TopBar</code> 增加帮助按钮和用户入口。", "<code>SidePanel</code>(ドキュメント・管理)と外観切替付きの <code>UserMenu</code> を追加。<code>TopBar</code> にヘルプとユーザーメニューを追加。"] },
45
+ { tag: "new", t: ["<code>ContextMenu</code> / <code>Menu</code> items accept <code>selected: true</code> for single-choice menus (section switcher, language picker): <code>--bg-hover</code> fill and medium heading text, no checkmark.", "<code>ContextMenu</code> / <code>Menu</code> 的菜单项支持 <code>selected: true</code>,用于单选菜单(分区切换、语言选择):<code>--bg-hover</code> 底色、中等字重标题色文字,不带对勾。", "<code>ContextMenu</code> / <code>Menu</code> の項目が <code>selected: true</code> に対応。単一選択メニュー(セクション切替、言語選択)用で、<code>--bg-hover</code> の塗りと中ウェイトの見出し色。チェックマークは付けません。"] },
46
+ { tag: "new", t: ["Icon Usage page at the top of Icons: when a glyph stays monochrome and when it takes colour — category tiles, document hues, status, marks.", "图标分组最上方新增「图标用法」页:什么时候用单色、什么时候用颜色——分类色块、文档色、状态、标记。", "アイコンの先頭に「アイコンの使い方」ページを追加:単色のままにする場合と色を付ける場合 — カテゴリタイル、ドキュメント色、ステータス、マーク。"] },
47
+ { tag: "improved", t: ["The documentation site now follows the system's own rules: neutral selected states instead of blue, sentence-case labels, sm-tier toolbar controls, Sidebar-spec navigation rows.", "文档网站本身改为遵循设计系统规范:选中态不再用蓝色、标签用句首大写、工具栏控件用 sm 尺寸、导航行与 Sidebar 规格一致。", "ドキュメントサイト自体がシステムのルールに準拠:選択状態は青ではなくニュートラル、ラベルはセンテンスケース、ツールバーは sm サイズ、ナビ行は Sidebar 仕様。"] },
48
+ { tag: "improved", t: ["A single-choice menu spaces its rows 2px apart, like Sidebar, Tree and DocTree; action menus keep flush rows.", "单选菜单的行间距为 2px,与 Sidebar、Tree、DocTree 一致;操作菜单保持行间无缝。", "単一選択メニューは行間 2px(Sidebar・Tree・DocTree と同じ)。アクションメニューは従来どおり行間なし。"] }
49
+ ]},
50
+ { v: "2.3.2", date: "", items: [
51
+ { tag: "new", t: ["Count badges on <code>Tabs</code>, <code>PanelTabs</code>, <code>PillTabs</code> and <code>SegmentedControl</code>: <code>{ label, count }</code>, hidden at 0 unless <code>showZero</code>.", "<code>Tabs</code>、<code>PanelTabs</code>、<code>PillTabs</code>、<code>SegmentedControl</code> 支持计数标签:<code>{ label, count }</code>,为 0 时隐藏,<code>showZero</code> 时显示。", "<code>Tabs</code>・<code>PanelTabs</code>・<code>PillTabs</code>・<code>SegmentedControl</code> にカウントバッジ:<code>{ label, count }</code>。0 は <code>showZero</code> のときだけ表示。"] },
52
+ { tag: "new", t: ["<code>CountBadge</code> component and the <code>--count-h</code> tier token (16 · 18 · 20px).", "新增 <code>CountBadge</code> 组件和尺寸 token <code>--count-h</code>(16 · 18 · 20px)。", "<code>CountBadge</code> コンポーネントとサイズトークン <code>--count-h</code>(16 · 18 · 20px)を追加。"] }
53
+ ]},
54
+ { v: "2.3.1", date: "2026-10-20", items: [
55
+ { tag: "new", t: ["<code>Table</code> tree rows: nested <code>children</code>, 24px indent per level, expand arrows, <code>expandedKeys</code> / <code>onExpandChange</code>.", "<code>Table</code> 树状行:嵌套 <code>children</code>,每层缩进 24px,展开箭头,<code>expandedKeys</code> / <code>onExpandChange</code>。", "<code>Table</code> のツリー行:<code>children</code> の入れ子、1 階層 24px のインデント、展開矢印、<code>expandedKeys</code> / <code>onExpandChange</code>。"] },
56
+ { tag: "new", t: ["<code>onRowOpen</code> on two-line name cells: the icon tile and the title open the row.", "两行名称列支持 <code>onRowOpen</code>:点击图标块或主标题打开该行。", "2 行名セルに <code>onRowOpen</code>:アイコンタイルとタイトルで行を開きます。"] },
57
+ { tag: "new", t: ["<code>labels</code> translates every word the table draws: sort, ⋯ and expand tooltips.", "<code>labels</code> 参数可翻译表格自带的全部文字:排序、⋯ 和展开的提示。", "<code>labels</code> でテーブルが描く文言(並べ替え・⋯・展開のツールチップ)をすべて翻訳できます。"] }
58
+ ]},
59
+ { v: "2.3.0", date: "2026-10-19", items: [
60
+ { tag: "breaking", t: ["Size tiers: sm controls are 28px (was 24), lg 40px (was 36); rows and bars 36 · 40 · 48. Re-check anything sized by hand beside sm or lg controls.", "尺寸档:sm 控件 28px(原 24),lg 40px(原 36);行与工具栏 36 · 40 · 48。手动设尺寸、紧挨 sm 或 lg 控件的地方需复查。", "サイズ段階:sm は 28px(旧 24)、lg は 40px(旧 36)、行とバーは 36 · 40 · 48。sm・lg の横に手動サイズで置いた要素は要確認。"] },
61
+ { tag: "improved", t: ["CJK text below 14px is one step larger (12→13, 11→12); CJK medium and semibold are both 500.", "中日韩文字 14px 以下大一档(12→13、11→12);中日韩的中等与半粗字重都改为 500。", "CJK の 14px 未満は 1 段大きく(12→13、11→12)。CJK の medium と semibold はともに 500。"] },
62
+ { tag: "new", t: ["<code>Table</code>: two-line name rows, sortable headers, and <code>code: true</code> columns with a code chip.", "<code>Table</code>:两行名称行、可排序表头,以及带代码标签的 <code>code: true</code> 列。", "<code>Table</code>:2 行名の行、並べ替え可能なヘッダー、コードチップ付きの <code>code: true</code> 列。"] },
63
+ { tag: "improved", t: ["The monospace font is for code only; amounts and IDs use Inter with tabular figures.", "等宽字体只用于代码;金额与编号改用 Inter 等宽数字。", "等幅フォントはコード専用に。金額と ID は Inter の等幅数字。"] },
64
+ { tag: "improved", t: ["Borderless <code>Pagination</code> with a neutral current page; <code>IconButton</code> hover is an alpha overlay; table header splits one step darker.", "<code>Pagination</code> 去掉边框,当前页用中性色;<code>IconButton</code> 悬停改为半透明叠加;表头分隔线加深一档。", "<code>Pagination</code> は枠なし・現在ページはニュートラル。<code>IconButton</code> のホバーは半透明オーバーレイ。ヘッダーの区切り線を 1 段濃く。"] },
65
+ { tag: "new", t: ["<code>ai</code> and <code>ai-sparkles</code> join the core icon set.", "核心图标新增 <code>ai</code> 和 <code>ai-sparkles</code>。", "コアアイコンに <code>ai</code> と <code>ai-sparkles</code> を追加。"] },
66
+ { tag: "fixed", t: ["Vue components matched to React prop by prop; <code>applyStoredTheme</code> and <code>KEYBRICKS_NAV</code> are exported for both frameworks.", "Vue 组件按属性逐一与 React 对齐;<code>applyStoredTheme</code> 和 <code>KEYBRICKS_NAV</code> 在两个框架中都已导出。", "Vue コンポーネントを React とプロパティ単位で一致。<code>applyStoredTheme</code> と <code>KEYBRICKS_NAV</code> を両フレームワークでエクスポート。"] },
67
+ { tag: "removed", t: ["The product recreation (<code>ui_kits/</code>) and the web-app starter (<code>templates/</code>).", "移除产品复刻页(<code>ui_kits/</code>)和 Web App 模板(<code>templates/</code>)。", "製品の再現ページ(<code>ui_kits/</code>)と Web アプリのスターター(<code>templates/</code>)を削除。"] }
68
+ ]},
69
+ { v: "2.2.0", date: "", items: [
70
+ { tag: "new", t: ["Eleven Keybricks glyphs join the core icon set, among them <code>reconciliation</code>, <code>consolidation</code> and <code>journal</code>.", "核心图标新增 11 个 Keybricks 图标,包括 <code>reconciliation</code>、<code>consolidation</code>、<code>journal</code>。", "コアアイコンに Keybricks 独自の 11 個を追加(<code>reconciliation</code>・<code>consolidation</code>・<code>journal</code> など)。"] },
71
+ { tag: "improved", t: ["Icon drawing rules are written down in <code>readme.md</code>; six glyphs were redrawn to meet them.", "图标绘制规范写入 <code>readme.md</code>,6 个图标按规范重画。", "アイコンの描画ルールを <code>readme.md</code> に明文化し、6 個を描き直し。"] }
72
+ ]},
73
+ { v: "2.1.1", date: "", items: [
74
+ { tag: "improved", t: ["New chart series palette: one lightness band, no green or red in the sequence, distinguishable under colour-vision deficiency.", "新的图表系列配色:明度统一,序列中不含红绿,色觉障碍下仍可区分。", "グラフ系列色を刷新:明度をそろえ、系列に赤・緑を含めず、色覚多様性のシミュレーションでも判別可能。"] },
75
+ { tag: "improved", t: ["Hover hooks moved to <code>tokens/hover.css</code>; the one-line stylesheet import is unchanged.", "悬停样式移到 <code>tokens/hover.css</code>;单行样式引入方式不变。", "ホバーのフックを <code>tokens/hover.css</code> に移動。1 行のスタイル読み込みは変わりません。"] }
76
+ ]},
77
+ { v: "2.1.0", date: "", items: [
78
+ { tag: "removed", t: ["<code>BrandVisual</code> and its motifs. Pin <code>~2.0.3</code> until your code no longer imports it.", "移除 <code>BrandVisual</code> 及其图案。代码仍引用它的,请先锁定 <code>~2.0.3</code>。", "<code>BrandVisual</code> とそのモチーフを削除。まだ読み込んでいる場合は <code>~2.0.3</code> に固定してください。"] }
79
+ ]},
80
+ { v: "2.0.2", date: "", items: [
81
+ { tag: "improved", t: ["Hover on every pointer target: field borders darken, segments and tabs darken their ink, table rows take a light wash.", "所有可点击元素都有悬停态:输入框边框加深,分段和标签文字加深,表格行出现浅底色。", "すべてのポインター対象にホバー:入力枠が濃くなり、セグメントとタブの文字が濃くなり、テーブル行に淡い塗り。"] }
82
+ ]},
83
+ { v: "2.0.1", date: "", items: [
84
+ { tag: "fixed", t: ["Icons beside multi-line text centre on the first line; overlay close buttons centre on the title line.", "多行文字旁的图标对齐首行;浮层关闭按钮对齐标题行。", "複数行テキスト横のアイコンは 1 行目に揃え、オーバーレイの閉じるボタンはタイトル行に揃えます。"] }
85
+ ]},
86
+ { v: "2.0.0", date: "", items: [
87
+ { tag: "breaking", t: ["The 14px scale: body text 14px (was 13), small text 12px (was 11), line-heights on a 4px rhythm.", "14px 字号体系:正文 14px(原 13),小字 12px(原 11),行高按 4px 节奏。", "14px スケール:本文 14px(旧 13)、小さい文字 12px(旧 11)、行の高さは 4px リズム。"] },
88
+ { tag: "breaking", t: ["Controls are 32px by default; size tiers per region (<code>data-size</code>) replace per-control sizing.", "控件默认 32px;按区域设尺寸档(<code>data-size</code>),不再逐个控件设尺寸。", "コントロールは既定 32px。コントロールごとのサイズ指定に代えて、領域ごとのサイズ段階(<code>data-size</code>)。"] },
89
+ { tag: "improved", t: ["Table headers match their cells: same size, weight 600, sentence case.", "表头与单元格同字号,字重 600,句首大写。", "テーブルヘッダーはセルと同じサイズ・ウェイト 600・センテンスケース。"] }
90
+ ]}
91
+ ];
package/covers.js ADDED
@@ -0,0 +1,104 @@
1
+ /* Thumbnail covers for the documentation home page: the simplest form of each component, or one telling part of it.
2
+ Keyed by card file stem. Each entry is [scale, render(h, K)] — K is the design-system namespace. A cover that throws
3
+ falls back to the component's name (see renderTiles in index.html). Covers are inert: no pointer events, no focus. */
4
+ window.KB_COVERS = (function () {
5
+ const L = (n, a = 0) => Array.from({ length: n }, (_, i) => Math.round(50 + 30 * Math.sin(i / 1.6 + a) + i * 4));
6
+ const M = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"];
7
+ const col = (h, gap, kids) => h("div", { style: { display: "flex", flexDirection: "column", gap, alignItems: "flex-start" } }, ...kids);
8
+ const row = (h, gap, kids) => h("div", { style: { display: "flex", gap, alignItems: "center" } }, ...kids);
9
+ return {
10
+ // components
11
+ "accordion": [.8, (h, K) => h("div", { style: { width: 260 } }, h(K.Accordion, { title: "Connection", subtitle: "Host, port, credentials", defaultOpen: false }, "Details"), h(K.Accordion, { title: "Schedule", defaultOpen: false }, "Details"))],
12
+ "action-chip": [1, (h, K) => row(h, 8, [h(K.ActionChip, { tone: "info" }, "Mark as New"), h(K.ActionChip, null, "Skip")])],
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
+ "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"))))],
16
+ "banner": [.7, (h, K) => h("div", { style: { width: 340 } }, h(K.Banner, { tone: "warning", title: "Scheduled maintenance tonight", action: "Details" }))],
17
+ "breadcrumb": [1, (h, K) => h(K.Breadcrumb, { items: ["Home", "Pipelines", "Import"] })],
18
+ "button-1-base": [1, (h, K) => row(h, 8, [h(K.Button, { variant: "primary" }, "Save"), h(K.Button, { variant: "outline" }, "Cancel")])],
19
+ "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
+ "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
+ "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"))])],
22
+ "canvas-zoom-controls": [1, (h, K) => h(K.ZoomControls, { value: 100 })],
23
+ "cards-indicators": [.85, (h, K) => h("div", { style: { width: 220 } }, h(K.StatCard, { label: "Rows imported", value: "12,480" }))],
24
+ "checkbox": [1, (h, K) => col(h, 10, [h(K.Checkbox, { checked: true, label: "Include headers" }), h(K.Checkbox, { checked: false, label: "Skip empty rows" })])],
25
+ "codeblock": [.75, (h, K) => h("div", { style: { width: 300 } }, h(K.CodeBlock, { language: "SQL", code: "SELECT id, amount\nFROM ledger\nWHERE period = '2026-09'" }))],
26
+ "combobox": [1, (h, K) => h(K.Combobox, { options: ["Oracle", "SAP"], value: "Oracle", width: 200 })],
27
+ "context-menu": [.9, (h, K) => h(K.ContextMenu, { items: [{ label: "Preview", icon: "eye" }, { label: "Duplicate", icon: "copy" }, { divider: true }, { label: "Delete", icon: "trash-2", danger: true }] })],
28
+ "date-picker": [1, (h, K) => h(K.DatePicker, { value: "2026-10-22", width: 200 })],
29
+ "diffvalue": [1.1, (h, K) => h(K.DiffValue, { from: "1,200", to: "1,450" })],
30
+ "divider": [1, (h, K) => h("div", { style: { width: 200, display: "flex", flexDirection: "column", gap: 10, fontSize: "var(--text-base)", color: "var(--text-body)" } }, h("span", null, "Connection"), h(K.Divider), h("span", null, "Schedule"), h(K.Divider, { label: "or" }))],
31
+ "drawer": [.5, (h, K) => h(K.Drawer, { open: true, inline: true, title: "Run details", subtitle: "RUN-1890", width: 320, height: 220 }, h("div", { style: { padding: 16 } }, h(K.KeyValue, { label: "Status", value: "Completed" })))],
32
+ "dropdown-menu": [.9, (h, K) => col(h, 6, [h(K.Button, { variant: "outline", icon: "chevron-down", iconPosition: "right" }, "Sort by"), h(K.ContextMenu, { items: [{ label: "Name" }, { label: "Date modified" }, { label: "Size" }] })])],
33
+ "dropzone": [.6, (h, K) => h("div", { style: { width: 320 } }, h(K.Dropzone, { title: "Drop a file to import", hint: "CSV or XLSX, up to 20 MB", height: 140 }))],
34
+ "empty-state": [.7, (h, K) => h(K.EmptyState, { icon: "inbox", title: "No runs yet", hint: "Runs appear here once a pipeline starts." })],
35
+ "filter-bar": [.45, (h, K) => h("div", { style: { width: 520 } }, h(K.FilterBar, { variant: "Standard", adaptCount: 2, defaultExpanded: false }))],
36
+ "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
+ "input": [1, (h, K) => h("div", { style: { width: 220 } }, h(K.Input, { value: "FIN_CURRENCY_DEFAULT", onChange: () => {} }))],
38
+ "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
+ "listrow": [.8, (h, K) => h("div", { style: { width: 280 } }, h(K.ListRow, { icon: "database", title: "Oracle EBS", meta: "Last sync 2 min ago" }))],
41
+ "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
+ "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 }))],
43
+ "modal": [.5, (h, K) => h("div", { style: { width: 360, borderRadius: "var(--radius-lg)", border: "1px solid var(--border-card)", background: "var(--bg-raised)", boxShadow: "var(--shadow-menu)", padding: 20, display: "flex", flexDirection: "column", gap: 16 } }, h("div", { style: { fontSize: "var(--text-md)", fontWeight: "var(--weight-semibold)", color: "var(--text-heading)" } }, "Delete pipeline?"), h("div", { style: { fontSize: "var(--text-base)", color: "var(--text-body)" } }, "This removes 4 nodes and their run history."), row(h, 8, [h("div", { style: { flex: 1 } }), h(K.Button, { variant: "outline" }, "Cancel"), h(K.Button, { variant: "danger" }, "Delete")]))],
44
+ "multi-select": [.9, (h, K) => h(K.MultiSelect, { options: ["HK", "SG", "CN"], value: ["HK", "SG"], width: 220 })],
45
+ "number-stepper": [1.1, (h, K) => h(K.NumberStepper, { value: 100 })],
46
+ "pagination": [.8, (h, K) => h(K.Pagination, { page: 2, pageCount: 5, total: 96 })],
47
+ "people": [1.2, (h, K) => h(K.AvatarGroup, { names: ["Felix Wang", "Luo Lisi", "Guo Kaige", "Ana Silva", "Kim Lee"], max: 4 })],
48
+ "pipeline-node": [.75, (h, K) => h(K.NodeCard, { title: "Join Ledger", subtitle: "2 inputs", icon: "merge", hue: "join", inputs: ["A", "B"] })],
49
+ "pipeline-palette": [.5, (h, K) => h(K.IconTile, { icon: "database", hue: "source" })],
50
+ "radio": [1, (h, K) => col(h, 10, [h(K.Radio, { checked: true, label: "Overwrite" }), h(K.Radio, { checked: false, label: "Append" })])],
51
+ "search": [1, (h, K) => h("div", { style: { width: 220 } }, h(K.SearchInput, { placeholder: "Search pipelines" }))],
52
+ "segmented-control": [1, (h, K) => h(K.SegmentedControl, { options: ["Grid", "List", "Board"], value: "Grid" })],
53
+ "relative-time-picker": [1, (h, K) => h("div", { style: { width: 220 } }, h(K.RelativeTimePicker, { value: { amount: 24, unit: "Hour" } }))],
54
+ "select": [1, (h, K) => h("div", { style: { width: 200 } }, h(K.Select, { options: ["Monthly", "Quarterly"], value: "Monthly" }))],
55
+ "slider": [1, (h, K) => h(K.Slider, { value: 60, width: 200 })],
56
+ "smart-table": [.5, (h, K) => h("div", { style: { width: 440 } }, h(K.SmartTable, { toolbar: false, fields: [{ key: "name", label: "Name", primary: true }, { key: "owner", label: "Owner", type: "person" }, { key: "done", label: "Done", type: "checkbox" }], rows: [{ name: "FX rates", owner: "Felix Wang", done: true }, { name: "Opening balances", owner: "Luo Lisi", done: false }] }))],
57
+ "spreadsheet": [.45, (h, K) => h("div", { style: { width: 460 } }, h(K.Spreadsheet, { rows: 4, toolbar: false, height: 170, data: [[{ v: "Entity" }, { v: "Q3" }, { v: "Q4" }], [{ v: "HK" }, { v: 4100 }, { v: 4600 }], [{ v: "SG" }, { v: 1610 }, { v: 1820 }]] }))],
58
+ "stepper": [.75, (h, K) => h(K.Stepper, { steps: [{ label: "Source" }, { label: "Map" }, { label: "Run" }], current: 1 })],
59
+ "table": [.55, (h, K) => h("div", { style: { width: 400 } }, h(K.Table, { bordered: true, columns: [{ key: "id", label: "Run" }, { key: "doc", label: "Document" }, { key: "st", label: "Status" }], rows: [{ id: "RUN-1890", doc: "FX Rates", st: "Completed" }, { id: "RUN-1891", doc: "Ledger", st: "Running" }] }))],
60
+ "tabs": [.9, (h, K) => h(K.Tabs, { tabs: [{ label: "Import", count: 3 }, "Export", "History"], active: "Import" })],
61
+ "tag": [1.1, (h, K) => row(h, 6, [h(K.Tag, { onRemove: () => {} }, "HK"), h(K.Tag, { tone: "info", onRemove: () => {} }, "Q3")])],
62
+ "textarea": [.9, (h, K) => h("div", { style: { width: 240 } }, h(K.Textarea, { value: "Monthly close notes", rows: 3, onChange: () => {} }))],
63
+ "timeline": [.8, (h, K) => h("div", { style: { width: 240 } }, h(K.Timeline, { items: [{ tone: "success", title: "Run completed", meta: "14:31" }, { title: "Mapping updated", meta: "13:05" }] }))],
64
+ "toast": [.75, (h, K) => h(K.Toast, { tone: "success", title: "Pipeline saved", meta: "Just now" })],
65
+ "toggles": [1.2, (h, K) => row(h, 12, [h(K.Switch, { checked: true }), h(K.Switch, { checked: false })])],
66
+ "tooltip": [1, (h, K) => h("div", { style: { padding: "6px 10px", borderRadius: "var(--radius-md)", background: "var(--action-dark)", color: "var(--action-dark-fg)", fontSize: "var(--text-xs)", lineHeight: "var(--leading-xs)" } }, "Copy to clipboard")],
67
+ "tree": [.8, (h, K) => h("div", { style: { width: 220 } }, h(K.Tree, { defaultExpanded: ["a"], items: [{ key: "a", title: "Assets", children: [{ key: "a1", title: "Cash" }, { key: "a2", title: "Receivables" }] }, { key: "b", title: "Liabilities", children: [{ key: "b1", title: "Payables" }] }] }))],
68
+ // icons — any icon card without a cover falls back to its name; new sets just need an entry here
69
+ "icons-0-usage": [1, (h, K) => h("div", { style: { display: "grid", gridTemplateColumns: "repeat(3, 40px)", gap: 12 } }, ...[["source", "table"], ["join", "shuffle"], ["transform", "funnel"], ["merge", "merge"], ["output", "layers"]].map(([hu, i]) => h(K.IconTile, { key: hu, icon: i, hue: hu })), h("span", { key: "s", style: { display: "flex", alignItems: "center", justifyContent: "center" } }, h(K.StatusBadge, { tone: "success", icon: "check" })))],
70
+ "icons-1-core": [1, (h, K) => h("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 28px)", gap: 14, color: "var(--text-body)" } }, ...["house", "file-text", "database", "journal", "reconciliation", "consolidation", "ai", "settings"].map(n => h(K.Icon, { key: n, name: n, size: 24 })))],
71
+ "icons-2-feather": [1, (h, K) => h("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 28px)", gap: 14, color: "var(--text-body)" } }, ...["feather", "anchor", "aperture", "compass", "cpu", "droplet", "globe", "umbrella"].map(n => h(K.Icon, { key: n, name: n, size: 24 })))],
72
+ "icons-2b-lucide": [1, (h, K) => h("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 28px)", gap: 14, color: "var(--text-body)" } }, ...["calendar-clock", "file-chart-pie", "list-checks", "badge-check", "folder-tree", "square-terminal", "zap", "boxes"].map(n => h(K.Lucide, { key: n, name: n, size: 24 })))],
73
+ "icons-3-unicons": [1, (h, K) => h("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 28px)", gap: 14, color: "var(--text-body)" } }, ...["chart", "bolt", "cloud", "envelope", "rocket", "star", "user", "wallet"].map(n => h(K.Unicon, { key: n, name: n, size: 24 })))],
74
+ "icons-4-datasource": [1, (h) => h("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 32px)", gap: 12 } }, ...["oracle", "sap", "sql-server", "mysql", "postgresql", "mongodb", "rest-api", "excel"].map(n => h("img", { key: n, src: "assets/logos/datasource/" + n + ".png", alt: n, width: 32, height: 32, style: { display: "block", borderRadius: "var(--radius-md)" } })))],
75
+ // charts
76
+ "charts-1-sparkline": [1, (h, K) => h(K.Sparkline, { values: L(14), width: 200, height: 56 })],
77
+ "charts-2-line": [.6, (h, K) => h(K.LineChart, { series: [{ name: "Actual", values: L(6) }, { name: "Plan", values: L(6, 1) }], xLabels: M, width: 340, height: 180 })],
78
+ "charts-3-bar": [.6, (h, K) => h(K.BarChart, { series: [{ name: "2025", values: [40, 62, 55, 80] }, { name: "2026", values: [52, 70, 66, 92] }], categories: ["Q1", "Q2", "Q3", "Q4"], width: 340, height: 180 })],
79
+ "charts-4-barlist": [.7, (h, K) => h(K.BarList, { rows: [{ label: "Germany", value: 5200 }, { label: "France", value: 3100 }, { label: "Spain", value: 1100 }], width: 280 })],
80
+ "charts-5-donut": [.7, (h, K) => h(K.DonutChart, { segments: [{ label: "EMEA", value: 42 }, { label: "APAC", value: 31 }, { label: "AMER", value: 27 }], size: 150, centerValue: "100%", legend: false })],
81
+ "charts-6-scatter": [.6, (h, K) => h(K.ScatterChart, { points: [[12, 340, 8], [30, 210, 5], [44, 420, 10], [58, 300, 6], [70, 480, 9], [82, 260, 4]].map(([x, y, r]) => ({ x, y, r })), width: 340, height: 180 })],
82
+ "charts-7-heatmap": [.6, (h, K) => h(K.HeatmapChart, { xLabels: M, yLabels: ["HK", "SG", "CN", "JP"], values: [0, 1, 2, 3].map(r => M.map((_, c) => (r * 7 + c * 5) % 17)), width: 340 })],
83
+ "charts-8-waterfall": [.6, (h, K) => h(K.WaterfallChart, { steps: [{ label: "Revenue", value: 6100 }, { label: "COGS", value: -2400 }, { label: "Opex", value: -1500 }, { label: "Tax", value: -500 }], width: 340, height: 180 })],
84
+ "charts-9-bullet": [.7, (h, K) => h(K.BulletChart, { rows: [{ label: "Revenue", value: 6100, target: 5800 }, { label: "Margin", value: 38, target: 42 }], width: 280 })],
85
+ "charts-10-gauge": [.75, (h, K) => h(K.GaugeChart, { value: 72, label: "Close progress" })],
86
+ "charts-11-funnel": [.55, (h, K) => h(K.FunnelChart, { stages: [{ label: "Imported", value: 1200 }, { label: "Mapped", value: 940 }, { label: "Validated", value: 720 }, { label: "Posted", value: 610 }], width: 280 })],
87
+ "charts-12-treemap": [.6, (h, K) => h(K.TreemapChart, { items: [{ label: "Payroll", value: 42 }, { label: "Rent", value: 18 }, { label: "IT", value: 14 }, { label: "Travel", value: 9 }, { label: "Other", value: 7 }], width: 340, height: 180 })],
88
+ "charts-14-radar": [.6, (h, K) => h(K.RadarChart, { axes: ["Speed", "Quality", "Cost", "Scope", "Risk"].map(label => ({ label, max: 100 })), series: [{ name: "Team A", values: [80, 65, 70, 90, 50] }, { name: "Team B", values: [60, 85, 55, 70, 75] }], size: 200, legend: false })],
89
+ "charts-15-distribution": [.6, (h, K) => h(K.Histogram, { values: Array.from({ length: 120 }, (_, i) => Math.round(50 + 20 * Math.sin(i * 1.7) + (i % 9) * 3)), bins: 12, width: 340, height: 180 })],
90
+ "charts-16-pareto": [.6, (h, K) => h(K.ParetoChart, { items: [{ label: "Mapping", value: 48 }, { label: "Format", value: 26 }, { label: "Dupes", value: 14 }, { label: "Other", value: 8 }], width: 340, height: 180 })],
91
+ "charts-17-candlestick": [.6, (h, K) => h(K.CandlestickChart, { candles: L(14).map((v, i) => { const o = v, c = v + ((i % 3) - 1) * 6; return { date: "D" + i, label: "D" + i, o, c, h: Math.max(o, c) + 5, l: Math.min(o, c) - 5, open: o, close: c, high: Math.max(o, c) + 5, low: Math.min(o, c) - 5 }; }), width: 340, height: 180 })],
92
+ "charts-18-sankey": [.55, (h, K) => h(K.SankeyChart, { nodes: ["Revenue", "COGS", "Opex", "Profit"].map(id => ({ id, label: id })), links: [{ source: "Revenue", target: "COGS", value: 40 }, { source: "Revenue", target: "Opex", value: 25 }, { source: "Revenue", target: "Profit", value: 35 }], width: 360, height: 200 })],
93
+ "charts-19-chord": [.55, (h, K) => h(K.ChordChart, { labels: ["HK", "SG", "CN", "JP"], matrix: [[0, 5, 8, 3], [4, 0, 2, 6], [7, 3, 0, 4], [2, 5, 3, 0]], size: 240 })],
94
+ "charts-20-sunburst": [.55, (h, K) => h(K.SunburstChart, { data: { label: "Total cost", children: [{ label: "People", children: [{ label: "Payroll", value: 40 }, { label: "Benefits", value: 12 }] }, { label: "Facilities", children: [{ label: "Rent", value: 18 }, { label: "Utilities", value: 6 }] }, { label: "IT", value: 14 }] }, size: 240 })],
95
+ "charts-21-worldmap": [.45, (h, K) => h(K.WorldMap, { values: { "United States": 6400, Canada: 2100, Brazil: 1400, "United Kingdom": 4200, Germany: 5200, France: 3100, China: 5800, Japan: 2600, Australia: 1200 }, width: 460, legend: false })],
96
+ "charts-22-gantt": [.55, (h, K) => h(K.GanttChart, { tasks: [{ label: "Extract", start: "2026-03-02", end: "2026-03-05", progress: 1, lane: 0 }, { label: "Map", start: "2026-03-04", end: "2026-03-09", progress: .6, lane: 1 }, { label: "Validate", start: "2026-03-08", end: "2026-03-12", progress: 0, lane: 2 }], width: 380 })],
97
+ "charts-23-bar3d": [.55, (h, K) => h(K.Bar3D, { series: [{ name: "2025", values: [40, 62, 55, 80] }, { name: "2026", values: [52, 70, 66, 92] }], categories: ["Q1", "Q2", "Q3", "Q4"], width: 360, height: 220, interactive: false })],
98
+ "charts-24-pie3d": [.6, (h, K) => h(K.Pie3D, { segments: [{ label: "EMEA", value: 42 }, { label: "APAC", value: 31 }, { label: "AMER", value: 27 }], legend: false, width: 300, height: 200 })],
99
+ "charts-25-surface3d": [.55, (h, K) => h(K.Surface3D, { width: 360, height: 220, interactive: false })],
100
+ "charts-26-scatter3d": [.55, (h, K) => h(K.Scatter3D, { points: Array.from({ length: 30 }, (_, i) => ({ x: (i * 37) % 100, y: (i * 53) % 100, z: (i * 71) % 100, series: ["Alpha", "Beta", "Gamma"][i % 3] })), width: 360, height: 220, legend: false, interactive: false })],
101
+ "charts-27-ribbon3d": [.55, (h, K) => h(K.Ribbon3D, { series: [{ name: "HK", values: L(6) }, { name: "SG", values: L(6, 1) }, { name: "CN", values: L(6, 2) }], xLabels: M, width: 360, height: 220, interactive: false })],
102
+ "charts-99-fullpage": [.5, (h, K) => h("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, width: 380 } }, h(K.StatCard, { label: "Revenue", value: "$6.1M" }), h(K.StatCard, { label: "Margin", value: "38%" }), h("div", { style: { gridColumn: "1 / -1" } }, h(K.Sparkline, { values: L(20), width: 380, height: 60 })))]
103
+ };
104
+ })();