@greypan/web-ui 8.0.0 → 9.0.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 (189) hide show
  1. package/README.CN.md +277 -146
  2. package/README.md +323 -191
  3. package/dist/assets/glass.js +1 -1
  4. package/dist/assets/glass.js.map +1 -1
  5. package/dist/assets/menu-portal.js +1 -1
  6. package/dist/assets/menu-portal.js.map +1 -1
  7. package/dist/assets/selection-control.js +1 -1
  8. package/dist/assets/selection-control.js.map +1 -1
  9. package/dist/assets/toast-containers.js +1 -1
  10. package/dist/assets/toast-containers.js.map +1 -1
  11. package/dist/components/autocomplete/index.d.ts +3 -2
  12. package/dist/components/autocomplete/index.js +46 -50
  13. package/dist/components/autocomplete/index.js.map +1 -1
  14. package/dist/components/autocomplete/style.js +1 -1
  15. package/dist/components/autocomplete/style.js.map +1 -1
  16. package/dist/components/avatar/index.js.map +1 -1
  17. package/dist/components/avatar/style.js +1 -1
  18. package/dist/components/avatar/style.js.map +1 -1
  19. package/dist/components/back-top/style.js +1 -1
  20. package/dist/components/back-top/style.js.map +1 -1
  21. package/dist/components/badge/style.js +1 -1
  22. package/dist/components/badge/style.js.map +1 -1
  23. package/dist/components/button/index.d.ts +368 -1
  24. package/dist/components/button/index.js +56 -36
  25. package/dist/components/button/index.js.map +1 -1
  26. package/dist/components/button/style.js +1 -1
  27. package/dist/components/button/style.js.map +1 -1
  28. package/dist/components/button-group/index.js +0 -1
  29. package/dist/components/button-group/index.js.map +1 -1
  30. package/dist/components/button-group/style.js +1 -1
  31. package/dist/components/button-group/style.js.map +1 -1
  32. package/dist/components/checkbox/index.d.ts +3 -0
  33. package/dist/components/checkbox/index.js +35 -37
  34. package/dist/components/checkbox/index.js.map +1 -1
  35. package/dist/components/checkbox/style.js +1 -1
  36. package/dist/components/checkbox/style.js.map +1 -1
  37. package/dist/components/checkbox-group/index.js +8 -8
  38. package/dist/components/checkbox-group/style.js +1 -1
  39. package/dist/components/checkbox-group/style.js.map +1 -1
  40. package/dist/components/context-menu/index.d.ts +167 -3
  41. package/dist/components/context-menu/index.js +162 -91
  42. package/dist/components/context-menu/index.js.map +1 -1
  43. package/dist/components/context-menu/scrim.js +6 -0
  44. package/dist/components/context-menu/scrim.js.map +1 -0
  45. package/dist/components/context-menu/style.js +1 -1
  46. package/dist/components/context-menu/style.js.map +1 -1
  47. package/dist/components/dialog/index.d.ts +9 -0
  48. package/dist/components/dialog/index.js +61 -46
  49. package/dist/components/dialog/index.js.map +1 -1
  50. package/dist/components/dialog/style.js +1 -1
  51. package/dist/components/dialog/style.js.map +1 -1
  52. package/dist/components/drawer/index.d.ts +45 -0
  53. package/dist/components/drawer/index.js +116 -52
  54. package/dist/components/drawer/index.js.map +1 -1
  55. package/dist/components/drawer/style.js +1 -1
  56. package/dist/components/drawer/style.js.map +1 -1
  57. package/dist/components/dropdown/index.d.ts +12 -0
  58. package/dist/components/dropdown/index.js +13 -10
  59. package/dist/components/dropdown/index.js.map +1 -1
  60. package/dist/components/dropdown-divider/style.js +1 -1
  61. package/dist/components/dropdown-divider/style.js.map +1 -1
  62. package/dist/components/dropdown-header/style.js +1 -1
  63. package/dist/components/dropdown-header/style.js.map +1 -1
  64. package/dist/components/dropdown-item/style.js +1 -1
  65. package/dist/components/dropdown-item/style.js.map +1 -1
  66. package/dist/components/editable-text/index.d.ts +41 -0
  67. package/dist/components/editable-text/index.js +55 -31
  68. package/dist/components/editable-text/index.js.map +1 -1
  69. package/dist/components/empty/index.d.ts +21 -4
  70. package/dist/components/empty/index.js +37 -32
  71. package/dist/components/empty/index.js.map +1 -1
  72. package/dist/components/empty/style.js +1 -1
  73. package/dist/components/empty/style.js.map +1 -1
  74. package/dist/components/icon/index.js +7 -7
  75. package/dist/components/icon/index.js.map +1 -1
  76. package/dist/components/image-preview/index.js +9 -2
  77. package/dist/components/image-preview/index.js.map +1 -1
  78. package/dist/components/image-preview/style.js +1 -1
  79. package/dist/components/image-preview/style.js.map +1 -1
  80. package/dist/components/index.js +23 -23
  81. package/dist/components/input/index.d.ts +7 -0
  82. package/dist/components/input/index.js +34 -29
  83. package/dist/components/input/index.js.map +1 -1
  84. package/dist/components/input/style.js +1 -1
  85. package/dist/components/input/style.js.map +1 -1
  86. package/dist/components/input-number/index.d.ts +1 -0
  87. package/dist/components/input-number/index.js +28 -26
  88. package/dist/components/input-number/index.js.map +1 -1
  89. package/dist/components/input-number/style.js +1 -1
  90. package/dist/components/input-number/style.js.map +1 -1
  91. package/dist/components/layout/index.d.ts +0 -3
  92. package/dist/components/layout/index.js +1 -1
  93. package/dist/components/layout/index.js.map +1 -1
  94. package/dist/components/layout/style.js +1 -1
  95. package/dist/components/layout/style.js.map +1 -1
  96. package/dist/components/option/style.js +1 -1
  97. package/dist/components/option/style.js.map +1 -1
  98. package/dist/components/popover/index.js.map +1 -1
  99. package/dist/components/popover/style.js +1 -1
  100. package/dist/components/popover/style.js.map +1 -1
  101. package/dist/components/radio/index.d.ts +3 -0
  102. package/dist/components/radio/index.js +23 -19
  103. package/dist/components/radio/index.js.map +1 -1
  104. package/dist/components/radio/style.js +1 -1
  105. package/dist/components/radio/style.js.map +1 -1
  106. package/dist/components/radio-group/index.js +8 -8
  107. package/dist/components/radio-group/style.js +1 -1
  108. package/dist/components/radio-group/style.js.map +1 -1
  109. package/dist/components/segmented/index.d.ts +5 -0
  110. package/dist/components/segmented/index.js +49 -32
  111. package/dist/components/segmented/index.js.map +1 -1
  112. package/dist/components/segmented/style.js +1 -1
  113. package/dist/components/segmented/style.js.map +1 -1
  114. package/dist/components/segmented-trigger/style.js +1 -1
  115. package/dist/components/segmented-trigger/style.js.map +1 -1
  116. package/dist/components/select/index.js +0 -1
  117. package/dist/components/select/index.js.map +1 -1
  118. package/dist/components/select/style.js +1 -1
  119. package/dist/components/select/style.js.map +1 -1
  120. package/dist/components/slider/index.js +9 -9
  121. package/dist/components/slider/style.js +1 -1
  122. package/dist/components/slider/style.js.map +1 -1
  123. package/dist/components/spinner/style.js +1 -1
  124. package/dist/components/spinner/style.js.map +1 -1
  125. package/dist/components/svg-draw-lines/index.js.map +1 -1
  126. package/dist/components/switch/index.d.ts +1 -0
  127. package/dist/components/switch/index.js +26 -24
  128. package/dist/components/switch/index.js.map +1 -1
  129. package/dist/components/switch/style.js +1 -1
  130. package/dist/components/switch/style.js.map +1 -1
  131. package/dist/components/textarea/index.d.ts +7 -1
  132. package/dist/components/textarea/index.js +45 -43
  133. package/dist/components/textarea/index.js.map +1 -1
  134. package/dist/components/textarea/style.js +1 -1
  135. package/dist/components/textarea/style.js.map +1 -1
  136. package/dist/components/theme/index.d.ts +9 -0
  137. package/dist/components/theme/index.js +128 -85
  138. package/dist/components/theme/index.js.map +1 -1
  139. package/dist/components/theme/style.js +1 -1
  140. package/dist/components/theme/style.js.map +1 -1
  141. package/dist/components/toast/style.js +1 -1
  142. package/dist/components/toast/style.js.map +1 -1
  143. package/dist/components/toast/toast.js +8 -8
  144. package/dist/components/toast/toast.js.map +1 -1
  145. package/dist/components/tooltip/index.js.map +1 -1
  146. package/dist/components/tooltip/style.js +1 -1
  147. package/dist/components/tooltip/style.js.map +1 -1
  148. package/dist/icons/generated/akar-icons-check.d.ts +6 -0
  149. package/dist/icons/generated/akar-icons-check.js +10 -0
  150. package/dist/icons/generated/akar-icons-check.js.map +1 -0
  151. package/dist/icons/generated/akar-icons-circle-check.d.ts +6 -0
  152. package/dist/icons/generated/akar-icons-circle-check.js +10 -0
  153. package/dist/icons/generated/akar-icons-circle-check.js.map +1 -0
  154. package/dist/icons/generated/bi-check-lg.d.ts +6 -0
  155. package/dist/icons/generated/bi-check-lg.js +10 -0
  156. package/dist/icons/generated/bi-check-lg.js.map +1 -0
  157. package/dist/icons/generated/bi-check.d.ts +6 -0
  158. package/dist/icons/generated/bi-check.js +10 -0
  159. package/dist/icons/generated/bi-check.js.map +1 -0
  160. package/dist/icons/generated/fluent-tag-search-24-regular.d.ts +6 -0
  161. package/dist/icons/generated/fluent-tag-search-24-regular.js +10 -0
  162. package/dist/icons/generated/fluent-tag-search-24-regular.js.map +1 -0
  163. package/dist/icons/generated/mdi-tag-search-outline.d.ts +6 -0
  164. package/dist/icons/generated/mdi-tag-search-outline.js +10 -0
  165. package/dist/icons/generated/mdi-tag-search-outline.js.map +1 -0
  166. package/dist/icons/index.d.ts +6 -0
  167. package/dist/icons/index.js +7 -1
  168. package/dist/shared/element-height/index.js +47 -0
  169. package/dist/shared/element-height/index.js.map +1 -0
  170. package/dist/shared/form-association/field-id.js +9 -0
  171. package/dist/shared/form-association/field-id.js.map +1 -0
  172. package/dist/shared/form-association/index.js +9 -1
  173. package/dist/shared/form-association/index.js.map +1 -1
  174. package/dist/shared/label-emptiness/index.js +45 -0
  175. package/dist/shared/label-emptiness/index.js.map +1 -0
  176. package/dist/shared/menu-portal/menu-portal.js +11 -11
  177. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  178. package/dist/shared/menu-portal/menu-tree.js +2 -2
  179. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  180. package/dist/shared/overlay/anchored-panel.js.map +1 -1
  181. package/dist/shared/overlay/native-dialog-presence.js +23 -11
  182. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  183. package/dist/shared/overlay/nested-drawer-layers.js +30 -23
  184. package/dist/shared/overlay/nested-drawer-layers.js.map +1 -1
  185. package/dist/shared/scroll-lock/scroll-lock.js +3 -3
  186. package/dist/shared/scroll-lock/scroll-lock.js.map +1 -1
  187. package/dist/shared/theme/root-sync.js +24 -18
  188. package/dist/shared/theme/root-sync.js.map +1 -1
  189. package/package.json +8 -4
