@icen.ai/ui 0.9.0 → 0.10.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 (281) hide show
  1. package/AGENTS.md +138 -80
  2. package/README.md +66 -91
  3. package/dist/base.css +208 -179
  4. package/dist/behaviors/accordion.mjs +8 -8
  5. package/dist/behaviors/ai-branch.d.mts +1 -1
  6. package/dist/behaviors/ai-branch.mjs +1010 -94
  7. package/dist/behaviors/ai-chat.d.mts +7 -7
  8. package/dist/behaviors/ai-chat.mjs +1071 -161
  9. package/dist/behaviors/ai-composer.d.mts +44 -12
  10. package/dist/behaviors/ai-composer.mjs +1997 -524
  11. package/dist/behaviors/ai-core.d.mts +1 -1
  12. package/dist/behaviors/ai-core.mjs +1016 -107
  13. package/dist/behaviors/ai-diff.mjs +1019 -127
  14. package/dist/behaviors/ai-feedback.d.mts +1 -1
  15. package/dist/behaviors/ai-feedback.mjs +1035 -126
  16. package/dist/behaviors/ai-panel.d.mts +8 -8
  17. package/dist/behaviors/ai-panel.mjs +1284 -266
  18. package/dist/behaviors/ai-provider.mjs +1003 -101
  19. package/dist/behaviors/ai-threads.d.mts +1 -1
  20. package/dist/behaviors/ai-threads.mjs +1068 -154
  21. package/dist/behaviors/ai-tool.d.mts +2 -2
  22. package/dist/behaviors/ai-tool.mjs +2037 -396
  23. package/dist/behaviors/ai-tools.d.mts +89 -16
  24. package/dist/behaviors/ai-tools.mjs +4448 -372
  25. package/dist/behaviors/autocomplete.d.mts +53 -0
  26. package/dist/behaviors/autocomplete.mjs +1600 -0
  27. package/dist/behaviors/back-top.d.mts +1 -1
  28. package/dist/behaviors/back-top.mjs +951 -14
  29. package/dist/behaviors/carousel.d.mts +1 -1
  30. package/dist/behaviors/carousel.mjs +906 -11
  31. package/dist/behaviors/cascader.d.mts +48 -0
  32. package/dist/behaviors/cascader.mjs +1853 -0
  33. package/dist/behaviors/charts.d.mts +72 -8
  34. package/dist/behaviors/charts.mjs +1901 -256
  35. package/dist/behaviors/code-block.d.mts +36 -0
  36. package/dist/behaviors/code-block.mjs +1611 -0
  37. package/dist/behaviors/command-palette.d.mts +9 -6
  38. package/dist/behaviors/command-palette.mjs +161 -59
  39. package/dist/behaviors/context-menu.d.mts +9 -8
  40. package/dist/behaviors/context-menu.mjs +1112 -44
  41. package/dist/behaviors/controls.d.mts +13 -13
  42. package/dist/behaviors/controls.mjs +989 -130
  43. package/dist/behaviors/copy.d.mts +21 -2
  44. package/dist/behaviors/copy.mjs +1206 -42
  45. package/dist/behaviors/datatable.d.mts +53 -3
  46. package/dist/behaviors/datatable.mjs +1963 -207
  47. package/dist/behaviors/date-picker.d.mts +0 -1
  48. package/dist/behaviors/date-picker.mjs +1340 -293
  49. package/dist/behaviors/design.d.mts +54 -0
  50. package/dist/behaviors/design.mjs +109 -0
  51. package/dist/behaviors/dropdown.d.mts +5 -6
  52. package/dist/behaviors/dropdown.mjs +262 -110
  53. package/dist/behaviors/events.d.mts +120 -3
  54. package/dist/behaviors/events.mjs +47 -2
  55. package/dist/behaviors/feedback.d.mts +30 -0
  56. package/dist/behaviors/feedback.mjs +296 -0
  57. package/dist/behaviors/focus.d.mts +8 -0
  58. package/dist/behaviors/focus.mjs +24 -0
  59. package/dist/behaviors/form-validate.d.mts +102 -0
  60. package/dist/behaviors/form-validate.mjs +6091 -0
  61. package/dist/behaviors/i18n.d.mts +789 -0
  62. package/dist/behaviors/i18n.mjs +1711 -0
  63. package/dist/behaviors/icons.d.mts +93 -0
  64. package/dist/behaviors/icons.mjs +113 -0
  65. package/dist/behaviors/input.d.mts +9 -1
  66. package/dist/behaviors/input.mjs +1056 -60
  67. package/dist/behaviors/kb-access.d.mts +1 -1
  68. package/dist/behaviors/kb-access.mjs +2129 -239
  69. package/dist/behaviors/kb-acl.d.mts +6 -6
  70. package/dist/behaviors/kb-acl.mjs +1119 -179
  71. package/dist/behaviors/kb-answer.mjs +2070 -418
  72. package/dist/behaviors/kb-audit.d.mts +1 -1
  73. package/dist/behaviors/kb-audit.mjs +1076 -154
  74. package/dist/behaviors/kb-canvas.mjs +1100 -177
  75. package/dist/behaviors/kb-chain.mjs +1022 -100
  76. package/dist/behaviors/kb-checkpoint.d.mts +1 -1
  77. package/dist/behaviors/kb-checkpoint.mjs +1319 -169
  78. package/dist/behaviors/kb-chunks.mjs +1152 -213
  79. package/dist/behaviors/kb-citation.d.mts +1 -1
  80. package/dist/behaviors/kb-citation.mjs +1201 -179
  81. package/dist/behaviors/kb-clarify.mjs +1058 -130
  82. package/dist/behaviors/kb-conflict.mjs +1041 -119
  83. package/dist/behaviors/kb-connector.mjs +1104 -176
  84. package/dist/behaviors/kb-core.d.mts +6 -1
  85. package/dist/behaviors/kb-core.mjs +1077 -162
  86. package/dist/behaviors/kb-eval.mjs +1971 -144
  87. package/dist/behaviors/kb-explain.d.mts +1 -1
  88. package/dist/behaviors/kb-explain.mjs +1024 -102
  89. package/dist/behaviors/kb-filter.mjs +2008 -178
  90. package/dist/behaviors/kb-gap.d.mts +1 -1
  91. package/dist/behaviors/kb-gap.mjs +1043 -121
  92. package/dist/behaviors/kb-hittest.d.mts +1 -1
  93. package/dist/behaviors/kb-hittest.mjs +1093 -150
  94. package/dist/behaviors/kb-metadata.mjs +1052 -130
  95. package/dist/behaviors/kb-passage.d.mts +2 -2
  96. package/dist/behaviors/kb-passage.mjs +1101 -161
  97. package/dist/behaviors/kb-pipeline.d.mts +2 -2
  98. package/dist/behaviors/kb-pipeline.mjs +1082 -162
  99. package/dist/behaviors/kb-qa.mjs +1088 -160
  100. package/dist/behaviors/kb-rerank.mjs +1047 -114
  101. package/dist/behaviors/kb-retrieval.mjs +2063 -224
  102. package/dist/behaviors/kb-review.mjs +1990 -159
  103. package/dist/behaviors/kb-sandbox.d.mts +1 -1
  104. package/dist/behaviors/kb-sandbox.mjs +1026 -104
  105. package/dist/behaviors/kb-segment.mjs +1111 -179
  106. package/dist/behaviors/kb-select.d.mts +24 -0
  107. package/dist/behaviors/kb-select.mjs +1989 -0
  108. package/dist/behaviors/kb-sources.d.mts +1 -1
  109. package/dist/behaviors/kb-sources.mjs +1084 -170
  110. package/dist/behaviors/kb-sql.d.mts +1 -1
  111. package/dist/behaviors/kb-sql.mjs +1143 -226
  112. package/dist/behaviors/kb-trace.d.mts +1 -1
  113. package/dist/behaviors/kb-trace.mjs +1042 -128
  114. package/dist/behaviors/kb-visibility.mjs +1086 -158
  115. package/dist/behaviors/kb-who-can.mjs +1974 -137
  116. package/dist/behaviors/mentions.d.mts +93 -0
  117. package/dist/behaviors/mentions.mjs +2152 -0
  118. package/dist/behaviors/modal.d.mts +4 -3
  119. package/dist/behaviors/modal.mjs +1055 -33
  120. package/dist/behaviors/nav.d.mts +1 -1
  121. package/dist/behaviors/nav.mjs +6 -6
  122. package/dist/behaviors/notification.d.mts +16 -8
  123. package/dist/behaviors/notification.mjs +1615 -265
  124. package/dist/behaviors/panel.d.mts +4 -0
  125. package/dist/behaviors/panel.mjs +994 -0
  126. package/dist/behaviors/popover.d.mts +28 -5
  127. package/dist/behaviors/popover.mjs +225 -24
  128. package/dist/behaviors/select.d.mts +5 -2
  129. package/dist/behaviors/select.mjs +1410 -117
  130. package/dist/behaviors/sidebar.d.mts +1 -1
  131. package/dist/behaviors/sidebar.mjs +13 -13
  132. package/dist/behaviors/slider.d.mts +1 -1
  133. package/dist/behaviors/slider.mjs +9 -9
  134. package/dist/behaviors/split-pane.d.mts +1 -1
  135. package/dist/behaviors/split-pane.mjs +7 -7
  136. package/dist/behaviors/suggestions.d.mts +27 -0
  137. package/dist/behaviors/suggestions.mjs +1089 -0
  138. package/dist/behaviors/svg-parse.d.mts +14 -0
  139. package/dist/behaviors/svg-parse.mjs +37 -0
  140. package/dist/behaviors/tabs.d.mts +2 -2
  141. package/dist/behaviors/tabs.mjs +25 -25
  142. package/dist/behaviors/tag-input.d.mts +23 -5
  143. package/dist/behaviors/tag-input.mjs +1359 -104
  144. package/dist/behaviors/theme-switcher.d.mts +24 -0
  145. package/dist/behaviors/theme-switcher.mjs +1981 -0
  146. package/dist/behaviors/theme.d.mts +15 -8
  147. package/dist/behaviors/theme.mjs +390 -28
  148. package/dist/behaviors/toast.d.mts +24 -25
  149. package/dist/behaviors/toast.mjs +1266 -88
  150. package/dist/behaviors/tooltip.d.mts +4 -0
  151. package/dist/behaviors/tooltip.mjs +378 -0
  152. package/dist/behaviors/tree-select.d.mts +69 -0
  153. package/dist/behaviors/tree-select.mjs +1907 -0
  154. package/dist/behaviors/tree.d.mts +1 -1
  155. package/dist/behaviors/tree.mjs +15 -15
  156. package/dist/behaviors/upload.d.mts +3 -2
  157. package/dist/behaviors/upload.mjs +1076 -66
  158. package/dist/cli.mjs +5 -6
  159. package/dist/components/ai-chat.css +666 -573
  160. package/dist/components/ai-diff.css +153 -132
  161. package/dist/components/ai-panel.css +351 -343
  162. package/dist/components/ai-tool.css +393 -238
  163. package/dist/components/autocomplete.css +61 -0
  164. package/dist/components/autocomplete.mjs +3 -0
  165. package/dist/components/back-top.css +34 -31
  166. package/dist/components/badge.css +44 -41
  167. package/dist/components/breadcrumb.css +67 -46
  168. package/dist/components/btn.css +80 -74
  169. package/dist/components/card.css +117 -106
  170. package/dist/components/cascader.css +311 -0
  171. package/dist/components/cascader.mjs +3 -0
  172. package/dist/components/chart-area.css +8 -2
  173. package/dist/components/chart-bar.css +95 -33
  174. package/dist/components/chart-gauge.css +14 -11
  175. package/dist/components/chart-graph.css +20 -17
  176. package/dist/components/chart-heatmap.css +96 -90
  177. package/dist/components/chart-line.css +8 -3
  178. package/dist/components/chart-pie.css +9 -6
  179. package/dist/components/chart-radar.css +8 -5
  180. package/dist/components/chart-scatter.css +9 -6
  181. package/dist/components/chart-sparkline.css +5 -2
  182. package/dist/components/chart-stack.css +14 -11
  183. package/dist/components/charts.css +164 -73
  184. package/dist/components/code-block.css +418 -0
  185. package/dist/components/code-block.mjs +4 -0
  186. package/dist/components/command-palette.css +138 -117
  187. package/dist/components/content.css +257 -251
  188. package/dist/components/copy.css +72 -44
  189. package/dist/components/datatable.css +423 -181
  190. package/dist/components/date-picker.css +135 -104
  191. package/dist/components/empty.css +68 -65
  192. package/dist/components/feedback.css +201 -183
  193. package/dist/components/form-validate.css +120 -0
  194. package/dist/components/form-validate.mjs +3 -0
  195. package/dist/components/form.css +150 -127
  196. package/dist/components/icon.css +102 -0
  197. package/dist/components/icon.mjs +3 -0
  198. package/dist/components/input.css +159 -104
  199. package/dist/components/kb-agent.css +188 -173
  200. package/dist/components/kb-data.css +257 -253
  201. package/dist/components/kb-ground.css +197 -185
  202. package/dist/components/kb-ingest.css +334 -350
  203. package/dist/components/kb-ops.css +265 -259
  204. package/dist/components/kb-perm.css +260 -271
  205. package/dist/components/kb-search.css +317 -360
  206. package/dist/components/kb.css +120 -109
  207. package/dist/components/layout.css +85 -82
  208. package/dist/components/material-chinese.css +73 -0
  209. package/dist/components/material-soviet.css +76 -0
  210. package/dist/components/material.css +275 -0
  211. package/dist/components/media.css +220 -166
  212. package/dist/components/mentions.css +189 -0
  213. package/dist/components/mentions.mjs +3 -0
  214. package/dist/components/menu.css +113 -105
  215. package/dist/components/modal.css +107 -112
  216. package/dist/components/nav.css +118 -115
  217. package/dist/components/notification.css +238 -174
  218. package/dist/components/pagination.css +56 -53
  219. package/dist/components/panel.css +66 -63
  220. package/dist/components/panel.mjs +1 -0
  221. package/dist/components/pill.css +81 -71
  222. package/dist/components/popover.css +67 -53
  223. package/dist/components/scroll-area.css +113 -110
  224. package/dist/components/segmented.css +146 -143
  225. package/dist/components/select.css +206 -186
  226. package/dist/components/sidebar.css +137 -127
  227. package/dist/components/slider.css +117 -114
  228. package/dist/components/split-pane.css +112 -109
  229. package/dist/components/stat.css +112 -106
  230. package/dist/components/steps.css +109 -103
  231. package/dist/components/switch.css +138 -134
  232. package/dist/components/table.css +131 -107
  233. package/dist/components/tabs.css +114 -108
  234. package/dist/components/tag-input.css +48 -133
  235. package/dist/components/tag.css +81 -71
  236. package/dist/components/theme-switcher.css +105 -0
  237. package/dist/components/theme-switcher.mjs +3 -0
  238. package/dist/components/toast.css +100 -86
  239. package/dist/components/toolbar.css +45 -42
  240. package/dist/components/tooltip.css +102 -43
  241. package/dist/components/tooltip.mjs +1 -0
  242. package/dist/components/tree-select.css +416 -0
  243. package/dist/components/tree-select.mjs +3 -0
  244. package/dist/components/upload.css +135 -92
  245. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  246. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  247. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  248. package/dist/fonts/OFL.txt +96 -0
  249. package/dist/fonts/README.md +14 -0
  250. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  251. package/dist/index.d.mts +28 -14
  252. package/dist/index.mjs +20705 -9601
  253. package/dist/react.d.mts +91 -0
  254. package/dist/react.mjs +8208 -0
  255. package/dist/registry.json +130 -13
  256. package/dist/tokens/chinese.css +44 -0
  257. package/dist/tokens/colors.css +365 -1222
  258. package/dist/tokens/design.css +109 -0
  259. package/dist/tokens/dtcg.json +11198 -0
  260. package/dist/tokens/figma.variables.json +7017 -0
  261. package/dist/tokens/icon-masks.css +78 -0
  262. package/dist/tokens/pixel.css +50 -0
  263. package/dist/tokens/soviet.css +44 -0
  264. package/dist/tokens/style-profiles.css +36 -547
  265. package/dist/tokens/themes.json +308 -0
  266. package/dist/tokens/tokens-studio.json +6728 -0
  267. package/dist/tokens/typography.css +21 -18
  268. package/dist/tokens.css +1555 -1801
  269. package/dist/ui.css +11975 -9831
  270. package/dist/vue.d.mts +344 -0
  271. package/dist/vue.mjs +7781 -0
  272. package/docs/spec/ai-input-experience.md +75 -0
  273. package/docs/spec/ai-native.md +238 -147
  274. package/docs/spec/design-philosophy.md +189 -0
  275. package/docs/spec/design-primitives.md +196 -0
  276. package/docs/spec/kb-family.md +147 -115
  277. package/package.json +43 -8
  278. package/dist/retro-effects.css +0 -255
  279. package/dist/tokens/retro-effects.css +0 -255
  280. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  281. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @icen.ai/ui — 内联 SVG 字符串 → 消毒 SVGElement(全库单点,ai-core.svgIcon / notification / toast /
3
+ * back-top / charts 全部经此)。SSR 安全:无 document/DOMParser 返回 null。
4
+ *
5
+ * 纪律:
6
+ * - 缺 xmlns 自动补——image/svg+xml 是 XML 严格解析,无 xmlns 的 <svg> 落在空命名空间,
7
+ * 浏览器一律不渲染(图标作者按 HTML 习惯常省 xmlns,曾致库内 19 处图标存量隐身);
8
+ * - 消毒:剥全部 on* 事件属性、剔除 script/foreignObject 子树、剔除 javascript: 协议的
9
+ * href/xlink:href(纵深防御);
10
+ * - 只接纳 <svg> 根元素,解析失败/含 parsererror 返回 null(不猜不兜底)。
11
+ */
12
+ declare function parseSvg(source: string): SVGElement | null;
13
+
14
+ export { parseSvg };
@@ -0,0 +1,37 @@
1
+ // src/behaviors/svg-parse.ts
2
+ function parseSvg(source) {
3
+ if (typeof document === "undefined" || typeof DOMParser === "undefined") return null;
4
+ const trimmed = source.trimStart();
5
+ if (!trimmed.startsWith("<svg")) return null;
6
+ const src = /^<svg(?![^>]*\bxmlns[=:])/i.test(trimmed) ? trimmed.replace(/^<svg/i, '<svg xmlns="http://www.w3.org/2000/svg"') : trimmed;
7
+ let parsed;
8
+ try {
9
+ parsed = new DOMParser().parseFromString(src, "image/svg+xml");
10
+ } catch {
11
+ return null;
12
+ }
13
+ const root = parsed.documentElement;
14
+ if (!root || root.tagName.toLowerCase() !== "svg" || parsed.querySelector("parsererror")) return null;
15
+ const sanitize = (el) => {
16
+ for (const attr of Array.from(el.attributes)) {
17
+ const name = attr.name.toLowerCase();
18
+ if (name.startsWith("on")) el.removeAttribute(attr.name);
19
+ if ((name === "href" || name === "xlink:href") && attr.value.trim().toLowerCase().startsWith("javascript:")) {
20
+ el.removeAttribute(attr.name);
21
+ }
22
+ }
23
+ for (const child of Array.from(el.children)) {
24
+ const tag = child.tagName.toLowerCase();
25
+ if (tag === "script" || tag === "foreignobject") {
26
+ child.remove();
27
+ continue;
28
+ }
29
+ sanitize(child);
30
+ }
31
+ };
32
+ sanitize(root);
33
+ return document.importNode(root, true);
34
+ }
35
+ export {
36
+ parseSvg
37
+ };
@@ -1,7 +1,7 @@
1
1
  /**
2
- * 为 root 下每个 [data-tabs] 容器初始化(root 自身是 [data-tabs] 也算)。
2
+ * 为 root 下每个 [data-icen-tabs] 容器初始化(root 自身是 [data-icen-tabs] 也算)。
3
3
  * 返回销毁函数:调用后移除所有容器监听、window hashchange/resize 监听与行为层创建的
4
- * .tabs-ink 元素,并复位幂等标记(销毁后的容器可被再次 initTabs 重新接管)。
4
+ * .icen-tabs-ink 元素,并复位幂等标记(销毁后的容器可被再次 initTabs 重新接管)。
5
5
  * SSR 下返回 no-op 函数。
6
6
  */
