@greypan/web-ui 7.0.0 → 8.1.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 (120) hide show
  1. package/README.CN.md +109 -24
  2. package/README.md +149 -63
  3. package/dist/assets/menu-portal.js +1 -1
  4. package/dist/assets/menu-portal.js.map +1 -1
  5. package/dist/assets/selection-control.js +1 -1
  6. package/dist/assets/selection-control.js.map +1 -1
  7. package/dist/components/autocomplete/index.d.ts +17 -5
  8. package/dist/components/autocomplete/index.js +138 -103
  9. package/dist/components/autocomplete/index.js.map +1 -1
  10. package/dist/components/autocomplete/style.js +1 -1
  11. package/dist/components/autocomplete/style.js.map +1 -1
  12. package/dist/components/avatar/index.js +4 -4
  13. package/dist/components/badge/style.js.map +1 -1
  14. package/dist/components/button/index.d.ts +368 -1
  15. package/dist/components/button/index.js +61 -41
  16. package/dist/components/button/index.js.map +1 -1
  17. package/dist/components/button/style.js +1 -1
  18. package/dist/components/button/style.js.map +1 -1
  19. package/dist/components/button-group/index.js +5 -5
  20. package/dist/components/checkbox/index.d.ts +3 -0
  21. package/dist/components/checkbox/index.js +30 -32
  22. package/dist/components/checkbox/index.js.map +1 -1
  23. package/dist/components/checkbox/style.js +1 -1
  24. package/dist/components/checkbox/style.js.map +1 -1
  25. package/dist/components/checkbox-group/index.js +4 -4
  26. package/dist/components/context-menu/index.js +4 -1
  27. package/dist/components/context-menu/index.js.map +1 -1
  28. package/dist/components/dialog/index.js +11 -8
  29. package/dist/components/dialog/index.js.map +1 -1
  30. package/dist/components/drawer/index.js +11 -8
  31. package/dist/components/drawer/index.js.map +1 -1
  32. package/dist/components/dropdown/index.js +4 -1
  33. package/dist/components/dropdown/index.js.map +1 -1
  34. package/dist/components/dropdown-item/style.js +1 -1
  35. package/dist/components/dropdown-item/style.js.map +1 -1
  36. package/dist/components/editable-text/index.d.ts +473 -0
  37. package/dist/components/editable-text/index.js +226 -0
  38. package/dist/components/editable-text/index.js.map +1 -0
  39. package/dist/components/editable-text/style.js +6 -0
  40. package/dist/components/editable-text/style.js.map +1 -0
  41. package/dist/components/icon/index.js +7 -7
  42. package/dist/components/icon/index.js.map +1 -1
  43. package/dist/components/image-preview/index.js +21 -18
  44. package/dist/components/image-preview/index.js.map +1 -1
  45. package/dist/components/index.d.ts +1 -0
  46. package/dist/components/index.js +39 -38
  47. package/dist/components/input/index.d.ts +9 -0
  48. package/dist/components/input/index.js +41 -30
  49. package/dist/components/input/index.js.map +1 -1
  50. package/dist/components/input-number/index.d.ts +1 -0
  51. package/dist/components/input-number/index.js +26 -24
  52. package/dist/components/input-number/index.js.map +1 -1
  53. package/dist/components/layout/index.js +8 -8
  54. package/dist/components/layout/index.js.map +1 -1
  55. package/dist/components/layout/style.js +1 -1
  56. package/dist/components/layout/style.js.map +1 -1
  57. package/dist/components/option/style.js +1 -1
  58. package/dist/components/option/style.js.map +1 -1
  59. package/dist/components/popover/index.js +13 -10
  60. package/dist/components/popover/index.js.map +1 -1
  61. package/dist/components/popover/style.js +1 -1
  62. package/dist/components/popover/style.js.map +1 -1
  63. package/dist/components/radio/index.d.ts +3 -0
  64. package/dist/components/radio/index.js +22 -18
  65. package/dist/components/radio/index.js.map +1 -1
  66. package/dist/components/radio-group/index.js +4 -4
  67. package/dist/components/segmented/index.d.ts +4 -1
  68. package/dist/components/segmented/index.js +42 -29
  69. package/dist/components/segmented/index.js.map +1 -1
  70. package/dist/components/segmented/style.js +1 -1
  71. package/dist/components/segmented/style.js.map +1 -1
  72. package/dist/components/segmented-trigger/style.js +1 -1
  73. package/dist/components/segmented-trigger/style.js.map +1 -1
  74. package/dist/components/select/index.js +35 -32
  75. package/dist/components/select/index.js.map +1 -1
  76. package/dist/components/select/style.js +1 -1
  77. package/dist/components/select/style.js.map +1 -1
  78. package/dist/components/slider/index.js +11 -11
  79. package/dist/components/switch/index.d.ts +1 -0
  80. package/dist/components/switch/index.js +34 -32
  81. package/dist/components/switch/index.js.map +1 -1
  82. package/dist/components/textarea/index.d.ts +7 -1
  83. package/dist/components/textarea/index.js +46 -44
  84. package/dist/components/textarea/index.js.map +1 -1
  85. package/dist/components/textarea/style.js.map +1 -1
  86. package/dist/components/theme/index.d.ts +10 -3
  87. package/dist/components/theme/index.js +133 -93
  88. package/dist/components/theme/index.js.map +1 -1
  89. package/dist/components/theme/style.js +1 -1
  90. package/dist/components/theme/style.js.map +1 -1
  91. package/dist/components/toast/toast.js +7 -7
  92. package/dist/components/toast/toast.js.map +1 -1
  93. package/dist/components/tooltip/index.js +12 -9
  94. package/dist/components/tooltip/index.js.map +1 -1
  95. package/dist/components/tooltip/style.js +1 -1
  96. package/dist/components/tooltip/style.js.map +1 -1
  97. package/dist/icons/generated/akar-icons-check.d.ts +6 -0
  98. package/dist/icons/generated/akar-icons-check.js +10 -0
  99. package/dist/icons/generated/akar-icons-check.js.map +1 -0
  100. package/dist/icons/generated/bi-check.d.ts +6 -0
  101. package/dist/icons/generated/bi-check.js +10 -0
  102. package/dist/icons/generated/bi-check.js.map +1 -0
  103. package/dist/icons/index.d.ts +2 -0
  104. package/dist/icons/index.js +3 -1
  105. package/dist/shared/form-association/field-id.js +9 -0
  106. package/dist/shared/form-association/field-id.js.map +1 -0
  107. package/dist/shared/form-association/index.js +9 -1
  108. package/dist/shared/form-association/index.js.map +1 -1
  109. package/dist/shared/label-emptiness/index.js +45 -0
  110. package/dist/shared/label-emptiness/index.js.map +1 -0
  111. package/dist/shared/option-portal/combobox-shell.js +47 -5
  112. package/dist/shared/option-portal/combobox-shell.js.map +1 -1
  113. package/dist/shared/option-portal/index.js +9 -9
  114. package/dist/shared/overlay/anchored-panel.js +2 -2
  115. package/dist/shared/overlay/anchored-panel.js.map +1 -1
  116. package/dist/shared/overlay/open-overlay.js +38 -22
  117. package/dist/shared/overlay/open-overlay.js.map +1 -1
  118. package/dist/shared/theme/root-sync.js +48 -0
  119. package/dist/shared/theme/root-sync.js.map +1 -0
  120. package/package.json +3 -1
@@ -1,19 +1,19 @@
1
1
  import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
- import t from "../../icons/generated/lucide-check.js";
3
+ import t from "../../assets/glass.js";
4
4
  import n from "../../icons/generated/lucide-info.js";
5
5
  import r from "../../icons/generated/lucide-triangle-alert.js";
6
6
  import i from "../../icons/generated/lucide-circle-alert.js";
7
- import a from "../../icons/generated/heroicons-x-mark-16-solid.js";
8
- import o from "../../assets/glass.js";
9
- import { getTransitionDuration as s } from "../../shared/overlay/presence.js";
7
+ import a from "../../icons/generated/heroicons-check-16-solid.js";
8
+ import o from "../../icons/generated/heroicons-x-mark-16-solid.js";
10
9
  import "../button/index.js";
10
+ import { getTransitionDuration as s } from "../../shared/overlay/presence.js";
11
11
  import c from "./style.js";
12
12
  import { LitElement as l, html as u, nothing as d, unsafeCSS as f } from "lit";
13
13
  import { customElement as p, property as m } from "lit/decorators.js";
14
14
  //#region src/components/toast/toast.ts
15
15
  var h = {
16
- success: t,
16
+ success: a,
17
17
  info: n,
18
18
  warning: r,
19
19
  error: i
@@ -39,7 +39,7 @@ var _ = class extends l {
39
39
  };
40
40
  }
41
41
  static {
42
- this.styles = [f(o), f(c)];
42
+ this.styles = [f(t), f(c)];
43
43
  }