@@ -1,42 +1,48 @@
1
1
  //#region src/shared/theme/root-sync.ts
2
- var e = "--wui-color-page", t = /* @__PURE__ */ new Set(), n;
3
- function r(e) {
2
+ var e = "--wui-color-page", t = /* @__PURE__ */ new Set(), n, r = /* @__PURE__ */ new Set();
3
+ function i(e) {
4
4
  return t.values().next().value === e;
5
5
  }
6
- function i(t) {
6
+ function a(t) {
7
7
  return getComputedStyle(t).getPropertyValue(e).trim();
8
8
  }
9
- function a() {
9
+ function o() {
10
10
  let n = t.values().next().value;
11
11
  if (!n || !n.isConnected) return;
12
- let r = i(n);
12
+ let r = a(n);
13
13
  if (!r) return;
14
- let a = document.documentElement.style;
15
- a.getPropertyValue(e) !== r && a.setProperty(e, r);
16
- }
17
- function o() {
18
- a();
14
+ let i = document.documentElement.style;
15
+ i.getPropertyValue(e) !== r && i.setProperty(e, r);
19
16
  }
20
17
  function s() {
21
- if (t.size > 0) {
18
+ o();
19
+ for (let e of r) e();
20
+ }
21
+ function c() {
22
+ if (t.size > 0 || r.size > 0) {
22
23
  if (n) return;
23
24
  try {
24
25
  n = window.matchMedia("(prefers-color-scheme: dark)");
25
26
  } catch {
26
27
  return;
27
28
  }
28
- n.addEventListener("change", o);
29
+ n.addEventListener("change", s);
29
30
  return;
30
31
  }
31
- n &&= (n.removeEventListener("change", o), void 0);
32
- }
33
- function c(e) {
34
- t.add(e), s(), r(e) && a();
32
+ n &&= (n.removeEventListener("change", s), void 0);
35
33
  }
36
34
  function l(e) {
37
- t.delete(e) && (s(), a());
35
+ return r.add(e), c(), () => {
36
+ r.delete(e) && c();
37
+ };
38
+ }
39
+ function u(e) {
40
+ t.add(e), c(), i(e) && o();
41
+ }
42
+ function d(e) {
43
+ t.delete(e) && (c(), o());
38
44
  }
39
45
  //#endregion
40
- export { c as registerThemeRootSync, l as unregisterThemeRootSync };
46
+ export { u as registerThemeRootSync, l as subscribeThemeSystemAppearanceChange, d as unregisterThemeRootSync };
41
47
 
42
48
  //# sourceMappingURL=root-sync.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"root-sync.js","names":[],"sources":["../../../src/shared/theme/root-sync.ts"],"sourcesContent":["/**\n * 根节点 page 色同步 —— 「哪一层最外层」的唯一拥有者。\n *\n * macOS 橡皮筋回弹露白的成因不在 body 而在画布:body 的背景只覆盖滚动范围,回弹时被扯出来的\n * 那一圈用的是 documentElement 的画布背景。而 `--wui-color-page` 定义在 `<web-ui-theme>` 的\n * shadow 作用域里,自定义属性的继承链到 documentElement 就断了,所以消费方写\n * `body { background: var(--wui-color-page) }` 也管不到回弹区。\n *\n * 本模块补上这一环:最外层 active theme 把自己计算出的 `--wui-color-page` 写到 documentElement\n * 的行内自定义属性上,消费方仍然只需要那一行 body 规则。\n *\n * 为什么按 connect 顺序取「第一个 active 实例」,而不是去判「DOM 上最外层的那一个」:\n * 组件无法可靠地回答后者——portal、shadow host 与 slot 都会让「谁包着谁」的物理关系和主题\n * 作用域不一致(`WebUiTheme._findThemeAncestor()` 正是为此单独实现了跨 shadow 边界的祖先链)。\n * root 值只可能有一个来源,按 connect 顺序取第一个是唯一不需要猜树形状的判据,且与用户视角\n * 一致:嵌套主题总是后 connect,先进页面那个主题范围就是盖住整页的那个。\n *\n * 其余取舍:\n *\n * - 同步权在已登记实例之间按同一顺序顺延:最外层断开时下一个已连接实例接管,不查 DOM。\n * 重新挂载的实例按新的一次 connect 排到队尾——队首才是当前 outermost。\n * - 写入值取该实例的**计算值**,因此消费者在 host 上覆盖 `--wui-color-page`(包括在自己的\n * 媒体查询里覆盖)会被原样镜像,主题与消费者的优先级关系不因此改变。\n * - 全部断开时**保留最后值**:清掉属性会让 body 背景在主题卸载/重挂的间隙闪回 UA 白底,\n * 而那正是本能力要消除的观感。代价是最后一个主题卸载后 documentElement 上仍留着一个自定义\n * 属性;消费者自己写 body 背景时它不产生任何影响。\n * - `appearance=\"system\"` 的计算值由组件内部 CSS 的 `prefers-color-scheme` 媒体查询决定,JS 侧\n * 没有订阅,所以登记表非空期间挂一个系统 scheme 监听,翻转时重算。\n * - 登记表强引用实例,但删除路径只有组件自己的 disconnectedCallback:自定义元素反应保证移除\n * 必然触发它,不存在 open-overlay 那种「面板被 portal 搬运」需要惰性兜底回收的形状。\n */\n\nconst ROOT_PAGE_TOKEN = '--wui-color-page'\n\n/** 按 connect 顺序排列的已登记 active 实例;队首持有 root 同步权。 */\nconst registered = new Set<HTMLElement>()\n\nlet schemeQuery: MediaQueryList | undefined\n\n/*\n * dev 期测试钩子:登记表尺寸。\n *\n * 「组件卸载后忘了撤销登记」是这层唯一的结构性风险,而 `registered` 无法从公开面观察——\n * 调用方只看见 documentElement 上的值,看不到注册表。有了它,泄漏在测试里是一个可直接断言的\n * 数字。`import.meta.env.DEV` 是编译期常量,生产构建里整段消失。\n */\ndeclare global {\n // eslint-disable-next-line no-var\n var __webUiThemeRootSyncCount: () => number\n}\n\nif (import.meta.env.DEV) {\n globalThis.__webUiThemeRootSyncCount = () => registered.size\n}\n\nfunction isRootSyncOwner(host: HTMLElement): boolean {\n return registered.values().next().value === host\n}\n\n/** 计算值可能为空(jsdom、未激活作用域、已断开),空值不写入也不删除既有值。 */\nfunction readPageColor(host: HTMLElement): string {\n return getComputedStyle(host).getPropertyValue(ROOT_PAGE_TOKEN).trim()\n}\n\nfunction syncRootPageColor(): void {\n const owner = registered.values().next().value as HTMLElement | undefined\n if (!owner) return\n // 已断开的所有者不能再写 root:整棵子树一起卸载时,队首顺延到的实例已经不在文档里\n // (浏览器对 detached 元素取不到计算值,jsdom 却仍按选择器匹配返回旧值),\n // 不设这道坎就会在两种环境里得到不同的 root 末值。\n if (!owner.isConnected) return\n const value = readPageColor(owner)\n if (!value) return\n const style = document.documentElement.style\n // 与当前行内值比较而不是与模块记忆的上次写入比较:消费者中途覆写时,下一次同步仍然夺回\n // 归属权,而值没变时不做无谓的样式写入。\n if (style.getPropertyValue(ROOT_PAGE_TOKEN) === value) return\n style.setProperty(ROOT_PAGE_TOKEN, value)\n}\n\nfunction handleSchemeChange(): void {\n syncRootPageColor()\n}\n\nfunction syncSchemeListener(): void {\n if (registered.size > 0) {\n if (schemeQuery) return\n try {\n schemeQuery = window.matchMedia('(prefers-color-scheme: dark)')\n } catch {\n // jsdom 等没有 matchMedia 的环境:system 档跟随不到系统翻转,登记表行为不受影响。\n return\n }\n schemeQuery.addEventListener('change', handleSchemeChange)\n return\n }\n if (!schemeQuery) return\n schemeQuery.removeEventListener('change', handleSchemeChange)\n schemeQuery = undefined\n}\n\n/**\n * 登记一个 active theme。幂等,组件的 connectedCallback 与 updated() 可以无条件调用:\n * 已在表中的实例重复登记保留原队序,只有队首实例会刷新 root 值。\n */\nexport function registerThemeRootSync(host: HTMLElement): void {\n registered.add(host)\n syncSchemeListener()\n // 嵌套实例的变更按契约不影响 root 值;顺延不到新实例时 root 值同样不变。\n if (!isRootSyncOwner(host)) return\n syncRootPageColor()\n}\n\n/** 撤销登记。移交同步权时由新的队首实例立即接管 root 值。 */\nexport function unregisterThemeRootSync(host: HTMLElement): void {\n if (!registered.delete(host)) return\n syncSchemeListener()\n syncRootPageColor()\n}\n"],"mappings":";AAgCA,IAAM,IAAkB,oBAGlB,oBAAa,IAAI,IAAiB,GAEpC;AAkBJ,SAAS,EAAgB,GAA4B;CACnD,OAAO,EAAW,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU;AAC9C;AAGA,SAAS,EAAc,GAA2B;CAChD,OAAO,iBAAiB,CAAI,CAAC,CAAC,iBAAiB,CAAe,CAAC,CAAC,KAAK;AACvE;AAEA,SAAS,IAA0B;CACjC,IAAM,IAAQ,EAAW,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;CAKzC,IAJI,CAAC,KAID,CAAC,EAAM,aAAa;CACxB,IAAM,IAAQ,EAAc,CAAK;CACjC,IAAI,CAAC,GAAO;CACZ,IAAM,IAAQ,SAAS,gBAAgB;CAGnC,EAAM,iBAAiB,CAAe,MAAM,KAChD,EAAM,YAAY,GAAiB,CAAK;AAC1C;AAEA,SAAS,IAA2B;CAClC,EAAkB;AACpB;AAEA,SAAS,IAA2B;CAClC,IAAI,EAAW,OAAO,GAAG;EACvB,IAAI,GAAa;EACjB,IAAI;GACF,IAAc,OAAO,WAAW,8BAA8B;EAChE,QAAQ;GAEN;EACF;EACA,EAAY,iBAAiB,UAAU,CAAkB;EACzD;CACF;CACK,AAEL,OADA,EAAY,oBAAoB,UAAU,CAAkB,GAC9C,KAAA;AAChB;AAMA,SAAgB,EAAsB,GAAyB;CAC7D,EAAW,IAAI,CAAI,GACnB,EAAmB,GAEd,EAAgB,CAAI,KACzB,EAAkB;AACpB;AAGA,SAAgB,EAAwB,GAAyB;CAC1D,EAAW,OAAO,CAAI,MAC3B,EAAmB,GACnB,EAAkB;AACpB"}
1
+ {"version":3,"file":"root-sync.js","names":[],"sources":["../../../src/shared/theme/root-sync.ts"],"sourcesContent":["/**\n * 根节点 page 色同步 —— 「哪一层最外层」的唯一拥有者。\n *\n * macOS 橡皮筋回弹露白的成因不在 body 而在画布:body 的背景只覆盖滚动范围,回弹时被扯出来的\n * 那一圈用的是 documentElement 的画布背景。而 `--wui-color-page` 定义在 `<web-ui-theme>` 的\n * shadow 作用域里,自定义属性的继承链到 documentElement 就断了,所以消费方写\n * `body { background: var(--wui-color-page) }` 也管不到回弹区。\n *\n * 本模块补上这一环:最外层 active theme 把自己计算出的 `--wui-color-page` 写到 documentElement\n * 的行内自定义属性上,消费方仍然只需要那一行 body 规则。\n *\n * 为什么按 connect 顺序取「第一个 active 实例」,而不是去判「DOM 上最外层的那一个」:\n * 组件无法可靠地回答后者——portal、shadow host 与 slot 都会让「谁包着谁」的物理关系和主题\n * 作用域不一致(`WebUiTheme._findThemeAncestor()` 正是为此单独实现了跨 shadow 边界的祖先链)。\n * root 值只可能有一个来源,按 connect 顺序取第一个是唯一不需要猜树形状的判据,且与用户视角\n * 一致:嵌套主题总是后 connect,先进页面那个主题范围就是盖住整页的那个。\n *\n * 其余取舍:\n *\n * - 同步权在已登记实例之间按同一顺序顺延:最外层断开时下一个已连接实例接管,不查 DOM。\n * 重新挂载的实例按新的一次 connect 排到队尾——队首才是当前 outermost。\n * - 写入值取该实例的**计算值**,因此消费者在 host 上覆盖 `--wui-color-page`(包括在自己的\n * 媒体查询里覆盖)会被原样镜像,主题与消费者的优先级关系不因此改变。\n * - 全部断开时**保留最后值**:清掉属性会让 body 背景在主题卸载/重挂的间隙闪回 UA 白底,\n * 而那正是本能力要消除的观感。代价是最后一个主题卸载后 documentElement 上仍留着一个自定义\n * 属性;消费者自己写 body 背景时它不产生任何影响。\n * - `appearance=\"system\"` 的 token 计算值仍由组件内部 CSS 的 `prefers-color-scheme` 决定;\n * root 同步与 `resolved-appearance` 输出共用同一个 MediaQueryList 监听,翻转时一次重算。\n * - 登记表强引用实例,但删除路径只有组件自己的 disconnectedCallback:自定义元素反应保证移除\n * 必然触发它,不存在 open-overlay 那种「面板被 portal 搬运」需要惰性兜底回收的形状。\n */\n\nconst ROOT_PAGE_TOKEN = '--wui-color-page'\n\n/** 按 connect 顺序排列的已登记 active 实例;队首持有 root 同步权。 */\nconst registered = new Set<HTMLElement>()\n\nlet schemeQuery: MediaQueryList | undefined\nconst schemeSubscribers = new Set<() => void>()\n\n/*\n * dev 期测试钩子:登记表尺寸。\n *\n * 「组件卸载后忘了撤销登记」是这层唯一的结构性风险,而 `registered` 无法从公开面观察——\n * 调用方只看见 documentElement 上的值,看不到注册表。有了它,泄漏在测试里是一个可直接断言的\n * 数字。`import.meta.env.DEV` 是编译期常量,生产构建里整段消失。\n */\ndeclare global {\n // eslint-disable-next-line no-var\n var __webUiThemeRootSyncCount: () => number\n}\n\nif (import.meta.env.DEV) {\n globalThis.__webUiThemeRootSyncCount = () => registered.size\n}\n\nfunction isRootSyncOwner(host: HTMLElement): boolean {\n return registered.values().next().value === host\n}\n\n/** 计算值可能为空(jsdom、未激活作用域、已断开),空值不写入也不删除既有值。 */\nfunction readPageColor(host: HTMLElement): string {\n return getComputedStyle(host).getPropertyValue(ROOT_PAGE_TOKEN).trim()\n}\n\nfunction syncRootPageColor(): void {\n const owner = registered.values().next().value as HTMLElement | undefined\n if (!owner) return\n // 已断开的所有者不能再写 root:整棵子树一起卸载时,队首顺延到的实例已经不在文档里\n // (浏览器对 detached 元素取不到计算值,jsdom 却仍按选择器匹配返回旧值),\n // 不设这道坎就会在两种环境里得到不同的 root 末值。\n if (!owner.isConnected) return\n const value = readPageColor(owner)\n if (!value) return\n const style = document.documentElement.style\n // 与当前行内值比较而不是与模块记忆的上次写入比较:消费者中途覆写时,下一次同步仍然夺回\n // 归属权,而值没变时不做无谓的样式写入。\n if (style.getPropertyValue(ROOT_PAGE_TOKEN) === value) return\n style.setProperty(ROOT_PAGE_TOKEN, value)\n}\n\nfunction handleSchemeChange(): void {\n syncRootPageColor()\n for (const subscriber of schemeSubscribers) subscriber()\n}\n\nfunction syncSchemeListener(): void {\n if (registered.size > 0 || schemeSubscribers.size > 0) {\n if (schemeQuery) return\n try {\n schemeQuery = window.matchMedia('(prefers-color-scheme: dark)')\n } catch {\n // jsdom 等没有 matchMedia 的环境:system 档跟随不到系统翻转,登记与输出仍保持当前值。\n return\n }\n schemeQuery.addEventListener('change', handleSchemeChange)\n return\n }\n if (!schemeQuery) return\n schemeQuery.removeEventListener('change', handleSchemeChange)\n schemeQuery = undefined\n}\n\n/*\n * 复用 root 同步已经持有的系统 scheme 监听:resolved-appearance 只登记回调,不另建 MediaQueryList。\n * 登记先于订阅或订阅先于登记都可以;syncSchemeListener 以两者任一非空为准。\n */\nexport function subscribeThemeSystemAppearanceChange(listener: () => void): () => void {\n schemeSubscribers.add(listener)\n syncSchemeListener()\n return () => {\n if (!schemeSubscribers.delete(listener)) return\n syncSchemeListener()\n }\n}\n\n/**\n * 登记一个 active theme。幂等,组件的 connectedCallback 与 updated() 可以无条件调用:\n * 已在表中的实例重复登记保留原队序,只有队首实例会刷新 root 值。\n */\nexport function registerThemeRootSync(host: HTMLElement): void {\n registered.add(host)\n syncSchemeListener()\n // 嵌套实例的变更按契约不影响 root 值;顺延不到新实例时 root 值同样不变。\n if (!isRootSyncOwner(host)) return\n syncRootPageColor()\n}\n\n/** 撤销登记。移交同步权时由新的队首实例立即接管 root 值。 */\nexport function unregisterThemeRootSync(host: HTMLElement): void {\n if (!registered.delete(host)) return\n syncSchemeListener()\n syncRootPageColor()\n}\n"],"mappings":";AAgCA,IAAM,IAAkB,oBAGlB,oBAAa,IAAI,IAAiB,GAEpC,GACE,oBAAoB,IAAI,IAAgB;AAkB9C,SAAS,EAAgB,GAA4B;CACnD,OAAO,EAAW,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU;AAC9C;AAGA,SAAS,EAAc,GAA2B;CAChD,OAAO,iBAAiB,CAAI,CAAC,CAAC,iBAAiB,CAAe,CAAC,CAAC,KAAK;AACvE;AAEA,SAAS,IAA0B;CACjC,IAAM,IAAQ,EAAW,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;CAKzC,IAJI,CAAC,KAID,CAAC,EAAM,aAAa;CACxB,IAAM,IAAQ,EAAc,CAAK;CACjC,IAAI,CAAC,GAAO;CACZ,IAAM,IAAQ,SAAS,gBAAgB;CAGnC,EAAM,iBAAiB,CAAe,MAAM,KAChD,EAAM,YAAY,GAAiB,CAAK;AAC1C;AAEA,SAAS,IAA2B;CAClC,EAAkB;CAClB,KAAK,IAAM,KAAc,GAAmB,EAAW;AACzD;AAEA,SAAS,IAA2B;CAClC,IAAI,EAAW,OAAO,KAAK,EAAkB,OAAO,GAAG;EACrD,IAAI,GAAa;EACjB,IAAI;GACF,IAAc,OAAO,WAAW,8BAA8B;EAChE,QAAQ;GAEN;EACF;EACA,EAAY,iBAAiB,UAAU,CAAkB;EACzD;CACF;CACK,AAEL,OADA,EAAY,oBAAoB,UAAU,CAAkB,GAC9C,KAAA;AAChB;AAMA,SAAgB,EAAqC,GAAkC;CAGrF,OAFA,EAAkB,IAAI,CAAQ,GAC9B,EAAmB,SACN;EACN,EAAkB,OAAO,CAAQ,KACtC,EAAmB;CACrB;AACF;AAMA,SAAgB,EAAsB,GAAyB;CAC7D,EAAW,IAAI,CAAI,GACnB,EAAmB,GAEd,EAAgB,CAAI,KACzB,EAAkB;AACpB;AAGA,SAAgB,EAAwB,GAAyB;CAC1D,EAAW,OAAO,CAAI,MAC3B,EAAmB,GACnB,EAAkB;AACpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greypan/web-ui",
3
- "version": "8.0.0",
3
+ "version": "9.0.0",
4
4
  "description": "Lit-based web components for React, Vue, and vanilla JS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,14 +37,18 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@floating-ui/dom": "^1.8.0",
40
- "@greypan/browser-kit": "3.0.0",
41
- "@greypan/js-kit": "3.0.0",
40
+ "@greypan/browser-kit": "3.0.1",
41
+ "@greypan/js-kit": "3.0.1",
42
42
  "@lit/context": "^1.1.6"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@greypan/tsconfig": "1.0.5",
46
+ "@iconify-json/akar-icons": "^1.2.7",
47
+ "@iconify-json/bi": "^1.2.7",
48
+ "@iconify-json/fluent": "^1.2.58",
46
49
  "@iconify-json/jam": "^1.2.3",
47
50
  "@iconify-json/lucide": "^1.2.126",
51
+ "@iconify-json/mdi": "^1.2.3",
48
52
  "@iconify-json/si": "^1.2.17",
49
53
  "@iconify-json/tabler": "^1.2.38",
50
54
  "@iconify-json/heroicons": "^1.2.3",
@@ -85,7 +89,7 @@
85
89
  "scripts": {
86
90
  "build": "vp build",
87
91
  "test": "vp test run",
88
- "dev": "vp build --watch",
92
+ "dev": "vp build --watch --emptyOutDir=false",
89
93
  "generate-icons": "node --experimental-strip-types scripts/generate-icons.ts"
90
94
  }
91
95
  }