7
7
  declare function initTabs(root?: ParentNode): () => void;
@@ -7,24 +7,24 @@ function emitIcen(source, type, detail) {
7
7
 
8
8
  // src/behaviors/tabs.ts
9
9
  function tabButtons(container) {
10
- return Array.from(container.querySelectorAll("[data-tab]"));
10
+ return Array.from(container.querySelectorAll("[data-icen-tab]"));
11
11
  }
12
12
  function tabNames(container) {
13
- return tabButtons(container).map((t) => t.getAttribute("data-tab")).filter((n) => n !== null);
13
+ return tabButtons(container).map((t) => t.getAttribute("data-icen-tab")).filter((n) => n !== null);
14
14
  }
15
15
  function currentHash() {
16
16
  return window.location.hash.replace(/^#/, "");
17
17
  }
18
18
  function hashWriteMethod(container) {
19
- const raw = container.getAttribute("data-tabs-hash");
19
+ const raw = container.getAttribute("data-icen-tabs-hash");
20
20
  if (raw === null || raw === "false") return null;
21
21
  return raw === "push" ? "push" : "replace";
22
22
  }
23
23
  function syncInk(container, name) {
24
- const btn = tabButtons(container).find((b) => b.getAttribute("data-tab") === name);
24
+ const btn = tabButtons(container).find((b) => b.getAttribute("data-icen-tab") === name);
25
25
  const tablist = btn?.parentElement;
26
26
  if (!btn || !tablist) return;
27
- const ink = tablist.querySelector(":scope > .tabs-ink");
27
+ const ink = tablist.querySelector(":scope > .icen-tabs-ink");
28
28
  if (!ink) return;
29
29
  ink.style.width = `${btn.offsetWidth}px`;
30
30
  ink.style.transform = `translateX(${btn.offsetLeft}px)`;
@@ -33,7 +33,7 @@ function activate(container, name, writeHash, emit = false) {
33
33
  const buttons = tabButtons(container);
34
34
  let matched = false;
35
35
  buttons.forEach((t) => {
36
- const on = t.getAttribute("data-tab") === name;
36
+ const on = t.getAttribute("data-icen-tab") === name;
37
37
  if (on) matched = true;
38
38
  t.classList.toggle("is-active", on);
39
39
  t.setAttribute("aria-selected", String(on));
@@ -41,13 +41,13 @@ function activate(container, name, writeHash, emit = false) {
41
41
  });
42
42
  if (!matched) return;
43
43
  let panel = null;
44
- container.querySelectorAll("[data-tab-panel]").forEach((p) => {
45
- const isOn = p.getAttribute("data-tab-panel") === name;
44
+ container.querySelectorAll("[data-icen-tab-panel]").forEach((p) => {
45
+ const isOn = p.getAttribute("data-icen-tab-panel") === name;
46
46
  p.hidden = !isOn;
47
47
  if (isOn) {
48
48
  panel = p;
49
49
  if (!p.getAttribute("aria-labelledby")) {
50
- const btn = buttons.find((b) => b.getAttribute("data-tab") === name);
50
+ const btn = buttons.find((b) => b.getAttribute("data-icen-tab") === name);
51
51
  if (btn?.id) p.setAttribute("aria-labelledby", btn.id);
52
52
  }
53
53
  }
@@ -58,7 +58,7 @@ function activate(container, name, writeHash, emit = false) {
58
58
  }
59
59
  syncInk(container, name);
60
60
  if (emit) {
61
- const index = buttons.findIndex((b) => b.getAttribute("data-tab") === name);
61
+ const index = buttons.findIndex((b) => b.getAttribute("data-icen-tab") === name);
62
62
  const tab = buttons[index] ?? null;
63
63
  emitIcen(container, "icen:tab-change", { tab, panel, index });
64
64
  }
@@ -86,7 +86,7 @@ function setup(container) {
86
86
  const el = container;
87
87
  if (el.__icenTabsInit) return void 0;
88
88
  const useHash = hashWriteMethod(container) !== null;
89
- const autoActivate = container.getAttribute("data-tabs-activation") === "auto";
89
+ const autoActivate = container.getAttribute("data-icen-tabs-activation") === "auto";
90
90
  const names = tabNames(container);
91
91
  if (names.length === 0) return;
92
92
  el.__icenTabsInit = true;
@@ -98,11 +98,11 @@ function setup(container) {
98
98
  const tablist = buttons[0]?.parentElement;
99
99
  if (tablist && !tablist.getAttribute("role")) tablist.setAttribute("role", "tablist");
100
100
  let ink = null;
101
- if (tablist instanceof HTMLElement && tablist.hasAttribute("data-tabs-ink")) {
101
+ if (tablist instanceof HTMLElement && tablist.hasAttribute("data-icen-tabs-ink")) {
102
102
  ink = document.createElement("div");
103
- ink.className = "tabs-ink";
103
+ ink.className = "icen-tabs-ink";
104
104
  ink.setAttribute("aria-hidden", "true");
105
- const initialBtn = buttons.find((b) => b.classList.contains("is-active")) ?? buttons.find((b) => b.getAttribute("data-tab") === names[0]);
105
+ const initialBtn = buttons.find((b) => b.classList.contains("is-active")) ?? buttons.find((b) => b.getAttribute("data-icen-tab") === names[0]);
106
106
  if (initialBtn) {
107
107
  ink.style.width = `${initialBtn.offsetWidth}px`;
108
108
  ink.style.transform = `translateX(${initialBtn.offsetLeft}px)`;
@@ -112,10 +112,10 @@ function setup(container) {
112
112
  const onClick = (ev) => {
113
113
  const target = ev.target;
114
114
  if (!(target instanceof Element)) return;
115
- const btn = target.closest("[data-tab]");
116
- if (!btn || btn.closest("[data-tabs]") !== container) return;
115
+ const btn = target.closest("[data-icen-tab]");
116
+ if (!btn || btn.closest("[data-icen-tabs]") !== container) return;
117
117
  if (btn instanceof HTMLElement && isDisabled(btn)) return;
118
- const name = btn.getAttribute("data-tab");
118
+ const name = btn.getAttribute("data-icen-tab");
119
119
  if (name) activate(container, name, useHash, true);
120
120
  };
121
121
  const followFocus = (idx) => {
@@ -123,15 +123,15 @@ function setup(container) {
123
123
  if (!autoActivate) return;
124
124
  const target = tabButtons(container)[idx];
125
125
  if (!target || isDisabled(target)) return;
126
- const name = target.getAttribute("data-tab");
126
+ const name = target.getAttribute("data-icen-tab");
127
127
  if (name) activate(container, name, useHash, true);
128
128
  };
129
129
  const onKeyDown = (ev) => {
130
130
  const kev = ev;
131
131
  const target = kev.target;
132
132
  if (!(target instanceof Element)) return;
133
- const btn = target.closest("[data-tab]");
134
- if (!btn || btn.closest("[data-tabs]") !== container) return;
133
+ const btn = target.closest("[data-icen-tab]");
134
+ if (!btn || btn.closest("[data-icen-tabs]") !== container) return;
135
135
  const buttonsList = tabButtons(container);
136
136
  const currentIdx = buttonsList.indexOf(btn);
137
137
  if (currentIdx === -1) return;
@@ -162,7 +162,7 @@ function setup(container) {
162
162
  case " ": {
163
163
  if (btn instanceof HTMLElement && !isDisabled(btn)) {
164
164
  kev.preventDefault();
165
- const name = btn.getAttribute("data-tab");
165
+ const name = btn.getAttribute("data-icen-tab");
166
166
  if (name) activate(container, name, useHash, true);
167
167
  }
168
168
  break;
@@ -176,7 +176,7 @@ function setup(container) {
176
176
  const h = currentHash();
177
177
  if (names.includes(h)) initial = h;
178
178
  } else {
179
- const n = container.querySelector("[data-tab].is-active")?.getAttribute("data-tab");
179
+ const n = container.querySelector("[data-icen-tab].is-active")?.getAttribute("data-icen-tab");
180
180
  if (n && names.includes(n)) initial = n;
181
181
  }
182
182
  activate(container, initial ?? names[0], false);
@@ -189,7 +189,7 @@ function setup(container) {
189
189
  }
190
190
  const onResize = () => {
191
191
  const active = tabButtons(container).find((b) => b.classList.contains("is-active"));
192
- const name = active?.getAttribute("data-tab");
192
+ const name = active?.getAttribute("data-icen-tab");
193
193
  if (name) syncInk(container, name);
194
194
  };
195
195
  if (ink && typeof window !== "undefined") {
@@ -213,8 +213,8 @@ function initTabs(root) {
213
213
  if (typeof document !== "undefined") {
214
214
  const scope = root ?? document;
215
215
  const containers = [];
216
- if (scope instanceof Element && scope.matches("[data-tabs]")) containers.push(scope);
217
- containers.push(...Array.from(scope.querySelectorAll("[data-tabs]")));
216
+ if (scope instanceof Element && scope.matches("[data-icen-tabs]")) containers.push(scope);
217
+ containers.push(...Array.from(scope.querySelectorAll("[data-icen-tabs]")));
218
218
  for (const c of containers) {
219
219
  const cleanup = setup(c);
220
220
  if (cleanup) cleanups.push(cleanup);
@@ -1,7 +1,25 @@
1
- /**
2
- * 为 root 下每个 .tag-input 容器初始化(root 自身匹配也算;data-tags 为可选初始值配置)。
3
- * 返回销毁函数:移除本次挂上的全部监听并复位幂等标记(销毁后可重新 init)。SSR 下返回 no-op。
4
- */
1
+ interface TagInputOptions {
2
+ value?: string[];
3
+ max?: number;
4
+ allowDuplicates?: boolean;
5
+ disabled?: boolean;
6
+ readOnly?: boolean;
7
+ /** Repeated native form entries, one per committed tag. Defaults to input.name. */
8
+ name?: string;
9
+ }
10
+ interface TagInputHandle {
11
+ getValue(): string[];
12
+ setValue(value: string[], options?: {
13
+ emit?: boolean;
14
+ }): void;
15
+ update(options: Omit<TagInputOptions, 'value'>): void;
16
+ focus(): void;
17
+ destroy(): void;
18
+ }
19
+ /** Explicit lifecycle handle; repeated creation reuses the editor and updates options. */
20
+ declare function createTagInput(root: HTMLElement, options?: TagInputOptions): TagInputHandle;
21
+ /** Dynamic scoped initialization. Overlapping scopes share each editor and only
22
+ * the last scope disposes it; an explicit createTagInput handle owns its lifecycle. */
5
23
  declare function initTagInput(root?: ParentNode): () => void;
6
24
 
7
- export { initTagInput };
25
+ export { type TagInputHandle, type TagInputOptions, createTagInput, initTagInput };