44
44
  get dismissing() {
45
45
  return this._dismissing;
@@ -153,7 +153,7 @@ var _ = class extends l {
153
153
  aria-label="关闭"
154
154
  @click=${this._onCloseClick}
155
155
  >
156
- <web-ui-icon .icon=${a} size="16"></web-ui-icon>
156
+ <web-ui-icon .icon=${o} size="16"></web-ui-icon>
157
157
  </web-ui-button>
158
158
  `}
159
159
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"toast.js","names":[],"sources":["../../../src/components/toast/toast.ts"],"sourcesContent":["import type { IconifyIcon } from '@iconify/types'\nimport { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\n\nimport '@/components/icon'\n// web-ui-button 复用 icon 变体的焦点环与统一样式(secondary 变体,浅灰底贴合 toast 角落)\nimport '@/components/button'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport { lucideCheck, lucideInfo, lucideTriangleAlert, lucideCircleAlert, heroiconsXMark16Solid } from '@/icons'\nimport { getTransitionDuration } from '@/shared/overlay/presence'\n\nimport style from './style.css?inline'\nimport type { ToastCloseReason, ToastPosition, ToastType } from './types'\n\nconst TYPE_ICONS: Record<ToastType, IconifyIcon> = {\n success: lucideCheck,\n info: lucideInfo,\n warning: lucideTriangleAlert,\n error: lucideCircleAlert\n}\n\nfunction _formatTime(): string {\n const now = new Date()\n const h = now.getHours().toString().padStart(2, '0')\n const m = now.getMinutes().toString().padStart(2, '0')\n return `${h}:${m}`\n}\n\n@customElement('web-ui-toast')\nexport class WebUiToast extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, attribute: false }) toastId = ''\n @property({ type: String, reflect: true }) type: ToastType = 'info'\n @property({ type: String, reflect: true }) position: ToastPosition = 'top-right'\n @property({ type: String }) heading = ''\n @property({ type: String }) message = ''\n @property({ type: Number }) duration = 3000\n @property({ type: Boolean, reflect: true, attribute: 'no-close-button' }) noCloseButton = false\n @property({ type: Boolean, reflect: true }) visible = false\n\n private _closeTimer?: ReturnType<typeof setTimeout>\n private _deadline = 0\n /**\n * 暂停自动关闭时记下的剩余时间。`undefined` 表示暂停时本来就没有计时器(`duration` 为 0、\n * 或元素尚未 `show()`),与「已到期」(剩余 0)是两件事,不能共用一个 0。\n */\n private _pausedRemaining?: number\n /** 指针停在 toast 上:计时处于悬停暂停态,只有指针离开才能续跑。 */\n private _hoverPaused = false\n private _dismissing = false\n\n /**\n * 退场已开始、`toast-close` 尚未派发。这段窗口内元素仍连接在 DOM、也仍被 manager 的映射\n * 持有,但已不再接受属性更新:manager 的 upsert 据此走新建路径,否则「更新」会写进一条\n * 正在消失的元素里 —— 调用方拿到同一个 id,却看不到任何可见通知。\n */\n get dismissing(): boolean {\n return this._dismissing\n }\n\n /** 指针仍停在 toast 上,自动关闭计时处于暂停态。 */\n get hoverPaused(): boolean {\n return this._hoverPaused\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n // 悬停中被搬迁(不支持 moveBefore 的引擎走摘出重插)时暂停态要连兜底一起带回来,\n // 否则新位置上既没有 document 监听、也不会再补发 pointerenter,这条 toast 又变成永久停留。\n if (this._hoverPaused) this._attachHoverFallback()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this._detachHoverFallback()\n this._clearTimer()\n }\n\n /**\n * 定义该回调后,`Element.moveBefore()` 搬迁节点不再触发 disconnected/connected,\n * 自动关闭计时与动画状态得以保留;未定义时旧引擎会走摘出重插,计时被 `_clearTimer()` 清掉。\n */\n connectedMoveCallback() {}\n\n protected override updated(changed: PropertyValues) {\n if (changed.has('position')) {\n this._applySlideDirection()\n }\n }\n\n private _applySlideDirection() {\n const SLIDE_OFFSET = 20\n let x = 0\n let y = 0\n\n if (this.position.includes('left')) x = -SLIDE_OFFSET\n else if (this.position.includes('right')) x = SLIDE_OFFSET\n\n if (this.position.startsWith('top')) y = -SLIDE_OFFSET\n else if (this.position.startsWith('bottom')) y = SLIDE_OFFSET\n\n this.style.setProperty('--toast-slide-x', `${x}px`)\n this.style.setProperty('--toast-slide-y', `${y}px`)\n }\n\n startAutoClose() {\n this._clearTimer()\n if (this.duration > 0) {\n this._deadline = Date.now() + this.duration\n this._closeTimer = setTimeout(() => {\n this.dismiss('auto')\n }, this.duration)\n }\n }\n\n /**\n * 由 manager 调用:显式 `duration` 更新。悬停暂停期间只记新值、不点火 —— 否则指针还压在\n * toast 上时计时就被重启,「悬停暂停」在这条路径上直接失效。恢复时按新 duration 计满:\n * 调用方显式改了生命周期,续跑按旧时长算出的剩余没有意义。`0` 表示不自动关闭,记成\n * 「没有计时器」,否则恢复时会被当成「已到期」立即退场。\n */\n setDuration(ms: number) {\n this.duration = ms\n if (this._hoverPaused) {\n this._pausedRemaining = ms > 0 ? ms : undefined\n return\n }\n this.startAutoClose()\n }\n\n // 不支持 moveBefore 的引擎上搬迁节点前调用:记下剩余时间,搬完由 resumeAutoClose() 续跑。\n pauseAutoClose() {\n // 已经在暂停态时保留既有剩余:悬停暂停期间若发生搬迁,降级路径也会走到这里,无条件\n // 重算会把悬停记下的剩余抹成「没有计时器」,指针离开后这条 toast 就再也不会关闭。\n if (this._closeTimer === undefined && this._pausedRemaining !== undefined) return\n // 计时器仍在跑时剩余时间可能算出 0:deadline 已过、回调还排在队列里没执行。这一支与\n // 「本来就没有计时器」必须分开记(undefined vs 0),否则续跑无法区分两者。\n this._pausedRemaining = this._closeTimer === undefined ? undefined : Math.max(0, this._deadline - Date.now())\n this._clearTimer()\n }\n\n // 与 pauseAutoClose() 成对:暂停时没有计时器就保持原状,不重启满时长;\n // 已到期则立即退场 —— 而不是把「已到期」当成「从来没有计时器」放过,那样这条 toast 会永不关闭。\n resumeAutoClose() {\n // 悬停还没结束时只交还剩余时间、不点火:搬迁降级路径也会走到这里,真正的续跑等指针\n // 离开(_resumeFromHover)再开始,否则鼠标还停着就已经在倒计时了。\n if (this._hoverPaused) return\n const remaining = this._pausedRemaining\n this._pausedRemaining = undefined\n if (remaining === undefined) return\n // 装新计时器前先拆掉可能仍在跑的旧计时器:pause/resume 一旦不再严格成对(调用序被重排),\n // 直接覆盖 `_closeTimer` 会留下两个 deadline 同时倒计时,先到的那个把 toast 提前关掉。\n this._clearTimer()\n if (remaining <= 0) {\n this.dismiss('auto')\n return\n }\n this._deadline = Date.now() + remaining\n this._closeTimer = setTimeout(() => {\n this.dismiss('auto')\n }, remaining)\n }\n\n // 由 manager 调用:播放入场动画后自动开始计时\n show() {\n this._dismissing = false\n this.visible = true\n // 挂载时指针已经压在上面(光标停在 toast 将要出现的位置):入场后直接进入暂停,\n // 不能点火 —— 那条计时会在指针还停着的时候把 toast 关掉。\n if (this._hoverPaused) {\n this._pausedRemaining = this.duration > 0 ? this.duration : undefined\n return\n }\n this.startAutoClose()\n }\n\n // 含退场动画,结束由 transitionend 驱动后派发 close。\n dismiss(reason: ToastCloseReason = 'programmatic') {\n if (this._dismissing) return\n this._dismissing = true\n // 退场优先于悬停:暂停态不再有意义,document 兜底监听也要收掉,否则退场中的\n // 元素会继续持有「指针还在上面」的状态。\n this._hoverPaused = false\n this._detachHoverFallback()\n if (!this.visible) {\n // 尚未 show()(manager 挂载之后、rAF 之前)或从未显示过:没有退场动画可播,立即派发,\n // 由 manager 的 toast-close 监听摘除元素。若在这里早退,close()/clear() 落在这段窗口\n // 里就会静默失效 —— 元素照常入场,调用方却以为已经关掉了。\n this._dispatchClose(reason)\n return\n }\n this.visible = false\n this._clearTimer()\n const onEnd = () => {\n this.removeEventListener('transitionend', onEnd)\n this._dispatchClose(reason)\n }\n this.addEventListener('transitionend', onEnd)\n // fallback: transitionend 不触发时(display:none 等)\n const toast = this.shadowRoot?.querySelector<HTMLElement>('.toast')\n setTimeout(onEnd, getTransitionDuration(toast ?? this) + 80)\n }\n\n private _clearTimer() {\n if (this._closeTimer !== undefined) {\n clearTimeout(this._closeTimer)\n this._closeTimer = undefined\n }\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this._hoverPaused) return\n this._hoverPaused = true\n this.pauseAutoClose()\n // pointerleave 是唯一的恢复入口时,漏掉一次(指针拖出窗口、元素在悬停期间被搬迁或\n // 摘出、光标静止时布局把 toast 移走)这条 toast 就永久停在屏幕上。document 级兜底\n // 补上这个缺口:指针落到别的元素上、或离开文档,都判定悬停结束。三个信号互相兜底,\n // 因为单一信号在不同引擎上都有漏派发的场景。\n this._attachHoverFallback()\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n this._resumeFromHover()\n }\n\n // 兜底路径:指针移到别的元素上(冒泡到 document)。路径不含本元素说明指针已经不在\n // toast 上;composedPath() 覆盖 shadow DOM,指针在 toast 内部节点之间移动不算离开。\n private _onDocumentPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (e.composedPath().includes(this)) return\n this._resumeFromHover()\n }\n\n // 兜底路径:指针移出窗口。部分引擎不保证 document 上的 pointerleave,用 relatedTarget\n // 为空的 pointerout 补上 —— 悬停中的 toast 被摘除时同样会派发这种 pointerout。\n private _onDocumentPointerOut = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (e.relatedTarget !== null) return\n this._resumeFromHover()\n }\n\n // 兜底路径:指针离开整个文档(移出窗口)。文档内的元素间移动不会派发到 document。\n private _onDocumentPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n this._resumeFromHover()\n }\n\n private _resumeFromHover() {\n if (!this._hoverPaused) return\n this._hoverPaused = false\n this._detachHoverFallback()\n this.resumeAutoClose()\n }\n\n private _attachHoverFallback() {\n document.addEventListener('pointerover', this._onDocumentPointerOver)\n document.addEventListener('pointerout', this._onDocumentPointerOut)\n document.addEventListener('pointerleave', this._onDocumentPointerLeave)\n }\n\n private _detachHoverFallback() {\n document.removeEventListener('pointerover', this._onDocumentPointerOver)\n document.removeEventListener('pointerout', this._onDocumentPointerOut)\n document.removeEventListener('pointerleave', this._onDocumentPointerLeave)\n }\n\n private _onCloseClick = () => {\n this.dismiss('manual')\n }\n\n private _dispatchClose(reason: ToastCloseReason) {\n this.dispatchEvent(\n new CustomEvent('toast-close', {\n detail: { id: this.toastId, reason },\n bubbles: true,\n composed: true\n })\n )\n }\n\n override render() {\n const icon = TYPE_ICONS[this.type]\n const ariaLive = this.type === 'error' ? 'assertive' : 'polite'\n // role=\"alert\" 会强制隐式 aria-live=\"assertive\",覆盖掉上方 aria-live 设置,\n // 因此仅 error toast 使用 alert(本就应 assertive);其余类型交给容器 role=\"log\" 的 polite 播报。\n const role = this.type === 'error' ? 'alert' : nothing\n\n return html`\n <div class=\"toast wui-glass ${this.type}\" role=${role} aria-live=${ariaLive} aria-atomic=\"true\">\n <span class=\"toast-icon\" aria-hidden=\"true\">\n <web-ui-icon .icon=${icon} size=\"14\"></web-ui-icon>\n </span>\n <div class=\"toast-body\">\n ${this.heading ? html`<div class=\"toast-heading\">${this.heading}</div>` : nothing}\n <div class=\"toast-message\">${this.message}</div>\n </div>\n <span class=\"toast-time\">${_formatTime()}</span>\n ${\n !this.noCloseButton\n ? html`\n <web-ui-button\n class=\"toast-close-btn\"\n icon\n variant=\"secondary\"\n size=\"24\"\n aria-label=\"关闭\"\n @click=${this._onCloseClick}\n >\n <web-ui-icon .icon=${heroiconsXMark16Solid} size=\"16\"></web-ui-icon>\n </web-ui-button>\n `\n : nothing\n }\n </div>\n `\n }\n\n declare readonly $events: {\n 'toast-close': CustomEvent<{ id: string; reason: ToastCloseReason }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-toast': WebUiToast\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"toast.js","names":[],"sources":["../../../src/components/toast/toast.ts"],"sourcesContent":["import type { IconifyIcon } from '@iconify/types'\nimport { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\n\nimport '@/components/icon'\n// web-ui-button 复用 icon 变体的焦点环与统一样式(secondary 变体,浅灰底贴合 toast 角落)\nimport '@/components/button'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport {\n lucideInfo,\n lucideTriangleAlert,\n lucideCircleAlert,\n heroiconsXMark16Solid,\n heroiconsCheck16Solid\n} from '@/icons'\nimport { getTransitionDuration } from '@/shared/overlay/presence'\n\nimport style from './style.css?inline'\nimport type { ToastCloseReason, ToastPosition, ToastType } from './types'\n\nconst TYPE_ICONS: Record<ToastType, IconifyIcon> = {\n success: heroiconsCheck16Solid,\n info: lucideInfo,\n warning: lucideTriangleAlert,\n error: lucideCircleAlert\n}\n\nfunction _formatTime(): string {\n const now = new Date()\n const h = now.getHours().toString().padStart(2, '0')\n const m = now.getMinutes().toString().padStart(2, '0')\n return `${h}:${m}`\n}\n\n@customElement('web-ui-toast')\nexport class WebUiToast extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, attribute: false }) toastId = ''\n @property({ type: String, reflect: true }) type: ToastType = 'info'\n @property({ type: String, reflect: true }) position: ToastPosition = 'top-right'\n @property({ type: String }) heading = ''\n @property({ type: String }) message = ''\n @property({ type: Number }) duration = 3000\n @property({ type: Boolean, reflect: true, attribute: 'no-close-button' }) noCloseButton = false\n @property({ type: Boolean, reflect: true }) visible = false\n\n private _closeTimer?: ReturnType<typeof setTimeout>\n private _deadline = 0\n /**\n * 暂停自动关闭时记下的剩余时间。`undefined` 表示暂停时本来就没有计时器(`duration` 为 0、\n * 或元素尚未 `show()`),与「已到期」(剩余 0)是两件事,不能共用一个 0。\n */\n private _pausedRemaining?: number\n /** 指针停在 toast 上:计时处于悬停暂停态,只有指针离开才能续跑。 */\n private _hoverPaused = false\n private _dismissing = false\n\n /**\n * 退场已开始、`toast-close` 尚未派发。这段窗口内元素仍连接在 DOM、也仍被 manager 的映射\n * 持有,但已不再接受属性更新:manager 的 upsert 据此走新建路径,否则「更新」会写进一条\n * 正在消失的元素里 —— 调用方拿到同一个 id,却看不到任何可见通知。\n */\n get dismissing(): boolean {\n return this._dismissing\n }\n\n /** 指针仍停在 toast 上,自动关闭计时处于暂停态。 */\n get hoverPaused(): boolean {\n return this._hoverPaused\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n // 悬停中被搬迁(不支持 moveBefore 的引擎走摘出重插)时暂停态要连兜底一起带回来,\n // 否则新位置上既没有 document 监听、也不会再补发 pointerenter,这条 toast 又变成永久停留。\n if (this._hoverPaused) this._attachHoverFallback()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this._detachHoverFallback()\n this._clearTimer()\n }\n\n /**\n * 定义该回调后,`Element.moveBefore()` 搬迁节点不再触发 disconnected/connected,\n * 自动关闭计时与动画状态得以保留;未定义时旧引擎会走摘出重插,计时被 `_clearTimer()` 清掉。\n */\n connectedMoveCallback() {}\n\n protected override updated(changed: PropertyValues) {\n if (changed.has('position')) {\n this._applySlideDirection()\n }\n }\n\n private _applySlideDirection() {\n const SLIDE_OFFSET = 20\n let x = 0\n let y = 0\n\n if (this.position.includes('left')) x = -SLIDE_OFFSET\n else if (this.position.includes('right')) x = SLIDE_OFFSET\n\n if (this.position.startsWith('top')) y = -SLIDE_OFFSET\n else if (this.position.startsWith('bottom')) y = SLIDE_OFFSET\n\n this.style.setProperty('--toast-slide-x', `${x}px`)\n this.style.setProperty('--toast-slide-y', `${y}px`)\n }\n\n startAutoClose() {\n this._clearTimer()\n if (this.duration > 0) {\n this._deadline = Date.now() + this.duration\n this._closeTimer = setTimeout(() => {\n this.dismiss('auto')\n }, this.duration)\n }\n }\n\n /**\n * 由 manager 调用:显式 `duration` 更新。悬停暂停期间只记新值、不点火 —— 否则指针还压在\n * toast 上时计时就被重启,「悬停暂停」在这条路径上直接失效。恢复时按新 duration 计满:\n * 调用方显式改了生命周期,续跑按旧时长算出的剩余没有意义。`0` 表示不自动关闭,记成\n * 「没有计时器」,否则恢复时会被当成「已到期」立即退场。\n */\n setDuration(ms: number) {\n this.duration = ms\n if (this._hoverPaused) {\n this._pausedRemaining = ms > 0 ? ms : undefined\n return\n }\n this.startAutoClose()\n }\n\n // 不支持 moveBefore 的引擎上搬迁节点前调用:记下剩余时间,搬完由 resumeAutoClose() 续跑。\n pauseAutoClose() {\n // 已经在暂停态时保留既有剩余:悬停暂停期间若发生搬迁,降级路径也会走到这里,无条件\n // 重算会把悬停记下的剩余抹成「没有计时器」,指针离开后这条 toast 就再也不会关闭。\n if (this._closeTimer === undefined && this._pausedRemaining !== undefined) return\n // 计时器仍在跑时剩余时间可能算出 0:deadline 已过、回调还排在队列里没执行。这一支与\n // 「本来就没有计时器」必须分开记(undefined vs 0),否则续跑无法区分两者。\n this._pausedRemaining = this._closeTimer === undefined ? undefined : Math.max(0, this._deadline - Date.now())\n this._clearTimer()\n }\n\n // 与 pauseAutoClose() 成对:暂停时没有计时器就保持原状,不重启满时长;\n // 已到期则立即退场 —— 而不是把「已到期」当成「从来没有计时器」放过,那样这条 toast 会永不关闭。\n resumeAutoClose() {\n // 悬停还没结束时只交还剩余时间、不点火:搬迁降级路径也会走到这里,真正的续跑等指针\n // 离开(_resumeFromHover)再开始,否则鼠标还停着就已经在倒计时了。\n if (this._hoverPaused) return\n const remaining = this._pausedRemaining\n this._pausedRemaining = undefined\n if (remaining === undefined) return\n // 装新计时器前先拆掉可能仍在跑的旧计时器:pause/resume 一旦不再严格成对(调用序被重排),\n // 直接覆盖 `_closeTimer` 会留下两个 deadline 同时倒计时,先到的那个把 toast 提前关掉。\n this._clearTimer()\n if (remaining <= 0) {\n this.dismiss('auto')\n return\n }\n this._deadline = Date.now() + remaining\n this._closeTimer = setTimeout(() => {\n this.dismiss('auto')\n }, remaining)\n }\n\n // 由 manager 调用:播放入场动画后自动开始计时\n show() {\n this._dismissing = false\n this.visible = true\n // 挂载时指针已经压在上面(光标停在 toast 将要出现的位置):入场后直接进入暂停,\n // 不能点火 —— 那条计时会在指针还停着的时候把 toast 关掉。\n if (this._hoverPaused) {\n this._pausedRemaining = this.duration > 0 ? this.duration : undefined\n return\n }\n this.startAutoClose()\n }\n\n // 含退场动画,结束由 transitionend 驱动后派发 close。\n dismiss(reason: ToastCloseReason = 'programmatic') {\n if (this._dismissing) return\n this._dismissing = true\n // 退场优先于悬停:暂停态不再有意义,document 兜底监听也要收掉,否则退场中的\n // 元素会继续持有「指针还在上面」的状态。\n this._hoverPaused = false\n this._detachHoverFallback()\n if (!this.visible) {\n // 尚未 show()(manager 挂载之后、rAF 之前)或从未显示过:没有退场动画可播,立即派发,\n // 由 manager 的 toast-close 监听摘除元素。若在这里早退,close()/clear() 落在这段窗口\n // 里就会静默失效 —— 元素照常入场,调用方却以为已经关掉了。\n this._dispatchClose(reason)\n return\n }\n this.visible = false\n this._clearTimer()\n const onEnd = () => {\n this.removeEventListener('transitionend', onEnd)\n this._dispatchClose(reason)\n }\n this.addEventListener('transitionend', onEnd)\n // fallback: transitionend 不触发时(display:none 等)\n const toast = this.shadowRoot?.querySelector<HTMLElement>('.toast')\n setTimeout(onEnd, getTransitionDuration(toast ?? this) + 80)\n }\n\n private _clearTimer() {\n if (this._closeTimer !== undefined) {\n clearTimeout(this._closeTimer)\n this._closeTimer = undefined\n }\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this._hoverPaused) return\n this._hoverPaused = true\n this.pauseAutoClose()\n // pointerleave 是唯一的恢复入口时,漏掉一次(指针拖出窗口、元素在悬停期间被搬迁或\n // 摘出、光标静止时布局把 toast 移走)这条 toast 就永久停在屏幕上。document 级兜底\n // 补上这个缺口:指针落到别的元素上、或离开文档,都判定悬停结束。三个信号互相兜底,\n // 因为单一信号在不同引擎上都有漏派发的场景。\n this._attachHoverFallback()\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n this._resumeFromHover()\n }\n\n // 兜底路径:指针移到别的元素上(冒泡到 document)。路径不含本元素说明指针已经不在\n // toast 上;composedPath() 覆盖 shadow DOM,指针在 toast 内部节点之间移动不算离开。\n private _onDocumentPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (e.composedPath().includes(this)) return\n this._resumeFromHover()\n }\n\n // 兜底路径:指针移出窗口。部分引擎不保证 document 上的 pointerleave,用 relatedTarget\n // 为空的 pointerout 补上 —— 悬停中的 toast 被摘除时同样会派发这种 pointerout。\n private _onDocumentPointerOut = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (e.relatedTarget !== null) return\n this._resumeFromHover()\n }\n\n // 兜底路径:指针离开整个文档(移出窗口)。文档内的元素间移动不会派发到 document。\n private _onDocumentPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n this._resumeFromHover()\n }\n\n private _resumeFromHover() {\n if (!this._hoverPaused) return\n this._hoverPaused = false\n this._detachHoverFallback()\n this.resumeAutoClose()\n }\n\n private _attachHoverFallback() {\n document.addEventListener('pointerover', this._onDocumentPointerOver)\n document.addEventListener('pointerout', this._onDocumentPointerOut)\n document.addEventListener('pointerleave', this._onDocumentPointerLeave)\n }\n\n private _detachHoverFallback() {\n document.removeEventListener('pointerover', this._onDocumentPointerOver)\n document.removeEventListener('pointerout', this._onDocumentPointerOut)\n document.removeEventListener('pointerleave', this._onDocumentPointerLeave)\n }\n\n private _onCloseClick = () => {\n this.dismiss('manual')\n }\n\n private _dispatchClose(reason: ToastCloseReason) {\n this.dispatchEvent(\n new CustomEvent('toast-close', {\n detail: { id: this.toastId, reason },\n bubbles: true,\n composed: true\n })\n )\n }\n\n override render() {\n const icon = TYPE_ICONS[this.type]\n const ariaLive = this.type === 'error' ? 'assertive' : 'polite'\n // role=\"alert\" 会强制隐式 aria-live=\"assertive\",覆盖掉上方 aria-live 设置,\n // 因此仅 error toast 使用 alert(本就应 assertive);其余类型交给容器 role=\"log\" 的 polite 播报。\n const role = this.type === 'error' ? 'alert' : nothing\n\n return html`\n <div class=\"toast wui-glass ${this.type}\" role=${role} aria-live=${ariaLive} aria-atomic=\"true\">\n <span class=\"toast-icon\" aria-hidden=\"true\">\n <web-ui-icon .icon=${icon} size=\"14\"></web-ui-icon>\n </span>\n <div class=\"toast-body\">\n ${this.heading ? html`<div class=\"toast-heading\">${this.heading}</div>` : nothing}\n <div class=\"toast-message\">${this.message}</div>\n </div>\n <span class=\"toast-time\">${_formatTime()}</span>\n ${\n !this.noCloseButton\n ? html`\n <web-ui-button\n class=\"toast-close-btn\"\n icon\n variant=\"secondary\"\n size=\"24\"\n aria-label=\"关闭\"\n @click=${this._onCloseClick}\n >\n <web-ui-icon .icon=${heroiconsXMark16Solid} size=\"16\"></web-ui-icon>\n </web-ui-button>\n `\n : nothing\n }\n </div>\n `\n }\n\n declare readonly $events: {\n 'toast-close': CustomEvent<{ id: string; reason: ToastCloseReason }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-toast': WebUiToast\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
2
2
  import t from "../../assets/glass.js";
3
- import n from "../../assets/overlay-motion.js";
4
- import { normalizeLiteral as r, normalizeNumber as i } from "../../shared/normalize/index.js";
3
+ import { normalizeLiteral as n, normalizeNumber as r } from "../../shared/normalize/index.js";
4
+ import i from "../../assets/overlay-motion.js";
5
5
  import { dispatchOpenChangeEvent as a } from "../../shared/open-state/index.js";
6
6
  import { defineAnchoredPanel as o } from "../../shared/overlay/anchored-panel.js";
7
7
  import { defineOpenOverlay as s } from "../../shared/overlay/open-overlay.js";
@@ -14,7 +14,10 @@ import { customElement as h, property as g } from "lit/decorators.js";
14
14
  //#region src/components/tooltip/index.ts
15
15
  var _ = 0, v = class extends f {
16
16
  constructor(...e) {
17
- super(...e), this._placement = "top", this._showDelay = 200, this._hideDelay = 100, this.disabled = !1, this._offset = 6, this.content = "", this.open = !1, this.portal = !1, this._isCountedVisible = !1, this._userOpenChange = new l(), this._shouldOpenInstantly = !0, this._overlay = s().make({ requestClose: () => this._hide() }), this._panel = o().make({
17
+ super(...e), this._placement = "top", this._showDelay = 200, this._hideDelay = 100, this.disabled = !1, this._offset = 6, this.content = "", this.open = !1, this.portal = !1, this._isCountedVisible = !1, this._userOpenChange = new l(), this._shouldOpenInstantly = !0, this._overlay = s().make({
18
+ requestClose: () => this._hide(),
19
+ isConnected: () => this.isConnected
20
+ }), this._panel = o().make({
18
21
  getAnchor: () => this.shadowRoot?.querySelector(".tooltip-trigger") ?? null,
19
22
  getLocalPanel: () => this.shadowRoot?.querySelector(".tooltip-panel") ?? null,
20
23
  getPositioning: () => ({
@@ -42,7 +45,7 @@ var _ = 0, v = class extends f {
42
45
  static {
43
46
  this.styles = [
44
47
  m(t),
45
- m(n),
48
+ m(i),
46
49
  m(d)
47
50
  ];
48
51
  }
@@ -51,28 +54,28 @@ var _ = 0, v = class extends f {
51
54
  }
52
55
  set placement(e) {
53
56
  let t = this._placement;
54
- this._placement = r(e, u, "top"), this.requestUpdate("placement", t);
57
+ this._placement = n(e, u, "top"), this.requestUpdate("placement", t);
55
58
  }
56
59
  get showDelay() {
57
60
  return this._showDelay;
58
61
  }
59
62
  set showDelay(e) {
60
63
  let t = this._showDelay;
61
- this._showDelay = i(e, 0, 5e3, 200), this.requestUpdate("showDelay", t);
64
+ this._showDelay = r(e, 0, 5e3, 200), this.requestUpdate("showDelay", t);
62
65
  }
63
66
  get hideDelay() {
64
67
  return this._hideDelay;
65
68
  }
66
69
  set hideDelay(e) {
67
70
  let t = this._hideDelay;
68
- this._hideDelay = i(e, 0, 5e3, 100), this.requestUpdate("hideDelay", t);
71
+ this._hideDelay = r(e, 0, 5e3, 100), this.requestUpdate("hideDelay", t);
69
72
  }
70
73
  get offset() {
71
74
  return this._offset;
72
75
  }
73
76
  set offset(e) {
74
77
  let t = this._offset;
75
- this._offset = i(e, 0, 100, 6), this.requestUpdate("offset", t);
78
+ this._offset = r(e, 0, 100, 6), this.requestUpdate("offset", t);
76
79
  }
77
80
  get isOpen() {
78
81
  return this.open;
@@ -102,7 +105,7 @@ var _ = 0, v = class extends f {
102
105
  let e = c().make({
103
106
  container: this.overlayContainer,
104
107
  target: this,
105
- style: `${t}\n${n}\n${d}`,
108
+ style: `${t}\n${i}\n${d}`,
106
109
  className: "tooltip-panel portal wui-glass wui-floating-panel",
107
110
  migrateAddedNodes: (e) => e.filter((e) => e instanceof Element && e.getAttribute("slot") === "content")
108
111
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/tooltip/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nlet visibleTooltipCount = 0\n\n@customElement('web-ui-tooltip')\nexport class WebUiTooltip extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'top')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'top'\n\n @property({ type: Number, attribute: 'show-delay' })\n get showDelay(): number {\n return this._showDelay\n }\n set showDelay(v: number) {\n const old = this._showDelay\n this._showDelay = normalizeNumber(v, 0, 5000, 200)\n this.requestUpdate('showDelay', old)\n }\n private _showDelay = 200\n\n @property({ type: Number, attribute: 'hide-delay' })\n get hideDelay(): number {\n return this._hideDelay\n }\n set hideDelay(v: number) {\n const old = this._hideDelay\n this._hideDelay = normalizeNumber(v, 0, 5000, 100)\n this.requestUpdate('hideDelay', old)\n }\n private _hideDelay = 100\n\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 6)\n this.requestUpdate('offset', old)\n }\n private _offset = 6\n\n @property({ type: String }) content = ''\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private _isCountedVisible = false\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n private _portal?: OverlayPortal\n /**\n * 实例作用域的帧事务入口。`requestClose` 是关闭入口的唯一接线:面板的\n * `arbitration: 'none'` 让 tooltip 在组合树里但永不成候选,因此这条**现在不会被\n * 模块调用**。保留它是不想把「怎么关」藏起来,也让仲裁策略变化时依然成立。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._hide()\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay,\n // tooltip 在逻辑组合树里(面板迁移后仍要判对「谁在谁里面」),但从不作为 Escape\n // 候选:按键穿过它落到下层浮层,与重构前一致。\n arbitration: 'none'\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n this.addEventListener('focusin', this._onFocusIn)\n this.addEventListener('focusout', this._onFocusOut)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this.removeEventListener('focusin', this._onFocusIn)\n this.removeEventListener('focusout', this._onFocusOut)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(句柄归它持有)。\n this._overlay.suspend()\n this._syncVisibleTooltipCount(false)\n this._panel.dispose()\n }\n\n override firstUpdated() {\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n }\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('portal') || changed.has('overlayContainer')) {\n // 同帧 open + reconfigure 可能重复建事务;invalidate 保证 reconfigure 是当前唯一帧回调。\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => this._reconfigureOverlay())\n } else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n this._syncVisibleTooltipCount(this.open)\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n } else {\n this._overlay.invalidate()\n void this._closeOverlay()\n }\n if (this._userOpenChange.consume()) this._dispatchChange(this.open)\n }\n if (changed.has('content')) this._syncPortalContent()\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._hideTimer)\n // 已有 tooltip 在场时(指针滑到相邻目标):既不等延迟,也不播入场动画。\n const isRepeat = visibleTooltipCount > 0\n this._showTimer = setTimeout(() => this._show(isRepeat), isRepeat ? 0 : this.showDelay)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => this._hide(), this.hideDelay)\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n if (this.disabled) return\n if (!(event.target instanceof Element) || !event.target.matches(':focus-visible')) return\n\n clearTimeout(this._hideTimer)\n this._show(true)\n }\n\n private _onFocusOut = () => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hide()\n }\n\n private _show(isInstant = false) {\n if (this.open) return\n this._shouldOpenInstantly = isInstant\n this._userOpenChange.mark()\n this.open = true\n }\n\n private _hide() {\n if (!this.open) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _openOverlay(isInstant = false) {\n this._panel.open(isInstant)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'tooltip-panel portal wui-glass wui-floating-panel',\n // 已迁移节点被框架删除后的解除追踪是 portal 内建默认行为,这里无需 onContentChange\n // 打开期实时渲染:新增的 slot=content 元素实时迁入面板(注释锚点无法携带\n // slot 属性,天然留在宿主作为框架 patch 的插入基准)。\n migrateAddedNodes: addedNodes =>\n addedNodes.filter(node => node instanceof Element && node.getAttribute('slot') === 'content')\n })\n this._portal = portal\n if (this.content) {\n const text = document.createElement('span')\n text.className = 'tooltip-text'\n text.textContent = this.content\n portal.panel.append(text)\n } else portal.moveContent(Array.from(this.querySelectorAll('[slot=\"content\"]')))\n portal.panel.setAttribute('role', 'tooltip')\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n this._panel.reconfigure(this.open)\n }\n\n private _syncPortalContent() {\n if (!this.portal || !this.open) return\n const localPanel = this._panel.getPanel()\n if (!localPanel) return\n const panel = this._portal?.panel ?? localPanel\n const text = localPanel.querySelector<HTMLElement>('.tooltip-text')\n if (text) {\n text.textContent = this.content\n return\n }\n if (!this.content) return\n panel.replaceChildren()\n const nextText = document.createElement('span')\n nextText.className = 'tooltip-text'\n nextText.textContent = this.content\n panel.append(nextText)\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _syncVisibleTooltipCount(isVisible: boolean) {\n if (isVisible && !this._isCountedVisible) {\n visibleTooltipCount += 1\n this._isCountedVisible = true\n } else if (!isVisible && this._isCountedVisible) {\n visibleTooltipCount = Math.max(0, visibleTooltipCount - 1)\n this._isCountedVisible = false\n }\n }\n\n override render() {\n return html`\n <div class=\"tooltip-anchor\">\n <div class=\"tooltip-trigger\"><slot></slot></div>\n <div class=\"tooltip-panel wui-floating-panel wui-glass\" hidden role=\"tooltip\">\n ${this.content ? html`<span class=\"tooltip-text\">${this.content}</span>` : html`<slot name=\"content\"></slot>`}\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-tooltip': WebUiTooltip\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/tooltip/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nlet visibleTooltipCount = 0\n\n@customElement('web-ui-tooltip')\nexport class WebUiTooltip extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'top')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'top'\n\n @property({ type: Number, attribute: 'show-delay' })\n get showDelay(): number {\n return this._showDelay\n }\n set showDelay(v: number) {\n const old = this._showDelay\n this._showDelay = normalizeNumber(v, 0, 5000, 200)\n this.requestUpdate('showDelay', old)\n }\n private _showDelay = 200\n\n @property({ type: Number, attribute: 'hide-delay' })\n get hideDelay(): number {\n return this._hideDelay\n }\n set hideDelay(v: number) {\n const old = this._hideDelay\n this._hideDelay = normalizeNumber(v, 0, 5000, 100)\n this.requestUpdate('hideDelay', old)\n }\n private _hideDelay = 100\n\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 6)\n this.requestUpdate('offset', old)\n }\n private _offset = 6\n\n @property({ type: String }) content = ''\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private _isCountedVisible = false\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n private _portal?: OverlayPortal\n /**\n * 实例作用域的帧事务入口。`requestClose` 是关闭入口的唯一接线:面板的\n * `arbitration: 'none'` 让 tooltip 在组合树里但永不成候选,因此这条**现在不会被\n * 模块调用**。保留它是不想把「怎么关」藏起来,也让仲裁策略变化时依然成立。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._hide(),\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.tooltip-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay,\n // tooltip 在逻辑组合树里(面板迁移后仍要判对「谁在谁里面」),但从不作为 Escape\n // 候选:按键穿过它落到下层浮层,与重构前一致。\n arbitration: 'none'\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n this.addEventListener('focusin', this._onFocusIn)\n this.addEventListener('focusout', this._onFocusOut)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n this.removeEventListener('focusin', this._onFocusIn)\n this.removeEventListener('focusout', this._onFocusOut)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n // 停止帧调度;撤销登记由 _panel.dispose() 完成(句柄归它持有)。\n this._overlay.suspend()\n this._syncVisibleTooltipCount(false)\n this._panel.dispose()\n }\n\n override firstUpdated() {\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n }\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('portal') || changed.has('overlayContainer')) {\n // 同帧 open + reconfigure 可能重复建事务;invalidate 保证 reconfigure 是当前唯一帧回调。\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => this._reconfigureOverlay())\n } else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n this._syncVisibleTooltipCount(this.open)\n if (this.open) {\n this._openOverlay(this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n } else {\n this._overlay.invalidate()\n void this._closeOverlay()\n }\n if (this._userOpenChange.consume()) this._dispatchChange(this.open)\n }\n if (changed.has('content')) this._syncPortalContent()\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._hideTimer)\n // 已有 tooltip 在场时(指针滑到相邻目标):既不等延迟,也不播入场动画。\n const isRepeat = visibleTooltipCount > 0\n this._showTimer = setTimeout(() => this._show(isRepeat), isRepeat ? 0 : this.showDelay)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => this._hide(), this.hideDelay)\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n if (this.disabled) return\n if (!(event.target instanceof Element) || !event.target.matches(':focus-visible')) return\n\n clearTimeout(this._hideTimer)\n this._show(true)\n }\n\n private _onFocusOut = () => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n this._hide()\n }\n\n private _show(isInstant = false) {\n if (this.open) return\n this._shouldOpenInstantly = isInstant\n this._userOpenChange.mark()\n this.open = true\n }\n\n private _hide() {\n if (!this.open) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _openOverlay(isInstant = false) {\n this._panel.open(isInstant)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'tooltip-panel portal wui-glass wui-floating-panel',\n // 已迁移节点被框架删除后的解除追踪是 portal 内建默认行为,这里无需 onContentChange\n // 打开期实时渲染:新增的 slot=content 元素实时迁入面板(注释锚点无法携带\n // slot 属性,天然留在宿主作为框架 patch 的插入基准)。\n migrateAddedNodes: addedNodes =>\n addedNodes.filter(node => node instanceof Element && node.getAttribute('slot') === 'content')\n })\n this._portal = portal\n if (this.content) {\n const text = document.createElement('span')\n text.className = 'tooltip-text'\n text.textContent = this.content\n portal.panel.append(text)\n } else portal.moveContent(Array.from(this.querySelectorAll('[slot=\"content\"]')))\n portal.panel.setAttribute('role', 'tooltip')\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n this._panel.reconfigure(this.open)\n }\n\n private _syncPortalContent() {\n if (!this.portal || !this.open) return\n const localPanel = this._panel.getPanel()\n if (!localPanel) return\n const panel = this._portal?.panel ?? localPanel\n const text = localPanel.querySelector<HTMLElement>('.tooltip-text')\n if (text) {\n text.textContent = this.content\n return\n }\n if (!this.content) return\n panel.replaceChildren()\n const nextText = document.createElement('span')\n nextText.className = 'tooltip-text'\n nextText.textContent = this.content\n panel.append(nextText)\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _syncVisibleTooltipCount(isVisible: boolean) {\n if (isVisible && !this._isCountedVisible) {\n visibleTooltipCount += 1\n this._isCountedVisible = true\n } else if (!isVisible && this._isCountedVisible) {\n visibleTooltipCount = Math.max(0, visibleTooltipCount - 1)\n this._isCountedVisible = false\n }\n }\n\n override render() {\n return html`\n <div class=\"tooltip-anchor\">\n <div class=\"tooltip-trigger\"><slot></slot></div>\n <div class=\"tooltip-panel wui-floating-panel wui-glass\" hidden role=\"tooltip\">\n ${this.content ? html`<span class=\"tooltip-text\">${this.content}</span>` : html`<slot name=\"content\"></slot>`}\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-tooltip': WebUiTooltip\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/tooltip/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host,.tooltip-trigger{display:inline-flex}.tooltip-anchor{display:inline-flex;position:relative}.tooltip-panel{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:var(--wui-radius-menu,18px);pointer-events:none;z-index:var(--wui-layer-inline-overlay,1);box-sizing:border-box;width:max-content;max-width:var(--wui-tooltip-max-width,240px);border-radius:var(--wui-radius-menu,18px);font-size:var(--wui-tooltip-font-size,13px);color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#f6f6f6d1);padding:6px 10px;position:absolute;top:-9999px;left:-9999px}.tooltip-panel.portal{z-index:var(--wui-layer-menu,100);position:fixed}.tooltip-panel.hidden{display:none}.tooltip-text{overflow-wrap:break-word;white-space:normal;display:block}:host([portal]) .tooltip-panel{display:none}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host,.tooltip-trigger{display:inline-flex}.tooltip-anchor{display:inline-flex;position:relative}.tooltip-panel{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:var(--wui-radius-menu,18px);pointer-events:none;z-index:var(--wui-layer-inline-overlay,1);box-sizing:border-box;width:max-content;max-width:var(--wui-tooltip-max-width,240px);border-radius:var(--wui-radius-menu,18px);font-size:var(--wui-tooltip-font-size,13px);color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#fefefec2);padding:6px 10px;position:absolute;top:-9999px;left:-9999px}.tooltip-panel.portal{z-index:var(--wui-layer-menu,100);position:fixed}.tooltip-panel.hidden{display:none}.tooltip-text{overflow-wrap:break-word;white-space:normal;display:block}:host([portal]) .tooltip-panel{display:none}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/tooltip/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-flex;\n}\n\n.tooltip-trigger {\n display: inline-flex;\n}\n\n.tooltip-anchor {\n position: relative;\n display: inline-flex;\n}\n\n.tooltip-panel {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n\n pointer-events: none;\n\n position: absolute;\n z-index: var(--wui-layer-inline-overlay, 1);\n top: -9999px;\n left: -9999px;\n\n box-sizing: border-box;\n width: max-content;\n max-width: var(--wui-tooltip-max-width, 240px);\n padding: 6px 10px;\n border-radius: var(--wui-radius-menu, 18px);\n\n font-size: var(--wui-tooltip-font-size, 13px);\n color: var(--wui-color-text, #1b1b1b);\n\n /* 玻璃背景:wui-glass 在面板自身,这里覆盖其默认玻璃底为菜单表面色 */\n background-color: var(--wui-color-surface-menu, rgb(246 246 246 / 0.82));\n}\n\n.tooltip-panel.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n}\n\n.tooltip-panel.hidden {\n display: none;\n}\n\n.tooltip-text {\n display: block;\n overflow-wrap: break-word;\n white-space: normal;\n}\n\n:host([portal]) .tooltip-panel {\n display: none;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/tooltip/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: inline-flex;\n}\n\n.tooltip-trigger {\n display: inline-flex;\n}\n\n.tooltip-anchor {\n position: relative;\n display: inline-flex;\n}\n\n.tooltip-panel {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n\n pointer-events: none;\n\n position: absolute;\n z-index: var(--wui-layer-inline-overlay, 1);\n top: -9999px;\n left: -9999px;\n\n box-sizing: border-box;\n width: max-content;\n max-width: var(--wui-tooltip-max-width, 240px);\n padding: 6px 10px;\n border-radius: var(--wui-radius-menu, 18px);\n\n font-size: var(--wui-tooltip-font-size, 13px);\n color: var(--wui-color-text, #1b1b1b);\n\n /* 玻璃背景:wui-glass 在面板自身,这里覆盖其默认玻璃底为菜单表面色 */\n background-color: var(--wui-color-surface-menu, rgb(254 254 254 / 0.76));\n}\n\n.tooltip-panel.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n}\n\n.tooltip-panel.hidden {\n display: none;\n}\n\n.tooltip-text {\n display: block;\n overflow-wrap: break-word;\n white-space: normal;\n}\n\n:host([portal]) .tooltip-panel {\n display: none;\n}\n"],"mappings":""}
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ body: string;
3
+ width: number;
4
+ height: number;
5
+ };
6
+ export default _default;
@@ -0,0 +1,10 @@
1
+ //#region src/icons/generated/akar-icons-check.ts
2
+ var e = {
3
+ body: "<path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m4 12l6 6L20 6\"/>",
4
+ width: 24,
5
+ height: 24
6
+ };
7
+ //#endregion
8
+ export { e as default };
9
+
10
+ //# sourceMappingURL=akar-icons-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"akar-icons-check.js","names":[],"sources":["../../../src/icons/generated/akar-icons-check.ts"],"sourcesContent":["import type { IconifyIcon } from '@iconify/types'\n\nexport default {\n body: '<path fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m4 12l6 6L20 6\"/>',\n width: 24,\n height: 24\n} satisfies IconifyIcon\n"],"mappings":";AAEA,IAAA,IAAe;CACb,MAAM;CACN,OAAO;CACP,QAAQ;AACV"}
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ body: string;
3
+ width: number;
4
+ height: number;
5
+ };
6
+ export default _default;
@@ -0,0 +1,10 @@
1
+ //#region src/icons/generated/bi-check.ts
2
+ var e = {
3
+ body: "<path fill=\"currentColor\" d=\"M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093l3.473-4.425z\"/>",
4
+ width: 16,
5
+ height: 16
6
+ };
7
+ //#endregion
8
+ export { e as default };
9
+
10
+ //# sourceMappingURL=bi-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bi-check.js","names":[],"sources":["../../../src/icons/generated/bi-check.ts"],"sourcesContent":["import type { IconifyIcon } from '@iconify/types'\n\nexport default {\n body: '<path fill=\"currentColor\" d=\"M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093l3.473-4.425z\"/>',\n width: 16,\n height: 16\n} satisfies IconifyIcon\n"],"mappings":";AAEA,IAAA,IAAe;CACb,MAAM;CACN,OAAO;CACP,QAAQ;AACV"}
@@ -65,3 +65,5 @@ export { default as heroiconsBarsArrowDown16Solid } from './generated/heroicons-
65
65
  export { default as heroiconsBarsArrowUp16Solid } from './generated/heroicons-bars-arrow-up-16-solid';
66
66
  export { default as lucideListRestart } from './generated/lucide-list-restart';
67
67
  export { default as radixIconsReset } from './generated/radix-icons-reset';
68
+ export { default as akarIconsCheck } from './generated/akar-icons-check';
69
+ export { default as biCheck } from './generated/bi-check';
@@ -65,4 +65,6 @@ import le from "./generated/heroicons-bars-arrow-down-16-solid.js";
65
65
  import ue from "./generated/heroicons-bars-arrow-up-16-solid.js";
66
66
  import de from "./generated/lucide-list-restart.js";
67
67
  import fe from "./generated/radix-icons-reset.js";
68
- export { le as heroiconsBarsArrowDown16Solid, ue as heroiconsBarsArrowUp16Solid, k as heroiconsCheck16Solid, j as heroiconsXMark16Solid, w as jamCloseCircleF, r as lucideArrowDownToLine, n as lucideArrowUpToLine, P as lucideBell, T as lucideCheck, s as lucideChevronDown, i as lucideChevronLeft, a as lucideChevronRight, o as lucideChevronUp, O as lucideCircleAlert, te as lucideClapperboard, h as lucideClipboardPaste, se as lucideCode, m as lucideCopy, y as lucideDownload, ce as lucideEllipsisVertical, B as lucideExternalLink, ee as lucideEye, f as lucideFile, V as lucideFileText, H as lucideFilm, p as lucideFolder, U as lucideFolderOpen, L as lucideGlobe, ne as lucideHeadphones, N as lucideHeart, I as lucideImage, e as lucideInbox, E as lucideInfo, W as lucideLayoutGrid, $ as lucideLink, ae as lucideListFilter, de as lucideListRestart, t as lucideLoaderCircle, F as lucideMail, l as lucideMinus, G as lucideMusic, K as lucidePackage, re as lucidePenLine, q as lucidePencil, ie as lucidePlay, c as lucidePlus, _ as lucidePrinter, S as lucideRedo2, J as lucideRefreshCw, C as lucideScissors, u as lucideSearch, v as lucideSettings, Q as lucideSlidersHorizontal, M as lucideStar, Y as lucideTag, X as lucideTags, g as lucideTrash2, D as lucideTriangleAlert, x as lucideUndo2, b as lucideUpload, A as lucideUser, Z as lucideWrench, d as lucideX, z as oouiClose, R as radixIconsPanelLeftMinimized, fe as radixIconsReset, oe as tablerSortAscendingLetters };
68
+ import pe from "./generated/akar-icons-check.js";
69
+ import me from "./generated/bi-check.js";
70
+ export { pe as akarIconsCheck, me as biCheck, le as heroiconsBarsArrowDown16Solid, ue as heroiconsBarsArrowUp16Solid, k as heroiconsCheck16Solid, j as heroiconsXMark16Solid, w as jamCloseCircleF, r as lucideArrowDownToLine, n as lucideArrowUpToLine, P as lucideBell, T as lucideCheck, s as lucideChevronDown, i as lucideChevronLeft, a as lucideChevronRight, o as lucideChevronUp, O as lucideCircleAlert, te as lucideClapperboard, h as lucideClipboardPaste, se as lucideCode, m as lucideCopy, y as lucideDownload, ce as lucideEllipsisVertical, B as lucideExternalLink, ee as lucideEye, f as lucideFile, V as lucideFileText, H as lucideFilm, p as lucideFolder, U as lucideFolderOpen, L as lucideGlobe, ne as lucideHeadphones, N as lucideHeart, I as lucideImage, e as lucideInbox, E as lucideInfo, W as lucideLayoutGrid, $ as lucideLink, ae as lucideListFilter, de as lucideListRestart, t as lucideLoaderCircle, F as lucideMail, l as lucideMinus, G as lucideMusic, K as lucidePackage, re as lucidePenLine, q as lucidePencil, ie as lucidePlay, c as lucidePlus, _ as lucidePrinter, S as lucideRedo2, J as lucideRefreshCw, C as lucideScissors, u as lucideSearch, v as lucideSettings, Q as lucideSlidersHorizontal, M as lucideStar, Y as lucideTag, X as lucideTags, g as lucideTrash2, D as lucideTriangleAlert, x as lucideUndo2, b as lucideUpload, A as lucideUser, Z as lucideWrench, d as lucideX, z as oouiClose, R as radixIconsPanelLeftMinimized, fe as radixIconsReset, oe as tablerSortAscendingLetters };
@@ -0,0 +1,9 @@
1
+ //#region src/shared/form-association/field-id.ts
2
+ var e = 0;
3
+ function t(t) {
4
+ return e += 1, `${t}-${e}`;
5
+ }
6
+ //#endregion
7
+ export { t as createFieldId };
8
+
9
+ //# sourceMappingURL=field-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-id.js","names":[],"sources":["../../../src/shared/form-association/field-id.ts"],"sourcesContent":["let nextFieldId = 0\n\n/**\n * 为 shadow 内原生表单控件生成实例级稳定 id。\n *\n * Chrome 的表单 a11y 审计要求 input / textarea 至少有 id 或 name;\n * 生成 id 让消费者无需显式传 host 属性也始终满足该契约。\n * id 在组件构造时生成一次,后续重渲染复用,避免 aria 引用与焦点时序抖动。\n */\nexport function createFieldId(prefix: string): string {\n nextFieldId += 1\n return `${prefix}-${nextFieldId}`\n}\n"],"mappings":";AAAA,IAAI,IAAc;AASlB,SAAgB,EAAc,GAAwB;CAEpD,OADA,KAAe,GACR,GAAG,EAAO,GAAG;AACtB"}
@@ -27,7 +27,15 @@ function n(t) {
27
27
  t.isStateManaged?.() || (t.restoreState(e), o());
28
28
  },
29
29
  setDisabled(e) {
30
- i !== e && (i = e, t.host.requestUpdate(), o());
30
+ if (i !== e) {
31
+ if (i = e, o(), t.host.isUpdatePending) {
32
+ queueMicrotask(() => {
33
+ t.host.requestUpdate(), o();
34
+ });
35
+ return;
36
+ }
37
+ t.host.requestUpdate();
38
+ }
31
39
  },
32
40
  isFormDisabled: () => i,
33
41
  getInternals: () => e
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/shared/form-association/index.ts"],"sourcesContent":["import { definePlugin } from '@greypan/js-kit'\nimport type { ReactiveController, ReactiveControllerHost } from 'lit'\n\n// Lit 官方 mixin 签名需要构造器接受任意参数(paramCount 各异的子类构造器都要能赋给\n// 基座);never[] 变体在 extends 链上会丢失 Lit 静态侧类型。any 收敛在这个类型别名内。\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Constructor<T = object> = new (...args: any[]) => T\n\ntype FormSubmissionValue = File | FormData | string | null\ntype FormStateValue = File | FormData | string | null\n\ninterface FormAssociationHost extends HTMLElement, ReactiveControllerHost {}\n\nexport interface FormAssociationOptions<State> {\n readonly host: FormAssociationHost\n readonly initialize?: () => void\n readonly getState: () => State\n readonly setState: (state: State) => void\n readonly copyState?: (state: State) => State\n readonly getFormValue: () => FormSubmissionValue\n readonly getFormState: () => FormStateValue\n readonly restoreState: (state: FormStateValue) => void\n readonly isStateManaged?: () => boolean\n readonly syncValidity?: (internals: ElementInternals) => void\n}\n\nexport interface FormAssociationLifecycle {\n connect(): void\n sync(): void\n reset(): void\n restore(state: FormStateValue): void\n setDisabled(disabled: boolean): void\n isFormDisabled(): boolean\n getInternals(): ElementInternals | undefined\n}\n\n/**\n * 把原生 input 的 ValidityState 转发为 ElementInternals 的校验状态。\n * flagNames 是控件自己声明的校验契约(input 转发文本类 5 项、input-number\n * 转发范围类 4 项),这里只收敛 guard / valid 判定 / setValidity 接线。\n * disabled 元素被约束验证豁免,必须上报干净状态;isDisabled 传入控件的\n * 组合禁用态(含 formDisabled),因为 formDisabledCallback 触发时原生\n * input 的 disabled 属性可能尚未重渲染,不能依赖 input.validity.valid。\n */\nexport function forwardInputValidity(\n internals: ElementInternals,\n input: HTMLInputElement | HTMLTextAreaElement,\n flagNames: readonly (keyof ValidityStateFlags)[],\n isDisabled = false\n): void {\n if (typeof internals.setValidity !== 'function') return\n if (isDisabled || input.validity.valid) {\n internals.setValidity({})\n return\n }\n const flags: ValidityStateFlags = {}\n for (const name of flagNames) {\n if (input.validity[name]) flags[name] = true\n }\n internals.setValidity(flags, input.validationMessage, input)\n}\n\n/**\n * 承接原生 custom element 表单生命周期,值序列化与校验语义仍由各控件组件自己表达。\n */\nexport function defineFormAssociation<State>(options: FormAssociationOptions<State>) {\n return definePlugin((): FormAssociationLifecycle => {\n let internals: ElementInternals | undefined\n let initialState: State | undefined\n let initialized = false\n let formDisabled = false\n const copyState = options.copyState ?? (state => state)\n\n const sync = () => {\n if (!internals) return\n internals.setFormValue?.(options.getFormValue(), options.getFormState())\n options.syncValidity?.(internals)\n }\n\n return {\n connect() {\n if (!internals) internals = options.host.attachInternals()\n if (!initialized) {\n options.initialize?.()\n initialState = copyState(options.getState())\n initialized = true\n }\n sync()\n },\n sync,\n reset() {\n if (!initialized || options.isStateManaged?.()) return\n options.setState(copyState(initialState as State))\n sync()\n },\n restore(state) {\n if (options.isStateManaged?.()) return\n options.restoreState(state)\n sync()\n },\n setDisabled(disabled) {\n if (formDisabled === disabled) return\n formDisabled = disabled\n options.host.requestUpdate()\n sync()\n },\n isFormDisabled: () => formDisabled,\n getInternals: () => internals\n }\n })\n}\n\n/**\n * 表单关联元素 mixin:安装 `formAssociated` 与三个生命周期回调。\n *\n * 生命周期实现仍由 defineFormAssociation 表达;FormAssociationController\n * 在构造时把 lifecycle 注册到实例的 provider,回调经它转发。组件可继续\n * 覆写单个回调注入自己的额外逻辑(如 autocomplete 的禁用收口)。\n * 这是字段组合(mixin),不是共享基类:除回调接线外不继承任何实现。\n */\nexport interface FormAssociatedLifecycleProvider {\n __formLifecycleProvider?: () => FormAssociationLifecycle\n}\n\nexport function FormAssociated<T extends Constructor<HTMLElement>>(superClass: T) {\n class FormAssociatedElement extends superClass {\n static formAssociated = true\n\n formResetCallback(): void {\n ;(this as FormAssociatedLifecycleProvider).__formLifecycleProvider?.().reset()\n }\n\n formDisabledCallback(disabled: boolean): void {\n ;(this as FormAssociatedLifecycleProvider).__formLifecycleProvider?.().setDisabled(disabled)\n }\n\n formStateRestoreCallback(state: File | FormData | string | null): void {\n ;(this as FormAssociatedLifecycleProvider).__formLifecycleProvider?.().restore(state)\n }\n }\n return FormAssociatedElement\n}\n\n/** 把表单生命周期插件接入宿主(回调接线经 FormAssociated mixin,无需共享基类)。 */\nexport class FormAssociationController implements ReactiveController {\n constructor(\n private readonly host: FormAssociationHost,\n private readonly lifecycle: FormAssociationLifecycle\n ) {\n host.addController(this)\n ;(host as FormAssociationHost & FormAssociatedLifecycleProvider).__formLifecycleProvider = () => lifecycle\n }\n\n hostConnected() {\n this.lifecycle.connect()\n }\n\n hostUpdated() {\n this.lifecycle.sync()\n }\n}\n"],"mappings":";;AA4CA,SAAgB,EACd,GACA,GACA,GACA,IAAa,IACP;CACN,IAAI,OAAO,EAAU,eAAgB,YAAY;CACjD,IAAI,KAAc,EAAM,SAAS,OAAO;EACtC,EAAU,YAAY,CAAC,CAAC;EACxB;CACF;CACA,IAAM,IAA4B,CAAC;CACnC,KAAK,IAAM,KAAQ,GACjB,AAAI,EAAM,SAAS,OAAO,EAAM,KAAQ;CAE1C,EAAU,YAAY,GAAO,EAAM,mBAAmB,CAAK;AAC7D;AAKA,SAAgB,EAA6B,GAAwC;CACnF,OAAO,QAA6C;EAClD,IAAI,GACA,GACA,IAAc,IACd,IAAe,IACb,IAAY,EAAQ,eAAc,MAAS,IAE3C,UAAa;GACZ,MACL,EAAU,eAAe,EAAQ,aAAa,GAAG,EAAQ,aAAa,CAAC,GACvE,EAAQ,eAAe,CAAS;EAClC;EAEA,OAAO;GACL,UAAU;IAOR,AANA,AAAgB,MAAY,EAAQ,KAAK,gBAAgB,GACzD,AAGE,OAFA,EAAQ,aAAa,GACrB,IAAe,EAAU,EAAQ,SAAS,CAAC,GAC7B,KAEhB,EAAK;GACP;GACA;GACA,QAAQ;IACF,AAAC,KAAe,GAAQ,iBAAiB,MAC7C,EAAQ,SAAS,EAAU,CAAqB,CAAC,GACjD,EAAK;GACP;GACA,QAAQ,GAAO;IACT,EAAQ,iBAAiB,MAC7B,EAAQ,aAAa,CAAK,GAC1B,EAAK;GACP;GACA,YAAY,GAAU;IAChB,MAAiB,MACrB,IAAe,GACf,EAAQ,KAAK,cAAc,GAC3B,EAAK;GACP;GACA,sBAAsB;GACtB,oBAAoB;EACtB;CACF,CAAC;AACH;AAcA,SAAgB,EAAmD,GAAe;CAChF,MAAM,UAA8B,EAAW;;GACrB,KAAA,iBAAA;;EAExB,oBAA0B;GACvB,KAA0C,0BAA0B,CAAC,CAAC,MAAM;EAC/E;EAEA,qBAAqB,GAAyB;GAC3C,KAA0C,0BAA0B,CAAC,CAAC,YAAY,CAAQ;EAC7F;EAEA,yBAAyB,GAA8C;GACpE,KAA0C,0BAA0B,CAAC,CAAC,QAAQ,CAAK;EACtF;CACF;CACA,OAAO;AACT;AAGA,IAAa,IAAb,MAAqE;CACnE,YACE,GACA,GACA;EAEC,AAJgB,KAAA,OAAA,GACA,KAAA,YAAA,GAEjB,EAAK,cAAc,IAAI,GACtB,EAAgE,gCAAgC;CACnG;CAEA,gBAAgB;EACd,KAAK,UAAU,QAAQ;CACzB;CAEA,cAAc;EACZ,KAAK,UAAU,KAAK;CACtB;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/shared/form-association/index.ts"],"sourcesContent":["import { definePlugin } from '@greypan/js-kit'\nimport type { ReactiveController, ReactiveControllerHost } from 'lit'\n\n// Lit 官方 mixin 签名需要构造器接受任意参数(paramCount 各异的子类构造器都要能赋给\n// 基座);never[] 变体在 extends 链上会丢失 Lit 静态侧类型。any 收敛在这个类型别名内。\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Constructor<T = object> = new (...args: any[]) => T\n\ntype FormSubmissionValue = File | FormData | string | null\ntype FormStateValue = File | FormData | string | null\n\ninterface FormAssociationHost extends HTMLElement, ReactiveControllerHost {\n /** Lit 的更新窗口判据:反射属性触发的回调落在本轮 performUpdate 之内时为 true。 */\n isUpdatePending: boolean\n}\n\nexport interface FormAssociationOptions<State> {\n readonly host: FormAssociationHost\n readonly initialize?: () => void\n readonly getState: () => State\n readonly setState: (state: State) => void\n readonly copyState?: (state: State) => State\n readonly getFormValue: () => FormSubmissionValue\n readonly getFormState: () => FormStateValue\n readonly restoreState: (state: FormStateValue) => void\n readonly isStateManaged?: () => boolean\n readonly syncValidity?: (internals: ElementInternals) => void\n}\n\nexport interface FormAssociationLifecycle {\n connect(): void\n sync(): void\n reset(): void\n restore(state: FormStateValue): void\n setDisabled(disabled: boolean): void\n isFormDisabled(): boolean\n getInternals(): ElementInternals | undefined\n}\n\n/**\n * 把原生 input 的 ValidityState 转发为 ElementInternals 的校验状态。\n * flagNames 是控件自己声明的校验契约(input 转发文本类 5 项、input-number\n * 转发范围类 4 项),这里只收敛 guard / valid 判定 / setValidity 接线。\n * disabled 元素被约束验证豁免,必须上报干净状态;isDisabled 传入控件的\n * 组合禁用态(含 formDisabled),因为 formDisabledCallback 触发时原生\n * input 的 disabled 属性可能尚未重渲染,不能依赖 input.validity.valid。\n */\nexport function forwardInputValidity(\n internals: ElementInternals,\n input: HTMLInputElement | HTMLTextAreaElement,\n flagNames: readonly (keyof ValidityStateFlags)[],\n isDisabled = false\n): void {\n if (typeof internals.setValidity !== 'function') return\n if (isDisabled || input.validity.valid) {\n internals.setValidity({})\n return\n }\n const flags: ValidityStateFlags = {}\n for (const name of flagNames) {\n if (input.validity[name]) flags[name] = true\n }\n internals.setValidity(flags, input.validationMessage, input)\n}\n\n/**\n * 承接原生 custom element 表单生命周期,值序列化与校验语义仍由各控件组件自己表达。\n */\nexport function defineFormAssociation<State>(options: FormAssociationOptions<State>) {\n return definePlugin((): FormAssociationLifecycle => {\n let internals: ElementInternals | undefined\n let initialState: State | undefined\n let initialized = false\n let formDisabled = false\n const copyState = options.copyState ?? (state => state)\n\n const sync = () => {\n if (!internals) return\n internals.setFormValue?.(options.getFormValue(), options.getFormState())\n options.syncValidity?.(internals)\n }\n\n return {\n connect() {\n if (!internals) internals = options.host.attachInternals()\n if (!initialized) {\n options.initialize?.()\n initialState = copyState(options.getState())\n initialized = true\n }\n sync()\n },\n sync,\n reset() {\n if (!initialized || options.isStateManaged?.()) return\n options.setState(copyState(initialState as State))\n sync()\n },\n restore(state) {\n if (options.isStateManaged?.()) return\n options.restoreState(state)\n sync()\n },\n setDisabled(disabled) {\n if (formDisabled === disabled) return\n formDisabled = disabled\n sync()\n if (options.host.isUpdatePending) {\n /*\n * 宿主 disabled 的反射会同步触发 formDisabledCallback,那一轮 render 已经读过旧值;\n * 而 Lit 在 isUpdatePending 为 true 时会丢掉 requestUpdate()(reactive-element 2.1.2\n * 的 requestUpdate 尾部判据),控件就会停在旧禁用态且再无渲染。等本轮更新结束再排一次。\n */\n queueMicrotask(() => {\n options.host.requestUpdate()\n sync()\n })\n return\n }\n options.host.requestUpdate()\n },\n isFormDisabled: () => formDisabled,\n getInternals: () => internals\n }\n })\n}\n\n/**\n * 表单关联元素 mixin:安装 `formAssociated` 与三个生命周期回调。\n *\n * 生命周期实现仍由 defineFormAssociation 表达;FormAssociationController\n * 在构造时把 lifecycle 注册到实例的 provider,回调经它转发。组件可继续\n * 覆写单个回调注入自己的额外逻辑(如 autocomplete 的禁用收口)。\n * 这是字段组合(mixin),不是共享基类:除回调接线外不继承任何实现。\n */\nexport interface FormAssociatedLifecycleProvider {\n __formLifecycleProvider?: () => FormAssociationLifecycle\n}\n\nexport function FormAssociated<T extends Constructor<HTMLElement>>(superClass: T) {\n class FormAssociatedElement extends superClass {\n static formAssociated = true\n\n formResetCallback(): void {\n ;(this as FormAssociatedLifecycleProvider).__formLifecycleProvider?.().reset()\n }\n\n formDisabledCallback(disabled: boolean): void {\n ;(this as FormAssociatedLifecycleProvider).__formLifecycleProvider?.().setDisabled(disabled)\n }\n\n formStateRestoreCallback(state: File | FormData | string | null): void {\n ;(this as FormAssociatedLifecycleProvider).__formLifecycleProvider?.().restore(state)\n }\n }\n return FormAssociatedElement\n}\n\n/** 把表单生命周期插件接入宿主(回调接线经 FormAssociated mixin,无需共享基类)。 */\nexport class FormAssociationController implements ReactiveController {\n constructor(\n private readonly host: FormAssociationHost,\n private readonly lifecycle: FormAssociationLifecycle\n ) {\n host.addController(this)\n ;(host as FormAssociationHost & FormAssociatedLifecycleProvider).__formLifecycleProvider = () => lifecycle\n }\n\n hostConnected() {\n this.lifecycle.connect()\n }\n\n hostUpdated() {\n this.lifecycle.sync()\n }\n}\n"],"mappings":";;AA+CA,SAAgB,EACd,GACA,GACA,GACA,IAAa,IACP;CACN,IAAI,OAAO,EAAU,eAAgB,YAAY;CACjD,IAAI,KAAc,EAAM,SAAS,OAAO;EACtC,EAAU,YAAY,CAAC,CAAC;EACxB;CACF;CACA,IAAM,IAA4B,CAAC;CACnC,KAAK,IAAM,KAAQ,GACjB,AAAI,EAAM,SAAS,OAAO,EAAM,KAAQ;CAE1C,EAAU,YAAY,GAAO,EAAM,mBAAmB,CAAK;AAC7D;AAKA,SAAgB,EAA6B,GAAwC;CACnF,OAAO,QAA6C;EAClD,IAAI,GACA,GACA,IAAc,IACd,IAAe,IACb,IAAY,EAAQ,eAAc,MAAS,IAE3C,UAAa;GACZ,MACL,EAAU,eAAe,EAAQ,aAAa,GAAG,EAAQ,aAAa,CAAC,GACvE,EAAQ,eAAe,CAAS;EAClC;EAEA,OAAO;GACL,UAAU;IAOR,AANA,AAAgB,MAAY,EAAQ,KAAK,gBAAgB,GACzD,AAGE,OAFA,EAAQ,aAAa,GACrB,IAAe,EAAU,EAAQ,SAAS,CAAC,GAC7B,KAEhB,EAAK;GACP;GACA;GACA,QAAQ;IACF,AAAC,KAAe,GAAQ,iBAAiB,MAC7C,EAAQ,SAAS,EAAU,CAAqB,CAAC,GACjD,EAAK;GACP;GACA,QAAQ,GAAO;IACT,EAAQ,iBAAiB,MAC7B,EAAQ,aAAa,CAAK,GAC1B,EAAK;GACP;GACA,YAAY,GAAU;IAChB,UAAiB,GAGrB;SAFA,IAAe,GACf,EAAK,GACD,EAAQ,KAAK,iBAAiB;MAMhC,qBAAqB;OAEnB,AADA,EAAQ,KAAK,cAAc,GAC3B,EAAK;MACP,CAAC;MACD;KACF;KACA,EAAQ,KAAK,cAAc;IAD3B;GAEF;GACA,sBAAsB;GACtB,oBAAoB;EACtB;CACF,CAAC;AACH;AAcA,SAAgB,EAAmD,GAAe;CAChF,MAAM,UAA8B,EAAW;;GACrB,KAAA,iBAAA;;EAExB,oBAA0B;GACvB,KAA0C,0BAA0B,CAAC,CAAC,MAAM;EAC/E;EAEA,qBAAqB,GAAyB;GAC3C,KAA0C,0BAA0B,CAAC,CAAC,YAAY,CAAQ;EAC7F;EAEA,yBAAyB,GAA8C;GACpE,KAA0C,0BAA0B,CAAC,CAAC,QAAQ,CAAK;EACtF;CACF;CACA,OAAO;AACT;AAGA,IAAa,IAAb,MAAqE;CACnE,YACE,GACA,GACA;EAEC,AAJgB,KAAA,OAAA,GACA,KAAA,YAAA,GAEjB,EAAK,cAAc,IAAI,GACtB,EAAgE,gCAAgC;CACnG;CAEA,gBAAgB;EACd,KAAK,UAAU,QAAQ;CACzB;CAEA,cAAc;EACZ,KAAK,UAAU,KAAK;CACtB;AACF"}
@@ -0,0 +1,45 @@
1
+ //#region src/shared/label-emptiness/index.ts
2
+ var e = /* @__PURE__ */ new WeakMap(), t;
3
+ function n() {
4
+ return typeof ResizeObserver > "u" ? null : t || (t = new ResizeObserver((t) => {
5
+ for (let n of t) {
6
+ let t = e.get(n.target);
7
+ if (!t) continue;
8
+ let r = n.contentRect.width === 0;
9
+ t.empty !== r && (t.empty = r, t.notify(r));
10
+ }
11
+ }), t);
12
+ }
13
+ function r(t, r) {
14
+ let i = n();
15
+ i && (e.set(t, {
16
+ notify: r,
17
+ empty: !1
18
+ }), i.observe(t));
19
+ }
20
+ function i(n) {
21
+ e.delete(n), t?.unobserve(n);
22
+ }
23
+ var a = class {
24
+ constructor(e, t, n) {
25
+ this.host = e, this.selector = t, this.notify = n, e.addController(this);
26
+ }
27
+ hostConnected() {
28
+ this.attach();
29
+ }
30
+ hostUpdated() {
31
+ this.attach();
32
+ }
33
+ hostDisconnected() {
34
+ this.target && i(this.target), this.target = void 0;
35
+ }
36
+ attach() {
37
+ if (this.target) return;
38
+ let e = this.host.renderRoot.querySelector(this.selector);
39
+ e && (this.target = e, r(e, this.notify));
40
+ }
41
+ };
42
+ //#endregion
43
+ export { a as LabelEmptinessController };
44
+
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/shared/label-emptiness/index.ts"],"sourcesContent":["/**\n * 判断 label 槽位有没有真的画出东西。\n *\n * radio / checkbox 的触发行是 `inline-flex` + `gap: 10px`,宿主宽度由内容撑开,所以那条 gap 是\n * 指示器与标签之间的距离。但 gap 只认「这里有个 flex item」,不认它有没有宽度:槽位空着,或者只放了\n * 一个视觉隐藏的无障碍名(`.sr-only` 出流,不产生行内盒),标签盒子是 0 宽,指示器右边仍然多出 10px。\n *\n * 判据因此取渲染宽度而不是「槽位有没有被指派内容」——两者只在无障碍名那一种用法上分开,而那正是这里\n * 要修的一种。CSS 也判不出这件事:`slot:empty` 看的是 slot 自己的子节点,被 assign 进来的节点并不是\n * 它的孩子。同理不能用 `hidden` 把盒子收掉,display: none 会连带把里面的文字从无障碍名里去掉。\n */\nimport type { LitElement, ReactiveController, ReactiveControllerHost } from 'lit'\n\ninterface Watched {\n readonly notify: (empty: boolean) => void\n empty: boolean\n}\n\nconst watched = new WeakMap<Element, Watched>()\nlet observer: ResizeObserver | undefined\n\n/**\n * 全模块共用一个 ResizeObserver:一个列表里可能有上百个选择控件,逐实例建观察者要给每个控件单独排\n * 一次尺寸回调。没有 ResizeObserver 的环境(jsdom)没有布局可测,直接不接。\n */\nfunction getObserver(): ResizeObserver | null {\n if (typeof ResizeObserver === 'undefined') return null\n if (observer) return observer\n\n observer = new ResizeObserver(entries => {\n for (const entry of entries) {\n const target = watched.get(entry.target)\n if (!target) continue\n\n const empty = entry.contentRect.width === 0\n if (target.empty === empty) continue\n\n target.empty = empty\n target.notify(empty)\n }\n })\n\n return observer\n}\n\nfunction watch(target: Element, notify: (empty: boolean) => void) {\n const shared = getObserver()\n if (!shared) return\n\n // 初值跟宿主的默认状态一致:非空。首帧的真实尺寸由 observe() 的初始回调报上来。\n watched.set(target, { notify, empty: false })\n shared.observe(target)\n}\n\nfunction unwatch(target: Element) {\n watched.delete(target)\n observer?.unobserve(target)\n}\n\n/** 把标签盒子的空 / 非空变化报给宿主;断开重连后重新接上观察。 */\nexport class LabelEmptinessController implements ReactiveController {\n private target: Element | undefined\n\n constructor(\n private readonly host: ReactiveControllerHost & LitElement,\n private readonly selector: string,\n private readonly notify: (empty: boolean) => void\n ) {\n host.addController(this)\n }\n\n /*\n * 两个生命周期都要接:重连(移出 DOM 再放回去、列表重排、Teleport)不会排一次更新,所以只挂在\n * hostUpdated 上的话,观察在断开时被拆掉就再也接不回来,标签后来改成什么都不显示宽度都停在旧值上。\n * 而首连时 shadow root 还没有子节点,这里查不到目标,得靠 hostUpdated 补上第一次。\n */\n hostConnected() {\n this.attach()\n }\n\n hostUpdated() {\n this.attach()\n }\n\n hostDisconnected() {\n if (this.target) unwatch(this.target)\n this.target = undefined\n }\n\n private attach() {\n if (this.target) return\n\n const target = this.host.renderRoot.querySelector(this.selector)\n if (!target) return\n\n this.target = target\n watch(target, this.notify)\n }\n}\n"],"mappings":";AAkBA,IAAM,oBAAU,IAAI,QAA0B,GAC1C;AAMJ,SAAS,IAAqC;CAiB5C,OAhBI,OAAO,iBAAmB,MAAoB,OAC9C,MAEJ,IAAW,IAAI,gBAAe,MAAW;EACvC,KAAK,IAAM,KAAS,GAAS;GAC3B,IAAM,IAAS,EAAQ,IAAI,EAAM,MAAM;GACvC,IAAI,CAAC,GAAQ;GAEb,IAAM,IAAQ,EAAM,YAAY,UAAU;GACtC,EAAO,UAAU,MAErB,EAAO,QAAQ,GACf,EAAO,OAAO,CAAK;EACrB;CACF,CAAC,GAEM;AACT;AAEA,SAAS,EAAM,GAAiB,GAAkC;CAChE,IAAM,IAAS,EAAY;CACtB,MAGL,EAAQ,IAAI,GAAQ;EAAE;EAAQ,OAAO;CAAM,CAAC,GAC5C,EAAO,QAAQ,CAAM;AACvB;AAEA,SAAS,EAAQ,GAAiB;CAEhC,AADA,EAAQ,OAAO,CAAM,GACrB,GAAU,UAAU,CAAM;AAC5B;AAGA,IAAa,IAAb,MAAoE;CAGlE,YACE,GACA,GACA,GACA;EACA,AAJiB,KAAA,OAAA,GACA,KAAA,WAAA,GACA,KAAA,SAAA,GAEjB,EAAK,cAAc,IAAI;CACzB;CAOA,gBAAgB;EACd,KAAK,OAAO;CACd;CAEA,cAAc;EACZ,KAAK,OAAO;CACd;CAEA,mBAAmB;EAEjB,AADI,KAAK,UAAQ,EAAQ,KAAK,MAAM,GACpC,KAAK,SAAS,KAAA;CAChB;CAEA,SAAiB;EACf,IAAI,KAAK,QAAQ;EAEjB,IAAM,IAAS,KAAK,KAAK,WAAW,cAAc,KAAK,QAAQ;EAC1D,MAEL,KAAK,SAAS,GACd,EAAM,GAAQ,KAAK,MAAM;CAC3B;AACF"}
@@ -1,5 +1,6 @@
1
+ import { definePlugin as e } from "@greypan/js-kit";
1
2
  //#region src/shared/option-portal/combobox-shell.ts
2
- function e(e) {
3
+ function t(e) {
3
4
  function t(t = !1) {
4
5
  e.canOpen() === !1 || e.getIsOpen() || (e.setIsOpen(!0), e.dispatchOpenChange(), e.onOpen?.(t), e.syncScrollLock(!0), e.isPortal() ? requestAnimationFrame(() => {
5
6
  e.getIsOpen() && e.openOverlay(t);
@@ -13,7 +14,48 @@ function e(e) {
13
14
  close: n
14
15
  };
15
16
  }
16
- function t(e) {
17
+ var n = () => e((e) => {
18
+ let t = null, n = () => e.getCustomTrigger() ?? e.getFallbackTrigger() ?? null, r = (e) => {
19
+ let t = e?.value;
20
+ return typeof t == "string" ? t : null;
21
+ }, i = (e, t) => {
22
+ let n = e.target;
23
+ return !!t && n instanceof Node && (n === t || t.contains(n));
24
+ }, a = (t) => {
25
+ let a = n();
26
+ if (!i(t, a)) return;
27
+ let o = r(a);
28
+ o !== null && e.onInput(o);
29
+ }, o = (e) => {
30
+ i(e, n()) && e.stopPropagation();
31
+ }, s = () => e.onClick(), c = (t) => e.onFocusIn(t), l = (t) => e.onFocusOut(t);
32
+ return {
33
+ getTrigger: n,
34
+ getValue: () => r(n()),
35
+ setValue(e) {
36
+ let t = n(), i = r(t);
37
+ t && i !== null && i !== e && (t.value = e);
38
+ },
39
+ isMultilineEdit(e) {
40
+ return e.composedPath()[0] instanceof HTMLTextAreaElement;
41
+ },
42
+ focusTrigger(e) {
43
+ n()?.focus(e);
44
+ },
45
+ blurTrigger() {
46
+ n()?.blur();
47
+ },
48
+ bind() {
49
+ let n = e.getWrapper();
50
+ n && n !== t && (t = n, n.addEventListener("input", a), n.addEventListener("change", o), n.addEventListener("click", s), n.addEventListener("focusin", c), n.addEventListener("focusout", l));
51
+ },
52
+ dispose() {
53
+ let e = t;
54
+ t = null, e && (e.removeEventListener("input", a), e.removeEventListener("change", o), e.removeEventListener("click", s), e.removeEventListener("focusin", c), e.removeEventListener("focusout", l));
55
+ }
56
+ };
57
+ });
58
+ function r(e) {
17
59
  function t(t) {
18
60
  t.addEventListener("click", e.onClick), t.addEventListener("pointerover", e.onPointerOver), t.addEventListener("pointerdown", e.onPointerDown), t.addEventListener("option-update", e.onUpdate);
19
61
  }
@@ -25,18 +67,18 @@ function t(e) {
25
67
  unbind: n
26
68
  };
27
69
  }
28
- function n(e, t, n, r) {
70
+ function i(e, t, n, r) {
29
71
  requestAnimationFrame(() => {
30
72
  let i = t();
31
73
  n() && !e.matches(":focus-within") && !i?.hasFocusWithin() && r();
32
74
  });
33
75
  }
34
- function r(e, t, n) {
76
+ function a(e, t, n) {
35
77
  if (e === 0) return -1;
36
78
  let r = t + n;
37
79
  return r < 0 && (r = e - 1), r >= e && (r = 0), r;
38
80
  }
39
81
  //#endregion
40
- export { e as createComboboxOpenController, t as createOptionListenerBinding, n as handleComboboxFocusOut, r as nextWrappingIndex };
82
+ export { t as createComboboxOpenController, r as createOptionListenerBinding, n as defineComboboxTrigger, i as handleComboboxFocusOut, a as nextWrappingIndex };
41
83
 
42
84
  //# sourceMappingURL=combobox-shell.js.map