@greypan/web-ui 6.3.0 → 6.4.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 (107) hide show
  1. package/README.CN.md +13 -4
  2. package/README.md +13 -4
  3. package/dist/_virtual/{_@oxc-project_runtime@0.146.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorate.js +1 -1
  4. package/dist/assets/glass.js +1 -1
  5. package/dist/assets/glass.js.map +1 -1
  6. package/dist/assets/menu-portal.js +1 -1
  7. package/dist/assets/menu-portal.js.map +1 -1
  8. package/dist/assets/overlay-motion.js +1 -1
  9. package/dist/assets/overlay-motion.js.map +1 -1
  10. package/dist/components/autocomplete/index.js +3 -3
  11. package/dist/components/autocomplete/index.js.map +1 -1
  12. package/dist/components/autocomplete/style.js +1 -1
  13. package/dist/components/autocomplete/style.js.map +1 -1
  14. package/dist/components/avatar/index.js +1 -1
  15. package/dist/components/back-top/index.js +1 -1
  16. package/dist/components/badge/index.js +1 -1
  17. package/dist/components/button/index.js +1 -1
  18. package/dist/components/button-group/index.js +1 -1
  19. package/dist/components/checkbox/index.js +2 -2
  20. package/dist/components/checkbox/index.js.map +1 -1
  21. package/dist/components/checkbox/style.js +1 -1
  22. package/dist/components/checkbox/style.js.map +1 -1
  23. package/dist/components/checkbox-group/index.js +2 -2
  24. package/dist/components/checkbox-group/index.js.map +1 -1
  25. package/dist/components/collapse/index.js +3 -3
  26. package/dist/components/collapse/index.js.map +1 -1
  27. package/dist/components/context-menu/index.js +7 -7
  28. package/dist/components/context-menu/index.js.map +1 -1
  29. package/dist/components/dialog/index.js +1 -1
  30. package/dist/components/dialog/style.js +1 -1
  31. package/dist/components/dialog/style.js.map +1 -1
  32. package/dist/components/drawer/index.js +1 -1
  33. package/dist/components/drawer/index.js.map +1 -1
  34. package/dist/components/drawer/style.js +1 -1
  35. package/dist/components/dropdown/index.js +5 -5
  36. package/dist/components/dropdown/index.js.map +1 -1
  37. package/dist/components/dropdown-divider/index.js +1 -1
  38. package/dist/components/dropdown-header/index.js +1 -1
  39. package/dist/components/dropdown-item/index.js +1 -1
  40. package/dist/components/empty/index.js +1 -1
  41. package/dist/components/icon/index.js +1 -1
  42. package/dist/components/icon/style.js +1 -1
  43. package/dist/components/icon/style.js.map +1 -1
  44. package/dist/components/image-preview/index.js +5 -5
  45. package/dist/components/image-preview/index.js.map +1 -1
  46. package/dist/components/image-preview/style.js +1 -1
  47. package/dist/components/image-preview/style.js.map +1 -1
  48. package/dist/components/input/index.js +2 -2
  49. package/dist/components/input/index.js.map +1 -1
  50. package/dist/components/input/style.js.map +1 -1
  51. package/dist/components/input-number/index.js +2 -2
  52. package/dist/components/input-number/index.js.map +1 -1
  53. package/dist/components/layout/index.js +1 -1
  54. package/dist/components/option/index.js +1 -1
  55. package/dist/components/popover/index.js +1 -1
  56. package/dist/components/radio/index.js +2 -2
  57. package/dist/components/radio/index.js.map +1 -1
  58. package/dist/components/radio/style.js +1 -1
  59. package/dist/components/radio/style.js.map +1 -1
  60. package/dist/components/radio-group/index.js +2 -2
  61. package/dist/components/radio-group/index.js.map +1 -1
  62. package/dist/components/segmented/index.js +1 -1
  63. package/dist/components/segmented/style.js +1 -1
  64. package/dist/components/segmented/style.js.map +1 -1
  65. package/dist/components/segmented-trigger/index.js +1 -1
  66. package/dist/components/select/index.js +3 -3
  67. package/dist/components/select/index.js.map +1 -1
  68. package/dist/components/select/style.js +1 -1
  69. package/dist/components/select/style.js.map +1 -1
  70. package/dist/components/slider/index.js +1 -1
  71. package/dist/components/slider/style.js +1 -1
  72. package/dist/components/slider/style.js.map +1 -1
  73. package/dist/components/spinner/index.js +2 -2
  74. package/dist/components/spinner/index.js.map +1 -1
  75. package/dist/components/spinner/style.js +1 -1
  76. package/dist/components/spinner/style.js.map +1 -1
  77. package/dist/components/svg-draw-lines/index.js +1 -1
  78. package/dist/components/svg-draw-lines/style.js +1 -1
  79. package/dist/components/svg-draw-lines/style.js.map +1 -1
  80. package/dist/components/switch/index.js +2 -2
  81. package/dist/components/switch/index.js.map +1 -1
  82. package/dist/components/switch/style.js +1 -1
  83. package/dist/components/switch/style.js.map +1 -1
  84. package/dist/components/textarea/index.js +3 -3
  85. package/dist/components/textarea/index.js.map +1 -1
  86. package/dist/components/textarea/style.js.map +1 -1
  87. package/dist/components/theme/index.js +1 -1
  88. package/dist/components/theme/style.js +1 -1
  89. package/dist/components/theme/style.js.map +1 -1
  90. package/dist/components/toast/style.js +1 -1
  91. package/dist/components/toast/style.js.map +1 -1
  92. package/dist/components/toast/toast.js +1 -1
  93. package/dist/components/tooltip/index.js +6 -3
  94. package/dist/components/tooltip/index.js.map +1 -1
  95. package/dist/shared/form-association/index.js +1 -1
  96. package/dist/shared/form-association/index.js.map +1 -1
  97. package/dist/shared/menu-portal/menu-tree.js +1 -1
  98. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  99. package/dist/shared/overlay/native-dialog-presence.js +2 -2
  100. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  101. package/dist/shared/overlay/overlay.js +1 -1
  102. package/dist/shared/overlay/overlay.js.map +1 -1
  103. package/dist/shared/overlay/portal.js +1 -1
  104. package/dist/shared/overlay/portal.js.map +1 -1
  105. package/dist/shared/visible-area/index.js +1 -1
  106. package/dist/shared/visible-area/index.js.map +1 -1
  107. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/switch/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n touch-action: none;\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\n/*\n标准视觉隐藏技术(sr-only):\n业内标准的“屏幕阅读器专用”隐藏方案。\n把复选框缩放到 1x1 像素,但保留在 dom 中,\n既让肉眼看不见,又能让读屏软件识别,并允许键盘用户通过空格键切换状态。\n*/\n.sr-only {\n position: absolute;\n\n overflow: hidden;\n\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n\n white-space: nowrap;\n\n clip-path: inset(50%);\n}\n\n.wui-switch-track {\n touch-action: none;\n cursor: default;\n user-select: none;\n\n position: relative;\n\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n width: 40px;\n height: 20px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n background-color: var(--wui-color-surface-track, #e5e5ea);\n outline: var(--wui-focus-ring-width, 3px) solid transparent;\n outline-offset: 2px;\n\n transition: background-color var(--wui-duration-trigger, 160ms) ease;\n\n /* 实际获得焦点的是内部 sr-only 的 checkbox,track 本身不可聚焦;\n :focus-visible 在 track 上永不匹配,需用 :focus-within 让键盘焦点环生效 */\n &:focus-within {\n outline-color: var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n }\n\n &.is-open {\n background-color: var(--wui-color-accent, #08f);\n }\n\n &.is-disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n.wui-switch-thumb {\n --wui-glass-corner-radius: calc(16px / 2);\n\n position: absolute;\n top: 2px;\n left: 2px;\n transform-origin: center center;\n transform: translateX(0) scale(1);\n\n overflow: hidden;\n\n width: 16px;\n height: 16px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n transition:\n width var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n transform var(--wui-duration-trigger, 160ms) cubic-bezier(0.4, 0, 0.2, 1),\n border-radius var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n background-color var(--wui-duration-press, 80ms) ease,\n box-shadow var(--wui-duration-press, 80ms) ease;\n\n /*\n * 静止态:实体白 thumb。按压/拖拽时切到 wui-glass(backdrop blur + 半透明玻璃背景\n * + 描边)并放大 1.5x,背景转为透明让玻璃材质透出。\n *\n * 按压/拖拽的 box-shadow 必须直接写死值、不能经自定义属性中转:iOS Safari 对\n * 「自定义属性值变化驱动依赖属性」不触发 transition(且 var 离散切换可能整体\n * 不生效),上一轮经 var 中转让按压阴影在真机上「回退之前」。直接写值后 box-shadow\n * 是普通属性变化,transition 正常插值。这里同时复制 wui-glass 的三条 inset 高光,\n * 避免整段覆盖后按压态丢失玻璃描边。\n */\n &.is-pressed {\n transform: translateX(0) scale(1.5);\n\n width: 20px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n background-color: transparent;\n box-shadow:\n inset 0 0 0 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 38%, transparent),\n inset 0 1px 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 52%, transparent),\n inset 0 -0.5px 1px rgb(0 0 0 / 0.03),\n 0 1px 6px rgb(0 0 0 / 0.2),\n 0 6px 16px rgb(0 0 0 / 0.16),\n 0 14px 28px rgb(0 0 0 / 0.1);\n }\n\n &:not(.is-pressed) {\n background-color: var(--wui-color-on-control, #fff);\n box-shadow: 1px 2px 6px rgb(0 0 0 / 0.2);\n }\n}\n\n.wui-switch-track.is-open .wui-switch-thumb {\n transform: translateX(20px) scale(1);\n\n &.is-pressed {\n transform: translateX(16px) scale(1.5);\n }\n}\n\n.wui-switch-track.is-dragging {\n cursor: grabbing;\n}\n\n:host([data-wui-pointer-focus]) .wui-switch-track:focus-within {\n outline-color: transparent;\n}\n\n.wui-switch-track.is-dragging .wui-switch-thumb,\n.wui-switch-track.is-dragging .wui-switch-thumb.is-pressed {\n transform: translateX(var(--wui-switch-drag-offset, 0)) scale(1.5);\n transition: none;\n}\n\n.wui-switch-loading {\n pointer-events: none;\n\n position: absolute;\n inset: 0;\n\n display: flex;\n align-items: center;\n justify-content: center;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/switch/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n touch-action: none;\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\n/*\n标准视觉隐藏技术(sr-only):\n业内标准的“屏幕阅读器专用”隐藏方案。\n把复选框缩放到 1x1 像素,但保留在 dom 中,\n既让肉眼看不见,又能让读屏软件识别,并允许键盘用户通过空格键切换状态。\n*/\n.sr-only {\n position: absolute;\n\n overflow: hidden;\n\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n\n white-space: nowrap;\n\n clip-path: inset(50%);\n}\n\n.wui-switch-track {\n touch-action: none;\n cursor: default;\n user-select: none;\n\n position: relative;\n\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n width: 40px;\n height: 20px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n background-color: var(--wui-color-surface-track, #e5e5ea);\n outline: var(--wui-focus-ring-width, 3px) solid transparent;\n outline-offset: 2px;\n\n transition: background-color var(--wui-duration-trigger, 160ms) ease;\n\n /* 实际获得焦点的是内部 sr-only 的 checkbox,track 本身不可聚焦;\n :focus-visible 在 track 上永不匹配,需用 :focus-within 让键盘焦点环生效 */\n &:focus-within {\n outline-color: var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n }\n\n &.is-open {\n background-color: var(--wui-color-accent, #08f);\n }\n\n &.is-disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n}\n\n.wui-switch-thumb {\n --wui-glass-corner-radius: calc(16px / 2);\n\n position: absolute;\n top: 2px;\n left: 2px;\n transform-origin: center center;\n transform: translateX(0) scale(1);\n\n overflow: hidden;\n\n width: 16px;\n height: 16px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n transition:\n width var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n transform var(--wui-duration-trigger, 160ms) cubic-bezier(0.4, 0, 0.2, 1),\n border-radius var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n background-color var(--wui-duration-press, 80ms) ease,\n box-shadow var(--wui-duration-press, 80ms) ease;\n\n &.is-pressed {\n transform: translateX(0) scale(1.5);\n\n width: 20px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n background-color: transparent;\n box-shadow:\n inset 0 0 0 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 38%, transparent),\n inset 0 1px 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 52%, transparent),\n inset 0 -0.5px 1px rgb(0 0 0 / 0.03),\n 0 2px 20px rgb(0 0 0 / 0.2);\n }\n\n &:not(.is-pressed) {\n background-color: var(--wui-color-on-control, #fff);\n box-shadow: 1px 2px 6px rgb(0 0 0 / 0.2);\n }\n}\n\n.wui-switch-track.is-open .wui-switch-thumb {\n transform: translateX(20px) scale(1);\n\n &.is-pressed {\n transform: translateX(16px) scale(1.5);\n }\n}\n\n.wui-switch-track.is-dragging {\n cursor: grabbing;\n}\n\n:host([data-wui-pointer-focus]) .wui-switch-track:focus-within {\n outline-color: transparent;\n}\n\n.wui-switch-track.is-dragging .wui-switch-thumb,\n.wui-switch-track.is-dragging .wui-switch-thumb.is-pressed {\n transform: translateX(var(--wui-switch-drag-offset, 0)) scale(1.5);\n transition: none;\n}\n\n.wui-switch-loading {\n pointer-events: none;\n\n position: absolute;\n inset: 0;\n\n display: flex;\n align-items: center;\n justify-content: center;\n}\n"],"mappings":""}
@@ -1,4 +1,4 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
3
  import t from "../../icons/generated/jam-close-circle-f.js";
4
4
  import n from "../../assets/glass.js";
@@ -58,7 +58,7 @@ var v = class extends r(c) {
58
58
  }
59
59
  _syncValidity() {
60
60
  let e = this._formAssociation.getInternals(), t = this._getTextarea();
61
- !e || !t || typeof e.setValidity != "function" || o(e, t, [
61
+ e && t && typeof e.setValidity == "function" && o(e, t, [
62
62
  "valueMissing",
63
63
  "tooShort",
64
64
  "tooLong"
@@ -77,7 +77,7 @@ var v = class extends r(c) {
77
77
  this._resizeObserver?.disconnect(), this._resizeObserver = null, e && this._textarea?.style.removeProperty("height");
78
78
  }
79
79
  _autosize() {
80
- !this._textarea || !this.autosize || (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight}px`);
80
+ this._textarea && this.autosize && (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight}px`);
81
81
  }
82
82
  handleInput(e) {
83
83
  e.target instanceof HTMLTextAreaElement && (this._value = e.target.value, this._formAssociation.sync(), this._syncValidity(), this._autosize());
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/textarea/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport '@/components/icon'\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { jamCloseCircleF } from '@/icons'\nimport {\n FormAssociated,\n defineFormAssociation,\n forwardInputValidity,\n FormAssociationController\n} from '@/shared/form-association'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-textarea')\nexport class WebUiTextarea extends FormAssociated(LitElement) {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) readonly = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) full = false\n @property({ type: Boolean, reflect: true }) clearable = false\n @property({ type: Boolean, reflect: true }) borderless = false\n @property({ type: Number, reflect: true }) rows = 3\n @property({ type: Number, reflect: true }) minlength: number | undefined\n @property({ type: Number, reflect: true }) maxlength: number | undefined\n @property({ type: Boolean, reflect: true }) autosize = false\n // 自动高度上限(px);0 表示不限制,随内容无限增高\n @property({ type: Number, reflect: true, attribute: 'max-height' }) maxHeight = 0\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n @property({ type: String, attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined\n\n @state() private _value = ''\n @state() private _focused = false\n @state() private _hasPrefix = false\n @state() private _hasSuffix = false\n\n private _textarea: HTMLTextAreaElement | null = null\n private _resizeObserver: ResizeObserver | null = null\n\n @property({ type: String, reflect: true })\n get value(): string {\n return this._value\n }\n\n set value(v: string) {\n const old = this._value\n this._value = v\n this._formAssociation.sync()\n this.requestUpdate('value', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formAssociation.isFormDisabled()\n }\n\n private readonly _formAssociation = defineFormAssociation<string>({\n host: this,\n getState: () => this._value,\n setState: value => {\n this.value = value\n },\n getFormValue: () => this._value,\n getFormState: () => this._value,\n restoreState: state => {\n if (typeof state === 'string') this.value = state\n },\n syncValidity: () => this._syncValidity()\n }).make()\n\n private readonly _formAssociationController = new FormAssociationController(this, this._formAssociation)\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._teardownAutosize()\n }\n\n override firstUpdated() {\n this._textarea = this.shadowRoot?.querySelector('textarea') ?? null\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('_value')) {\n const textarea = this._getTextarea()\n if (textarea && textarea.value !== this._value) {\n textarea.value = this._value\n }\n }\n if (changed.has('autosize')) {\n if (this.autosize) {\n this._setupAutosize()\n } else {\n this._teardownAutosize(true)\n }\n }\n this._syncValidity()\n this.toggleAttribute('focused', this._focused)\n }\n\n private _getTextarea(): HTMLTextAreaElement | null {\n this._textarea ??= this.shadowRoot?.querySelector('textarea') ?? null\n return this._textarea\n }\n\n private _syncValidity() {\n const internals = this._formAssociation.getInternals()\n const textarea = this._getTextarea()\n if (!internals || !textarea || typeof internals.setValidity !== 'function') return\n\n forwardInputValidity(internals, textarea, ['valueMissing', 'tooShort', 'tooLong'], this._isDisabled)\n }\n\n private _setupAutosize() {\n this._teardownAutosize()\n if (typeof ResizeObserver === 'undefined') {\n this._autosize()\n return\n }\n this._resizeObserver = new ResizeObserver(() => {\n this._autosize()\n })\n if (this._textarea) this._resizeObserver.observe(this._textarea)\n this._autosize()\n }\n\n private _teardownAutosize(resetHeight = false) {\n this._resizeObserver?.disconnect()\n this._resizeObserver = null\n if (resetHeight) this._textarea?.style.removeProperty('height')\n }\n\n private _autosize() {\n if (!this._textarea || !this.autosize) return\n this._textarea.style.height = 'auto'\n // height:auto 时 rows 已驱动自然高,scrollHeight 恒 ≥ rows 行高,无需额外 floor;\n // 上限由 CSS max-height(maxHeight 属性)钳制,这里只负责随内容增高,默认无限\n this._textarea.style.height = `${this._textarea.scrollHeight}px`\n }\n\n private handleInput(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._formAssociation.sync()\n this._syncValidity()\n this._autosize()\n }\n\n private handleFocus() {\n if (!this._isDisabled) this._focused = true\n }\n\n private handleBlur() {\n this._focused = false\n }\n\n // 原生 change 不 composed,被 shadow root 挡住;这里补发 composed 事件,\n // 兑现 $events/README 声明的公共 change 契约。\n private handleNativeChange(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._formAssociation.sync()\n this._syncValidity()\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n override focus() {\n this.shadowRoot?.querySelector('textarea')?.focus()\n }\n\n override blur() {\n this.shadowRoot?.querySelector('textarea')?.blur()\n }\n\n select() {\n this.shadowRoot?.querySelector('textarea')?.select()\n }\n\n private focusTextarea() {\n if (this._isDisabled) return\n this.shadowRoot?.querySelector('textarea')?.focus()\n }\n\n private _onSlotChange(e: Event) {\n if (!(e.target instanceof HTMLSlotElement)) return\n const slot = e.target\n const hasContent = slot.assignedElements().length > 0\n if (slot.name === 'prefix') this._hasPrefix = hasContent\n if (slot.name === 'suffix') this._hasSuffix = hasContent\n }\n\n private handleClear() {\n if (this._isDisabled || this.readonly) return\n this._value = ''\n this._formAssociation.sync()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n }\n\n private preventMouseDownBlur(e: Event) {\n e.preventDefault()\n }\n\n override render() {\n // readonly 下不可清除:清空按钮会修改值,与只读语义冲突\n const showClear = this.clearable && this._value && !this.readonly\n\n return html`\n <div class=\"wui-glass wui-textarea-inner\" @click=${this.focusTextarea}>\n <slot name=\"prefix\" class=${classMap({ empty: !this._hasPrefix })} @slotchange=${this._onSlotChange}></slot>\n <textarea\n placeholder=${this.placeholder}\n name=${this.name}\n aria-label=${ifDefined(this.ariaLabel)}\n aria-labelledby=${ifDefined(this.ariaLabelledby)}\n .rows=${this.rows}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n ?disabled=${this._isDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n .value=${this._value}\n style=${this.maxHeight > 0 ? styleMap({ 'max-height': `${this.maxHeight}px` }) : nothing}\n @input=${this.handleInput}\n @change=${this.handleNativeChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n ></textarea>\n ${\n showClear\n ? html`<web-ui-button\n icon\n variant=\"ghost\"\n size=\"24\"\n aria-label=\"清除\"\n @pointerdown=${this.preventMouseDownBlur}\n @click=${this.handleClear}\n >\n <web-ui-icon .icon=${jamCloseCircleF}></web-ui-icon>\n </web-ui-button>`\n : ''\n }\n <slot name=\"suffix\" class=${classMap({ empty: !this._hasSuffix })} @slotchange=${this._onSlotChange}></slot>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n focus: FocusEvent\n blur: FocusEvent\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-textarea': WebUiTextarea\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/textarea/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport '@/components/icon'\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { jamCloseCircleF } from '@/icons'\nimport {\n FormAssociated,\n defineFormAssociation,\n forwardInputValidity,\n FormAssociationController\n} from '@/shared/form-association'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-textarea')\nexport class WebUiTextarea extends FormAssociated(LitElement) {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) readonly = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) full = false\n @property({ type: Boolean, reflect: true }) clearable = false\n @property({ type: Boolean, reflect: true }) borderless = false\n @property({ type: Number, reflect: true }) rows = 3\n @property({ type: Number, reflect: true }) minlength: number | undefined\n @property({ type: Number, reflect: true }) maxlength: number | undefined\n @property({ type: Boolean, reflect: true }) autosize = false\n // 自动高度上限(px);0 表示不限制,随内容无限增高\n @property({ type: Number, reflect: true, attribute: 'max-height' }) maxHeight = 0\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n @property({ type: String, attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined\n\n @state() private _value = ''\n @state() private _focused = false\n @state() private _hasPrefix = false\n @state() private _hasSuffix = false\n\n private _textarea: HTMLTextAreaElement | null = null\n private _resizeObserver: ResizeObserver | null = null\n\n @property({ type: String, reflect: true })\n get value(): string {\n return this._value\n }\n\n set value(v: string) {\n const old = this._value\n this._value = v\n this._formAssociation.sync()\n this.requestUpdate('value', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formAssociation.isFormDisabled()\n }\n\n private readonly _formAssociation = defineFormAssociation<string>({\n host: this,\n getState: () => this._value,\n setState: value => {\n this.value = value\n },\n getFormValue: () => this._value,\n getFormState: () => this._value,\n restoreState: state => {\n if (typeof state === 'string') this.value = state\n },\n syncValidity: () => this._syncValidity()\n }).make()\n\n private readonly _formAssociationController = new FormAssociationController(this, this._formAssociation)\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._teardownAutosize()\n }\n\n override firstUpdated() {\n this._textarea = this.shadowRoot?.querySelector('textarea') ?? null\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('_value')) {\n const textarea = this._getTextarea()\n if (textarea && textarea.value !== this._value) {\n textarea.value = this._value\n }\n }\n if (changed.has('autosize')) {\n if (this.autosize) {\n this._setupAutosize()\n } else {\n this._teardownAutosize(true)\n }\n }\n this._syncValidity()\n this.toggleAttribute('focused', this._focused)\n }\n\n private _getTextarea(): HTMLTextAreaElement | null {\n this._textarea ??= this.shadowRoot?.querySelector('textarea') ?? null\n return this._textarea\n }\n\n private _syncValidity() {\n const internals = this._formAssociation.getInternals()\n const textarea = this._getTextarea()\n if (!internals || !textarea || typeof internals.setValidity !== 'function') return\n\n forwardInputValidity(internals, textarea, ['valueMissing', 'tooShort', 'tooLong'], this._isDisabled)\n }\n\n private _setupAutosize() {\n this._teardownAutosize()\n if (typeof ResizeObserver === 'undefined') {\n this._autosize()\n return\n }\n this._resizeObserver = new ResizeObserver(() => {\n this._autosize()\n })\n if (this._textarea) this._resizeObserver.observe(this._textarea)\n this._autosize()\n }\n\n private _teardownAutosize(resetHeight = false) {\n this._resizeObserver?.disconnect()\n this._resizeObserver = null\n if (resetHeight) this._textarea?.style.removeProperty('height')\n }\n\n private _autosize() {\n if (!this._textarea || !this.autosize) return\n this._textarea.style.height = 'auto'\n // height:auto 时 rows 已驱动自然高,scrollHeight 恒 ≥ rows 行高,无需额外 floor;\n // 上限由 CSS max-height(maxHeight 属性)钳制,这里只负责随内容增高,默认无限\n this._textarea.style.height = `${this._textarea.scrollHeight}px`\n }\n\n private handleInput(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._formAssociation.sync()\n this._syncValidity()\n this._autosize()\n }\n\n private handleFocus() {\n if (!this._isDisabled) this._focused = true\n }\n\n private handleBlur() {\n this._focused = false\n }\n\n // 原生 change 不 composed,被 shadow root 挡住;这里补发 composed 事件,\n // 兑现 $events/README 声明的公共 change 契约。\n private handleNativeChange(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._formAssociation.sync()\n this._syncValidity()\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n override focus() {\n this.shadowRoot?.querySelector('textarea')?.focus()\n }\n\n override blur() {\n this.shadowRoot?.querySelector('textarea')?.blur()\n }\n\n select() {\n this.shadowRoot?.querySelector('textarea')?.select()\n }\n\n private focusTextarea() {\n if (this._isDisabled) return\n this.shadowRoot?.querySelector('textarea')?.focus()\n }\n\n private _onSlotChange(e: Event) {\n if (!(e.target instanceof HTMLSlotElement)) return\n const slot = e.target\n const hasContent = slot.assignedElements().length > 0\n if (slot.name === 'prefix') this._hasPrefix = hasContent\n if (slot.name === 'suffix') this._hasSuffix = hasContent\n }\n\n private handleClear() {\n if (this._isDisabled || this.readonly) return\n this._value = ''\n this._formAssociation.sync()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n }\n\n private preventMouseDownBlur(e: Event) {\n e.preventDefault()\n }\n\n override render() {\n // readonly 下不可清除:清空按钮会修改值,与只读语义冲突\n const showClear = this.clearable && this._value && !this.readonly\n\n return html`\n <div class=\"wui-glass wui-textarea-inner\" @click=${this.focusTextarea}>\n <slot name=\"prefix\" class=${classMap({ empty: !this._hasPrefix })} @slotchange=${this._onSlotChange}></slot>\n <textarea\n placeholder=${this.placeholder}\n name=${this.name}\n aria-label=${ifDefined(this.ariaLabel)}\n aria-labelledby=${ifDefined(this.ariaLabelledby)}\n .rows=${this.rows}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n ?disabled=${this._isDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n .value=${this._value}\n style=${this.maxHeight > 0 ? styleMap({ 'max-height': `${this.maxHeight}px` }) : nothing}\n @input=${this.handleInput}\n @change=${this.handleNativeChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n ></textarea>\n ${\n showClear\n ? html`<web-ui-button\n icon\n variant=\"ghost\"\n size=\"24\"\n aria-label=\"清除\"\n @pointerdown=${this.preventMouseDownBlur}\n @click=${this.handleClear}\n >\n <web-ui-icon .icon=${jamCloseCircleF}></web-ui-icon>\n </web-ui-button>`\n : ''\n }\n <slot name=\"suffix\" class=${classMap({ empty: !this._hasSuffix })} @slotchange=${this._onSlotChange}></slot>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n focus: FocusEvent\n blur: FocusEvent\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-textarea': WebUiTextarea\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/textarea/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-textarea-clear-color: var(\n --wui-color-text-tertiary,\n color-mix(in srgb, var(--wui-color-text) 35%, transparent)\n );\n display: block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n/* ===== Textarea ===== */\n\n.wui-textarea-inner {\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n position: relative;\n\n display: flex;\n gap: 8px;\n align-items: flex-start;\n\n box-sizing: border-box;\n width: var(--wui-textarea-width, 200px);\n min-width: var(--wui-control-size, 36px);\n min-height: var(--wui-control-size, 36px);\n padding: 7.5px 12px;\n border-radius: var(--wui-radius-menu, 18px);\n}\n\n:host([full]) .wui-textarea-inner {\n width: 100%;\n}\n\n/* ===== Borderless ===== */\n\n:host([borderless]) .wui-textarea-inner {\n border: none;\n\n background: transparent;\n\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: none;\n backdrop-filter: none;\n box-shadow: none;\n}\n\n/* borderless 必须移除 glass 描边环(.wui-glass::before 底环 + 对角光泽),\n 否则无框后仍残留 1px 描边 */\n:host([borderless]) .wui-textarea-inner::before {\n content: none;\n}\n\ntextarea {\n resize: vertical;\n\n display: block;\n flex: 1;\n\n box-sizing: border-box;\n width: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: var(--wui-color-text-secondary, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n }\n\n &:read-only {\n cursor: default;\n }\n}\n\n/* Coarse pointers include iOS Safari, where a sub-16px font triggers focus zoom. */\n@media (pointer: coarse) {\n textarea {\n font-size: max(16px, var(--wui-font-size, 14px));\n }\n}\n\n/* Focus ring 独立成 ::after 层:base/focused 都是显式 box-shadow,保证所有变体都能过渡 */\n.wui-textarea-inner::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n border-radius: inherit;\n\n box-shadow:\n inset 0 0 0 1px transparent,\n 0 0 0 var(--wui-focus-ring-width, 3px) transparent;\n\n transition: box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .wui-textarea-inner::after {\n box-shadow:\n inset 0 0 0 1px var(--wui-color-accent, #08f),\n 0 0 0 var(--wui-focus-ring-width, 3px) var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n}\n\n/* ===== Prefix / Suffix ===== */\n\nslot {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\nslot.empty {\n display: none;\n}\n\n/* ===== Clear button ===== */\n\n/* 复用 web-ui-button icon ghost:仅覆盖颜色为 faint 并对齐首行,保持弱意图清除图标观感;\n 负 margin-left 抵消容器 flex gap,让清除按钮紧贴文本域内容\n 负 margin-right 抵消 button padding,让清除按钮右侧 spacing 视觉上协调 */\n.wui-textarea-inner web-ui-button[variant='ghost'] {\n --wui-button-color: var(--wui-textarea-clear-color);\n\n /* 与首行文字垂直居中对齐:容器 align-items: flex-start 使按钮贴内容区顶部,\n 首行中心 = padding-top + 行高/2;24px 按钮需相对内容区上移 (行高 − 按钮高度) / 2 */\n margin-top: calc((var(--wui-font-size, 14px) * 1.5 - 24px) / 2);\n margin-right: -4px;\n margin-left: -8px;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/textarea/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-textarea-clear-color: var(\n --wui-color-text-tertiary,\n color-mix(in srgb, var(--wui-color-text) 35%, transparent)\n );\n display: block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n/* ===== Textarea ===== */\n\n.wui-textarea-inner {\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n position: relative;\n\n display: flex;\n gap: 8px;\n align-items: flex-start;\n\n box-sizing: border-box;\n width: var(--wui-textarea-width, 200px);\n min-width: var(--wui-control-size, 36px);\n min-height: var(--wui-control-size, 36px);\n padding: 7.5px 12px;\n border-radius: var(--wui-radius-menu, 18px);\n}\n\n:host([full]) .wui-textarea-inner {\n width: 100%;\n}\n\n/* ===== Borderless ===== */\n\n:host([borderless]) .wui-textarea-inner {\n border: none;\n background: transparent;\n backdrop-filter: none;\n box-shadow: none;\n}\n\n/* borderless 必须移除 glass 描边环(.wui-glass::before 底环 + 对角光泽),\n 否则无框后仍残留 1px 描边 */\n:host([borderless]) .wui-textarea-inner::before {\n content: none;\n}\n\ntextarea {\n resize: vertical;\n\n display: block;\n flex: 1;\n\n box-sizing: border-box;\n width: 100%;\n margin: 0;\n padding: 0;\n border: none;\n\n /* 表单控件不继承字体;显式继承以对齐宿主排版,避免 UA 默认字体差异 */\n font: inherit;\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n\n background: transparent;\n outline: none;\n\n &::placeholder {\n color: var(--wui-color-text-secondary, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n }\n\n &:read-only {\n cursor: default;\n }\n}\n\n/* Coarse pointers include iOS Safari, where a sub-16px font triggers focus zoom. */\n@media (pointer: coarse) {\n textarea {\n font-size: max(16px, var(--wui-font-size, 14px));\n }\n}\n\n/* Focus ring 独立成 ::after 层:base/focused 都是显式 box-shadow,保证所有变体都能过渡 */\n.wui-textarea-inner::after {\n pointer-events: none;\n content: '';\n\n position: absolute;\n inset: 0;\n\n border-radius: inherit;\n\n box-shadow:\n inset 0 0 0 1px transparent,\n 0 0 0 var(--wui-focus-ring-width, 3px) transparent;\n\n transition: box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([focused]) .wui-textarea-inner::after {\n box-shadow:\n inset 0 0 0 1px var(--wui-color-accent, #08f),\n 0 0 0 var(--wui-focus-ring-width, 3px) var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n}\n\n/* ===== Prefix / Suffix ===== */\n\nslot {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\nslot.empty {\n display: none;\n}\n\n/* ===== Clear button ===== */\n\n/* 复用 web-ui-button icon ghost:仅覆盖颜色为 faint 并对齐首行,保持弱意图清除图标观感;\n 负 margin-left 抵消容器 flex gap,让清除按钮紧贴文本域内容\n 负 margin-right 抵消 button padding,让清除按钮右侧 spacing 视觉上协调 */\n.wui-textarea-inner web-ui-button[variant='ghost'] {\n --wui-button-color: var(--wui-textarea-clear-color);\n\n /* 与首行文字垂直居中对齐:容器 align-items: flex-start 使按钮贴内容区顶部,\n 首行中心 = padding-top + 行高/2;24px 按钮需相对内容区上移 (行高 − 按钮高度) / 2 */\n margin-top: calc((var(--wui-font-size, 14px) * 1.5 - 24px) / 2);\n margin-right: -4px;\n margin-left: -8px;\n}\n"],"mappings":""}
@@ -1,4 +1,4 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
2
2
  import { normalizeLiteral as t } from "../../shared/normalize/index.js";
3
3
  import { applyOverlayRootStyles as n } from "../../shared/overlay/overlay-root.js";
4
4
  import r from "./style.js";
@@ -1,5 +1,5 @@
1
1
  //#region src/components/theme/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{--wui-font-size:14px;--wui-input-width:200px;--wui-control-size:36px;--wui-overlay-min-width:200px;--wui-layer-base:0;--wui-layer-inline-overlay:1;--wui-layer-header:10;--wui-layer-auxiliary:20;--wui-layer-banner:30;--wui-layer-tabbar:40;--wui-layer-sidebar:50;--wui-layer-menu:100;--wui-layer-menu-nested:110;--wui-layer-toast:200;--wui-layer-loading:300;--wui-duration-press:80ms;--wui-duration-feedback:.1s;--wui-duration-trigger:.16s;--wui-duration-focus:.2s;--wui-duration-float-enter:.16s;--wui-duration-float-exit:.12s;--wui-duration-dialog-enter:.32s;--wui-duration-dialog-exit:.26s;--wui-duration-drawer-enter:.28s;--wui-duration-drawer-exit:.24s;--wui-duration-drawer-nested:.45s;--wui-duration-toast-enter:.28s;--wui-duration-toast-exit:.2s;--wui-duration-collapse-enter:.2s;--wui-duration-collapse-exit:.16s;--wui-duration-layout:.2s;--wui-ease-enter:cubic-bezier(.23, 1, .32, 1);--wui-ease-dialog:cubic-bezier(.2, 0, 0, 1);--wui-ease-slide:cubic-bezier(.77, 0, .175, 1);--wui-scale-enter:.97;--wui-focus-ring-width:3px;--wui-radius-control:calc(infinity * 1px);--wui-radius-menu:18px;--wui-radius-overlay:28px;display:contents}:host([motion=reduced]){--wui-duration-press:0s;--wui-duration-feedback:0s;--wui-duration-trigger:0s;--wui-duration-focus:0s;--wui-duration-float-enter:0s;--wui-duration-float-exit:0s;--wui-duration-dialog-enter:0s;--wui-duration-dialog-exit:0s;--wui-duration-drawer-enter:0s;--wui-duration-drawer-exit:0s;--wui-duration-drawer-nested:0s;--wui-duration-toast-enter:0s;--wui-duration-toast-exit:0s;--wui-duration-collapse-enter:0s;--wui-duration-collapse-exit:0s;--wui-duration-layout:0s;--wui-scale-enter:1}@media (prefers-reduced-motion:reduce){:host([motion=system]){--wui-duration-press:0s;--wui-duration-feedback:0s;--wui-duration-trigger:0s;--wui-duration-focus:0s;--wui-duration-float-enter:0s;--wui-duration-float-exit:0s;--wui-duration-dialog-enter:0s;--wui-duration-dialog-exit:0s;--wui-duration-drawer-enter:0s;--wui-duration-drawer-exit:0s;--wui-duration-drawer-nested:0s;--wui-duration-toast-enter:0s;--wui-duration-toast-exit:0s;--wui-duration-collapse-enter:0s;--wui-duration-collapse-exit:0s;--wui-duration-layout:0s;--wui-scale-enter:1}}:host([appearance=light]),:host([appearance=system]){--wui-color-page:#fff;--wui-color-surface:#fff;--wui-color-surface-raised:#f2f2f7;--wui-color-surface-control:#dfdfdf;--wui-color-surface-track:#e5e5ea;--wui-color-surface-menu:#f6f6f6d1;--wui-color-surface-glass:#fafafa57;--wui-color-surface-glass-hover:color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));--wui-color-surface-glass-active:color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));--wui-color-surface-overlay:#f6f6f6d1;--wui-color-surface-segmented:#e5e5ea;--wui-color-surface-selected:#fff;--wui-color-text:#1b1b1b;--wui-color-text-secondary:#6a6a6a;--wui-color-text-tertiary:color-mix(in srgb, var(--wui-color-text) 35%, transparent);--wui-color-text-disabled:color-mix(in srgb, var(--wui-color-text) 32%, transparent);--wui-color-state-layer-hover:color-mix(in srgb, var(--wui-color-text) 6%, transparent);--wui-color-state-layer-active:color-mix(in srgb, var(--wui-color-text) 15%, transparent);--wui-color-border:#0000001a;--wui-color-glass-border:transparent;--wui-color-glass-highlight:#ffffffe6;--wui-color-glass-corner:#ffffff14;--wui-color-glass-shade:#0000000f;--wui-glass-brightness:1.06;--wui-color-accent:#08f;--wui-color-on-accent:#fff;--wui-color-on-control:#fff;--wui-color-success:#16a34a;--wui-color-warning:#d97706;--wui-color-danger:#dc2626;--wui-color-info:#2563eb;--wui-color-backdrop:#0000001f;--wui-shadow-overlay:2px 16px 40px #0006;--wui-shadow-panel:0 3px 9px #00000045;--wui-shadow-glass:0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004;--wui-color-focus-ring:#08f6;--lightningcss-light:initial;--lightningcss-dark: ;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:host([appearance=dark]){--wui-color-page:#242628;--wui-color-surface:#2c2c2e;--wui-color-surface-raised:#2c2c2e;--wui-color-surface-control:#3a3a3c;--wui-color-surface-track:#444446;--wui-color-surface-menu:#1e1e20eb;--wui-color-surface-glass:#2c2c2e6b;--wui-color-surface-glass-hover:color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));--wui-color-surface-glass-active:color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));--wui-color-surface-overlay:#202222e6;--wui-color-surface-segmented:#3a3a3c;--wui-color-surface-selected:#5c5c5e;--wui-color-text:#e9eaea;--wui-color-text-secondary:#a1a1a6;--wui-color-text-tertiary:color-mix(in srgb, var(--wui-color-text) 42%, transparent);--wui-color-text-disabled:color-mix(in srgb, var(--wui-color-text) 38%, transparent);--wui-color-state-layer-hover:color-mix(in srgb, var(--wui-color-text) 6%, transparent);--wui-color-state-layer-active:color-mix(in srgb, var(--wui-color-text) 15%, transparent);--wui-color-border:#ffffff24;--wui-color-glass-border:#ffffff0d;--wui-color-glass-highlight:#ffffff1a;--wui-color-glass-corner:#fff3;--wui-color-glass-shade:#00000080;--wui-glass-brightness:1.02;--wui-color-accent:#0a84ff;--wui-color-on-accent:#fff;--wui-color-on-control:#f2f2f7;--wui-color-success:#30d158;--wui-color-warning:#ff9f0a;--wui-color-danger:#ff453a;--wui-color-info:#64d2ff;--wui-color-backdrop:#0000007a;--wui-shadow-overlay:0 18px 48px #0000007a;--wui-shadow-panel:0 4px 16px #00000052;--wui-shadow-glass:0 8px 24px #00000014;--wui-color-focus-ring:#0a84ff9e;--lightningcss-light: ;--lightningcss-dark:initial;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@media (prefers-color-scheme:dark){:host([appearance=system]){--wui-color-page:#242628;--wui-color-surface:#2c2c2e;--wui-color-surface-raised:#2c2c2e;--wui-color-surface-control:#3a3a3c;--wui-color-surface-track:#444446;--wui-color-surface-menu:#1e1e20eb;--wui-color-surface-glass:#2c2c2e6b;--wui-color-surface-glass-hover:color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));--wui-color-surface-glass-active:color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));--wui-color-surface-overlay:#202222e6;--wui-color-surface-segmented:#3a3a3c;--wui-color-surface-selected:#5c5c5e;--wui-color-text:#e9eaea;--wui-color-text-secondary:#a1a1a6;--wui-color-text-tertiary:color-mix(in srgb, var(--wui-color-text) 42%, transparent);--wui-color-text-disabled:color-mix(in srgb, var(--wui-color-text) 38%, transparent);--wui-color-state-layer-hover:color-mix(in srgb, var(--wui-color-text) 6%, transparent);--wui-color-state-layer-active:color-mix(in srgb, var(--wui-color-text) 15%, transparent);--wui-color-border:#ffffff24;--wui-color-glass-border:#ffffff0d;--wui-color-glass-highlight:#ffffff1a;--wui-color-glass-corner:#fff3;--wui-color-glass-shade:#00000080;--wui-glass-brightness:1.02;--wui-color-accent:#0a84ff;--wui-color-on-accent:#fff;--wui-color-on-control:#f2f2f7;--wui-color-success:#30d158;--wui-color-warning:#ff9f0a;--wui-color-danger:#ff453a;--wui-color-info:#64d2ff;--wui-color-backdrop:#0000007a;--wui-shadow-overlay:0 18px 48px #0000007a;--wui-shadow-panel:0 4px 16px #00000052;--wui-shadow-glass:0 8px 24px #00000014;--wui-color-focus-ring:#0a84ff9e;--lightningcss-light: ;--lightningcss-dark:initial;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{--wui-font-size:14px;--wui-input-width:200px;--wui-control-size:36px;--wui-overlay-min-width:200px;--wui-layer-base:0;--wui-layer-inline-overlay:1;--wui-layer-header:10;--wui-layer-auxiliary:20;--wui-layer-banner:30;--wui-layer-tabbar:40;--wui-layer-sidebar:50;--wui-layer-menu:100;--wui-layer-menu-nested:110;--wui-layer-toast:200;--wui-layer-loading:300;--wui-duration-press:80ms;--wui-duration-feedback:.1s;--wui-duration-trigger:.16s;--wui-duration-focus:.2s;--wui-duration-float-enter:.24s;--wui-duration-float-exit:.16s;--wui-duration-dialog-enter:.32s;--wui-duration-dialog-exit:.26s;--wui-duration-drawer-enter:.28s;--wui-duration-drawer-exit:.24s;--wui-duration-drawer-nested:.45s;--wui-duration-toast-enter:.28s;--wui-duration-toast-exit:.2s;--wui-duration-collapse-enter:.2s;--wui-duration-collapse-exit:.16s;--wui-duration-layout:.2s;--wui-duration-swipe-settle:.22s;--wui-duration-spin:.6s;--wui-duration-spinner:.8s;--wui-ease-enter:cubic-bezier(.23, 1, .32, 1);--wui-ease-dialog:cubic-bezier(.2, 0, 0, 1);--wui-ease-slide:cubic-bezier(.77, 0, .175, 1);--wui-ease-swipe:cubic-bezier(.32, .72, 0, 1);--wui-ease-float:cubic-bezier(.4, .38, .2, 1);--wui-scale-enter:.95;--wui-dialog-scale-enter:1.2;--wui-focus-ring-width:3px;--wui-radius-control:calc(infinity * 1px);--wui-radius-menu:18px;--wui-radius-overlay:28px;display:contents}:host([motion=reduced]){--wui-duration-press:0s;--wui-duration-feedback:0s;--wui-duration-trigger:0s;--wui-duration-focus:0s;--wui-duration-float-enter:0s;--wui-duration-float-exit:0s;--wui-duration-dialog-enter:0s;--wui-duration-dialog-exit:0s;--wui-duration-drawer-enter:0s;--wui-duration-drawer-exit:0s;--wui-duration-drawer-nested:0s;--wui-duration-toast-enter:0s;--wui-duration-toast-exit:0s;--wui-duration-collapse-enter:0s;--wui-duration-collapse-exit:0s;--wui-duration-layout:0s;--wui-duration-swipe-settle:0s;--wui-duration-spin:1.6s;--wui-duration-spinner:1.6s;--wui-scale-enter:1;--wui-dialog-scale-enter:1}@media (prefers-reduced-motion:reduce){:host([motion=system]){--wui-duration-press:0s;--wui-duration-feedback:0s;--wui-duration-trigger:0s;--wui-duration-focus:0s;--wui-duration-float-enter:0s;--wui-duration-float-exit:0s;--wui-duration-dialog-enter:0s;--wui-duration-dialog-exit:0s;--wui-duration-drawer-enter:0s;--wui-duration-drawer-exit:0s;--wui-duration-drawer-nested:0s;--wui-duration-toast-enter:0s;--wui-duration-toast-exit:0s;--wui-duration-collapse-enter:0s;--wui-duration-collapse-exit:0s;--wui-duration-layout:0s;--wui-duration-swipe-settle:0s;--wui-duration-spin:1.6s;--wui-duration-spinner:1.6s;--wui-scale-enter:1;--wui-dialog-scale-enter:1}}:host([appearance=light]),:host([appearance=system]){--wui-color-page:#fff;--wui-color-surface:#fff;--wui-color-surface-raised:#f2f2f7;--wui-color-surface-control:#dfdfdf;--wui-color-surface-track:#e5e5ea;--wui-color-surface-menu:#f6f6f6d1;--wui-color-surface-glass:#fafafa57;--wui-color-surface-glass-hover:color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));--wui-color-surface-glass-active:color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));--wui-color-surface-overlay:#f6f6f6d1;--wui-color-surface-segmented:#e5e5ea;--wui-color-surface-selected:#fff;--wui-color-text:#1b1b1b;--wui-color-text-secondary:#6a6a6a;--wui-color-text-tertiary:color-mix(in srgb, var(--wui-color-text) 35%, transparent);--wui-color-text-disabled:color-mix(in srgb, var(--wui-color-text) 32%, transparent);--wui-color-state-layer-hover:color-mix(in srgb, var(--wui-color-text) 6%, transparent);--wui-color-state-layer-active:color-mix(in srgb, var(--wui-color-text) 15%, transparent);--wui-color-border:#0000001a;--wui-color-glass-border:transparent;--wui-color-glass-highlight:#ffffffe6;--wui-color-glass-corner:#ffffff14;--wui-color-glass-shade:#0000000f;--wui-glass-brightness:1.06;--wui-color-accent:#08f;--wui-color-on-accent:#fff;--wui-color-on-control:#fff;--wui-color-success:#16a34a;--wui-color-warning:#d97706;--wui-color-danger:#dc2626;--wui-color-info:#2563eb;--wui-color-backdrop:#0000001f;--wui-shadow-overlay:2px 16px 40px #0006;--wui-shadow-panel:0 3px 9px #00000045;--wui-shadow-glass:0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004;--wui-color-focus-ring:#08f6;--lightningcss-light:initial;--lightningcss-dark: ;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:host([appearance=dark]){--wui-color-page:#242628;--wui-color-surface:#2c2c2e;--wui-color-surface-raised:#2c2c2e;--wui-color-surface-control:#3a3a3c;--wui-color-surface-track:#444446;--wui-color-surface-menu:#1e1e20eb;--wui-color-surface-glass:#2c2c2e6b;--wui-color-surface-glass-hover:color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));--wui-color-surface-glass-active:color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));--wui-color-surface-overlay:#202222e6;--wui-color-surface-segmented:#3a3a3c;--wui-color-surface-selected:#5c5c5e;--wui-color-text:#e9eaea;--wui-color-text-secondary:#a1a1a6;--wui-color-text-tertiary:color-mix(in srgb, var(--wui-color-text) 42%, transparent);--wui-color-text-disabled:color-mix(in srgb, var(--wui-color-text) 38%, transparent);--wui-color-state-layer-hover:color-mix(in srgb, var(--wui-color-text) 6%, transparent);--wui-color-state-layer-active:color-mix(in srgb, var(--wui-color-text) 15%, transparent);--wui-color-border:#ffffff24;--wui-color-glass-border:#ffffff0d;--wui-color-glass-highlight:#ffffff1a;--wui-color-glass-corner:#fff3;--wui-color-glass-shade:#00000080;--wui-glass-brightness:1.02;--wui-color-accent:#0a84ff;--wui-color-on-accent:#fff;--wui-color-on-control:#f2f2f7;--wui-color-success:#30d158;--wui-color-warning:#ff9f0a;--wui-color-danger:#ff453a;--wui-color-info:#64d2ff;--wui-color-backdrop:#0000007a;--wui-shadow-overlay:0 18px 48px #0000007a;--wui-shadow-panel:0 4px 16px #00000052;--wui-shadow-glass:0 8px 24px #00000014;--wui-color-focus-ring:#0a84ff9e;--lightningcss-light: ;--lightningcss-dark:initial;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@media (prefers-color-scheme:dark){:host([appearance=system]){--wui-color-page:#242628;--wui-color-surface:#2c2c2e;--wui-color-surface-raised:#2c2c2e;--wui-color-surface-control:#3a3a3c;--wui-color-surface-track:#444446;--wui-color-surface-menu:#1e1e20eb;--wui-color-surface-glass:#2c2c2e6b;--wui-color-surface-glass-hover:color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));--wui-color-surface-glass-active:color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));--wui-color-surface-overlay:#202222e6;--wui-color-surface-segmented:#3a3a3c;--wui-color-surface-selected:#5c5c5e;--wui-color-text:#e9eaea;--wui-color-text-secondary:#a1a1a6;--wui-color-text-tertiary:color-mix(in srgb, var(--wui-color-text) 42%, transparent);--wui-color-text-disabled:color-mix(in srgb, var(--wui-color-text) 38%, transparent);--wui-color-state-layer-hover:color-mix(in srgb, var(--wui-color-text) 6%, transparent);--wui-color-state-layer-active:color-mix(in srgb, var(--wui-color-text) 15%, transparent);--wui-color-border:#ffffff24;--wui-color-glass-border:#ffffff0d;--wui-color-glass-highlight:#ffffff1a;--wui-color-glass-corner:#fff3;--wui-color-glass-shade:#00000080;--wui-glass-brightness:1.02;--wui-color-accent:#0a84ff;--wui-color-on-accent:#fff;--wui-color-on-control:#f2f2f7;--wui-color-success:#30d158;--wui-color-warning:#ff9f0a;--wui-color-danger:#ff453a;--wui-color-info:#64d2ff;--wui-color-backdrop:#0000007a;--wui-shadow-overlay:0 18px 48px #0000007a;--wui-shadow-panel:0 4px 16px #00000052;--wui-shadow-glass:0 8px 24px #00000014;--wui-color-focus-ring:#0a84ff9e;--lightningcss-light: ;--lightningcss-dark:initial;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/theme/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-font-size: 14px;\n --wui-input-width: 200px;\n --wui-control-size: 36px;\n --wui-overlay-min-width: 200px;\n\n /* z-index layers - 基础结构 */\n --wui-layer-base: 0;\n --wui-layer-inline-overlay: 1;\n --wui-layer-header: 10;\n --wui-layer-auxiliary: 20;\n --wui-layer-banner: 30;\n --wui-layer-tabbar: 40;\n --wui-layer-sidebar: 50;\n\n /* z-index layers - 浮层 */\n --wui-layer-menu: 100;\n --wui-layer-menu-nested: 110;\n --wui-layer-toast: 200;\n --wui-layer-loading: 300;\n --wui-duration-press: 80ms;\n --wui-duration-feedback: 100ms;\n --wui-duration-trigger: 160ms;\n --wui-duration-focus: 200ms;\n --wui-duration-float-enter: 160ms;\n --wui-duration-float-exit: 120ms;\n --wui-duration-dialog-enter: 320ms;\n --wui-duration-dialog-exit: 260ms;\n --wui-duration-drawer-enter: 280ms;\n --wui-duration-drawer-exit: 240ms;\n --wui-duration-drawer-nested: 450ms;\n --wui-duration-toast-enter: 280ms;\n --wui-duration-toast-exit: 200ms;\n --wui-duration-collapse-enter: 200ms;\n --wui-duration-collapse-exit: 160ms;\n --wui-duration-layout: 200ms;\n --wui-ease-enter: cubic-bezier(0.23, 1, 0.32, 1);\n --wui-ease-dialog: cubic-bezier(0.2, 0, 0, 1);\n --wui-ease-slide: cubic-bezier(0.77, 0, 0.175, 1);\n --wui-scale-enter: 0.97;\n --wui-focus-ring-width: 3px;\n\n /* control=胶囊控件、menu=浮动菜单面板、overlay=大型覆盖层卡片 */\n --wui-radius-control: calc(infinity * 1px);\n --wui-radius-menu: 18px;\n --wui-radius-overlay: 28px;\n\n /* contents:主题宿主不生成盒、不绘制页面背景,嵌入方保留对宿主背景的完全控制\n (组件库不在宿主页面画背景)。自定义属性仍沿 DOM 树正常继承到 slotted 内容。 */\n display: contents;\n}\n\n:host([motion='reduced']) {\n --wui-duration-press: 0ms;\n --wui-duration-feedback: 0ms;\n --wui-duration-trigger: 0ms;\n --wui-duration-focus: 0ms;\n --wui-duration-float-enter: 0ms;\n --wui-duration-float-exit: 0ms;\n --wui-duration-dialog-enter: 0ms;\n --wui-duration-dialog-exit: 0ms;\n --wui-duration-drawer-enter: 0ms;\n --wui-duration-drawer-exit: 0ms;\n --wui-duration-drawer-nested: 0ms;\n --wui-duration-toast-enter: 0ms;\n --wui-duration-toast-exit: 0ms;\n --wui-duration-collapse-enter: 0ms;\n --wui-duration-collapse-exit: 0ms;\n --wui-duration-layout: 0ms;\n --wui-scale-enter: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([motion='system']) {\n --wui-duration-press: 0ms;\n --wui-duration-feedback: 0ms;\n --wui-duration-trigger: 0ms;\n --wui-duration-focus: 0ms;\n --wui-duration-float-enter: 0ms;\n --wui-duration-float-exit: 0ms;\n --wui-duration-dialog-enter: 0ms;\n --wui-duration-dialog-exit: 0ms;\n --wui-duration-drawer-enter: 0ms;\n --wui-duration-drawer-exit: 0ms;\n --wui-duration-drawer-nested: 0ms;\n --wui-duration-toast-enter: 0ms;\n --wui-duration-toast-exit: 0ms;\n --wui-duration-collapse-enter: 0ms;\n --wui-duration-collapse-exit: 0ms;\n --wui-duration-layout: 0ms;\n --wui-scale-enter: 1;\n }\n}\n\n:host([appearance='light']),\n:host([appearance='system']) {\n --wui-color-page: #fff;\n --wui-color-surface: #fff;\n --wui-color-surface-raised: #f2f2f7;\n --wui-color-surface-control: #dfdfdf;\n --wui-color-surface-track: #e5e5ea;\n --wui-color-surface-menu: rgb(246 246 246 / 0.82);\n --wui-color-surface-glass: rgb(250 250 250 / 0.34);\n --wui-color-surface-glass-hover: color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));\n --wui-color-surface-glass-active: color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));\n --wui-color-surface-overlay: rgb(246 246 246 / 0.82);\n --wui-color-surface-segmented: #e5e5ea;\n --wui-color-surface-selected: #fff;\n --wui-color-text: #1b1b1b;\n --wui-color-text-secondary: #6a6a6a;\n --wui-color-text-tertiary: color-mix(in srgb, var(--wui-color-text) 35%, transparent);\n --wui-color-text-disabled: color-mix(in srgb, var(--wui-color-text) 32%, transparent);\n --wui-color-state-layer-hover: color-mix(in srgb, var(--wui-color-text) 6%, transparent);\n --wui-color-state-layer-active: color-mix(in srgb, var(--wui-color-text) 15%, transparent);\n --wui-color-border: rgb(0 0 0 / 0.1);\n --wui-color-glass-border: transparent;\n --wui-color-glass-highlight: rgb(255 255 255 / 0.9);\n --wui-color-glass-corner: rgb(255 255 255 / 0.08);\n --wui-color-glass-shade: rgb(0 0 0 / 0.06);\n --wui-glass-brightness: 1.06;\n --wui-color-accent: #08f;\n --wui-color-on-accent: #fff;\n --wui-color-on-control: #fff;\n --wui-color-success: #16a34a;\n --wui-color-warning: #d97706;\n --wui-color-danger: #dc2626;\n --wui-color-info: #2563eb;\n --wui-color-backdrop: rgb(0 0 0 / 0.12);\n --wui-shadow-overlay: 2px 16px 40px rgb(0 0 0 / 0.4);\n --wui-shadow-panel: 0 3px 9px rgb(0 0 0 / 0.27);\n --wui-shadow-glass:\n 0 0 1px rgb(0 0 0 / 0.05), 0 0 8px rgb(0 0 0 / 0.03), 0 2px 16px rgb(0 0 0 / 0.025), 0 8px 32px rgb(0 0 0 / 0.015);\n --wui-color-focus-ring: rgb(0 136 255 / 0.4);\n color-scheme: light;\n}\n\n:host([appearance='dark']) {\n --wui-color-page: #242628;\n --wui-color-surface: #2c2c2e;\n --wui-color-surface-raised: #2c2c2e;\n --wui-color-surface-control: #3a3a3c;\n --wui-color-surface-track: #444446;\n --wui-color-surface-menu: rgb(30 30 32 / 0.92);\n --wui-color-surface-glass: rgb(44 44 46 / 0.42);\n --wui-color-surface-glass-hover: color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));\n --wui-color-surface-glass-active: color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));\n --wui-color-surface-overlay: rgb(32 34 34 / 0.9);\n --wui-color-surface-segmented: #3a3a3c;\n --wui-color-surface-selected: #5c5c5e;\n --wui-color-text: #e9eaea;\n --wui-color-text-secondary: #a1a1a6;\n --wui-color-text-tertiary: color-mix(in srgb, var(--wui-color-text) 42%, transparent);\n --wui-color-text-disabled: color-mix(in srgb, var(--wui-color-text) 38%, transparent);\n --wui-color-state-layer-hover: color-mix(in srgb, var(--wui-color-text) 6%, transparent);\n --wui-color-state-layer-active: color-mix(in srgb, var(--wui-color-text) 15%, transparent);\n --wui-color-border: rgb(255 255 255 / 0.14);\n --wui-color-glass-border: rgb(255 255 255 / 0.05);\n --wui-color-glass-highlight: rgb(255 255 255 / 0.1);\n --wui-color-glass-corner: rgb(255 255 255 / 0.2);\n --wui-color-glass-shade: rgb(0 0 0 / 0.5);\n --wui-glass-brightness: 1.02;\n --wui-color-accent: #0a84ff;\n --wui-color-on-accent: #fff;\n --wui-color-on-control: #f2f2f7;\n --wui-color-success: #30d158;\n --wui-color-warning: #ff9f0a;\n --wui-color-danger: #ff453a;\n --wui-color-info: #64d2ff;\n --wui-color-backdrop: rgb(0 0 0 / 0.48);\n --wui-shadow-overlay: 0 18px 48px rgb(0 0 0 / 0.48);\n --wui-shadow-panel: 0 4px 16px rgb(0 0 0 / 0.32);\n --wui-shadow-glass: 0 8px 24px rgb(0 0 0 / 0.08);\n --wui-color-focus-ring: rgb(10 132 255 / 0.62);\n color-scheme: dark;\n}\n\n@media (prefers-color-scheme: dark) {\n :host([appearance='system']) {\n --wui-color-page: #242628;\n --wui-color-surface: #2c2c2e;\n --wui-color-surface-raised: #2c2c2e;\n --wui-color-surface-control: #3a3a3c;\n --wui-color-surface-track: #444446;\n --wui-color-surface-menu: rgb(30 30 32 / 0.92);\n --wui-color-surface-glass: rgb(44 44 46 / 0.42);\n --wui-color-surface-glass-hover: color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));\n --wui-color-surface-glass-active: color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));\n --wui-color-surface-overlay: rgb(32 34 34 / 0.9);\n --wui-color-surface-segmented: #3a3a3c;\n --wui-color-surface-selected: #5c5c5e;\n --wui-color-text: #e9eaea;\n --wui-color-text-secondary: #a1a1a6;\n --wui-color-text-tertiary: color-mix(in srgb, var(--wui-color-text) 42%, transparent);\n --wui-color-text-disabled: color-mix(in srgb, var(--wui-color-text) 38%, transparent);\n --wui-color-state-layer-hover: color-mix(in srgb, var(--wui-color-text) 6%, transparent);\n --wui-color-state-layer-active: color-mix(in srgb, var(--wui-color-text) 15%, transparent);\n --wui-color-border: rgb(255 255 255 / 0.14);\n --wui-color-glass-border: rgb(255 255 255 / 0.05);\n --wui-color-glass-highlight: rgb(255 255 255 / 0.1);\n --wui-color-glass-corner: rgb(255 255 255 / 0.2);\n --wui-color-glass-shade: rgb(0 0 0 / 0.5);\n --wui-glass-brightness: 1.02;\n --wui-color-accent: #0a84ff;\n --wui-color-on-accent: #fff;\n --wui-color-on-control: #f2f2f7;\n --wui-color-success: #30d158;\n --wui-color-warning: #ff9f0a;\n --wui-color-danger: #ff453a;\n --wui-color-info: #64d2ff;\n --wui-color-backdrop: rgb(0 0 0 / 0.48);\n --wui-shadow-overlay: 0 18px 48px rgb(0 0 0 / 0.48);\n --wui-shadow-panel: 0 4px 16px rgb(0 0 0 / 0.32);\n --wui-shadow-glass: 0 8px 24px rgb(0 0 0 / 0.08);\n --wui-color-focus-ring: rgb(10 132 255 / 0.62);\n color-scheme: dark;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/theme/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-font-size: 14px;\n --wui-input-width: 200px;\n --wui-control-size: 36px;\n --wui-overlay-min-width: 200px;\n\n /* z-index layers - 基础结构 */\n --wui-layer-base: 0;\n --wui-layer-inline-overlay: 1;\n --wui-layer-header: 10;\n --wui-layer-auxiliary: 20;\n --wui-layer-banner: 30;\n --wui-layer-tabbar: 40;\n --wui-layer-sidebar: 50;\n\n /* z-index layers - 浮层 */\n --wui-layer-menu: 100;\n --wui-layer-menu-nested: 110;\n --wui-layer-toast: 200;\n --wui-layer-loading: 300;\n --wui-duration-press: 80ms;\n --wui-duration-feedback: 100ms;\n --wui-duration-trigger: 160ms;\n --wui-duration-focus: 200ms;\n\n /* 锚定浮动面板(menu/popover/select/dropdown/tooltip/autocomplete)的进场与退场时长,\n 出场快于入场。 */\n --wui-duration-float-enter: 240ms;\n --wui-duration-float-exit: 160ms;\n --wui-duration-dialog-enter: 320ms;\n --wui-duration-dialog-exit: 260ms;\n --wui-duration-drawer-enter: 280ms;\n --wui-duration-drawer-exit: 240ms;\n --wui-duration-drawer-nested: 450ms;\n --wui-duration-toast-enter: 280ms;\n --wui-duration-toast-exit: 200ms;\n --wui-duration-collapse-enter: 200ms;\n --wui-duration-collapse-exit: 160ms;\n --wui-duration-layout: 200ms;\n\n /* image-preview 轮播回位:跟手结束后把轨道过渡到目标位。不属于进出场族,故单独成 token。 */\n --wui-duration-swipe-settle: 220ms;\n\n /* 无限循环的加载指示:icon 旋转与 spinner 叶片追光。周期属于动画自身而非转场,\n 但同样受 motion 契约约束,reduce 下只放慢不停。 */\n --wui-duration-spin: 600ms;\n --wui-duration-spinner: 800ms;\n\n --wui-ease-enter: cubic-bezier(0.23, 1, 0.32, 1);\n --wui-ease-dialog: cubic-bezier(0.2, 0, 0, 1);\n --wui-ease-slide: cubic-bezier(0.77, 0, 0.175, 1);\n\n /* 轮播回位的缓动:起步快、末段极慢,与 --wui-ease-slide(整卡位移)区分开。 */\n --wui-ease-swipe: cubic-bezier(0.32, 0.72, 0, 1);\n\n /* 锚定浮动面板专属进场缓动,无回弹弹簧拟合曲线。若改用 --wui-ease-enter,\n 开局 30% 的时间就走完 85% 进度,观感是先弹出再落位。 */\n --wui-ease-float: cubic-bezier(0.4, 0.38, 0.2, 1);\n\n /* 进场缩放起点。两族方向相反,各自成 token:浮动面板与 image-preview 由小到大展开\n (0.95 → 1),dialog 由大到小收缩(1.2 → 1,退场反向)。\n 方向由承载层决定。image-preview 是满视口表面,起点 >1 会把贴边的 counter/close/\n toolbar 推出视口并裁掉图片四边,只能留在 <1 的档位。dialog 是有界卡片,起点 1.2 只\n 在视口窄于 432px 时越界,且缩放与卡片 opacity 共用 --wui-ease-dialog,越界期间卡片\n 不透明度始终 ≤44.4%;要零越界而不是取满 1.2,把本 token 降到 1.111 即可。 */\n --wui-scale-enter: 0.95;\n --wui-dialog-scale-enter: 1.2;\n --wui-focus-ring-width: 3px;\n\n /* control=胶囊控件、menu=浮动菜单面板、overlay=大型覆盖层卡片 */\n --wui-radius-control: calc(infinity * 1px);\n --wui-radius-menu: 18px;\n --wui-radius-overlay: 28px;\n\n /* contents:主题宿主不生成盒、不绘制页面背景,嵌入方保留对宿主背景的完全控制\n (组件库不在宿主页面画背景)。自定义属性仍沿 DOM 树正常继承到 slotted 内容。 */\n display: contents;\n}\n\n:host([motion='reduced']) {\n --wui-duration-press: 0ms;\n --wui-duration-feedback: 0ms;\n --wui-duration-trigger: 0ms;\n --wui-duration-focus: 0ms;\n --wui-duration-float-enter: 0ms;\n --wui-duration-float-exit: 0ms;\n --wui-duration-dialog-enter: 0ms;\n --wui-duration-dialog-exit: 0ms;\n --wui-duration-drawer-enter: 0ms;\n --wui-duration-drawer-exit: 0ms;\n --wui-duration-drawer-nested: 0ms;\n --wui-duration-toast-enter: 0ms;\n --wui-duration-toast-exit: 0ms;\n --wui-duration-collapse-enter: 0ms;\n --wui-duration-collapse-exit: 0ms;\n --wui-duration-layout: 0ms;\n --wui-duration-swipe-settle: 0ms;\n\n /* 加载循环不在 reduce 下归零:它是「正在进行」的唯一信号,停掉会被读成界面卡死,只放慢。 */\n --wui-duration-spin: 1600ms;\n --wui-duration-spinner: 1600ms;\n\n --wui-scale-enter: 1;\n --wui-dialog-scale-enter: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([motion='system']) {\n --wui-duration-press: 0ms;\n --wui-duration-feedback: 0ms;\n --wui-duration-trigger: 0ms;\n --wui-duration-focus: 0ms;\n --wui-duration-float-enter: 0ms;\n --wui-duration-float-exit: 0ms;\n --wui-duration-dialog-enter: 0ms;\n --wui-duration-dialog-exit: 0ms;\n --wui-duration-drawer-enter: 0ms;\n --wui-duration-drawer-exit: 0ms;\n --wui-duration-drawer-nested: 0ms;\n --wui-duration-toast-enter: 0ms;\n --wui-duration-toast-exit: 0ms;\n --wui-duration-collapse-enter: 0ms;\n --wui-duration-collapse-exit: 0ms;\n --wui-duration-layout: 0ms;\n --wui-duration-swipe-settle: 0ms;\n\n /* 加载循环不在 reduce 下归零:它是「正在进行」的唯一信号,停掉会被读成界面卡死,只放慢。 */\n --wui-duration-spin: 1600ms;\n --wui-duration-spinner: 1600ms;\n\n --wui-scale-enter: 1;\n --wui-dialog-scale-enter: 1;\n }\n}\n\n:host([appearance='light']),\n:host([appearance='system']) {\n --wui-color-page: #fff;\n --wui-color-surface: #fff;\n --wui-color-surface-raised: #f2f2f7;\n --wui-color-surface-control: #dfdfdf;\n --wui-color-surface-track: #e5e5ea;\n --wui-color-surface-menu: rgb(246 246 246 / 0.82);\n --wui-color-surface-glass: rgb(250 250 250 / 0.34);\n --wui-color-surface-glass-hover: color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));\n --wui-color-surface-glass-active: color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));\n --wui-color-surface-overlay: rgb(246 246 246 / 0.82);\n --wui-color-surface-segmented: #e5e5ea;\n --wui-color-surface-selected: #fff;\n --wui-color-text: #1b1b1b;\n --wui-color-text-secondary: #6a6a6a;\n --wui-color-text-tertiary: color-mix(in srgb, var(--wui-color-text) 35%, transparent);\n --wui-color-text-disabled: color-mix(in srgb, var(--wui-color-text) 32%, transparent);\n --wui-color-state-layer-hover: color-mix(in srgb, var(--wui-color-text) 6%, transparent);\n --wui-color-state-layer-active: color-mix(in srgb, var(--wui-color-text) 15%, transparent);\n --wui-color-border: rgb(0 0 0 / 0.1);\n --wui-color-glass-border: transparent;\n --wui-color-glass-highlight: rgb(255 255 255 / 0.9);\n --wui-color-glass-corner: rgb(255 255 255 / 0.08);\n --wui-color-glass-shade: rgb(0 0 0 / 0.06);\n --wui-glass-brightness: 1.06;\n --wui-color-accent: #08f;\n --wui-color-on-accent: #fff;\n --wui-color-on-control: #fff;\n --wui-color-success: #16a34a;\n --wui-color-warning: #d97706;\n --wui-color-danger: #dc2626;\n --wui-color-info: #2563eb;\n --wui-color-backdrop: rgb(0 0 0 / 0.12);\n --wui-shadow-overlay: 2px 16px 40px rgb(0 0 0 / 0.4);\n --wui-shadow-panel: 0 3px 9px rgb(0 0 0 / 0.27);\n --wui-shadow-glass:\n 0 0 1px rgb(0 0 0 / 0.05), 0 0 8px rgb(0 0 0 / 0.03), 0 2px 16px rgb(0 0 0 / 0.025), 0 8px 32px rgb(0 0 0 / 0.015);\n --wui-color-focus-ring: rgb(0 136 255 / 0.4);\n color-scheme: light;\n}\n\n:host([appearance='dark']) {\n --wui-color-page: #242628;\n --wui-color-surface: #2c2c2e;\n --wui-color-surface-raised: #2c2c2e;\n --wui-color-surface-control: #3a3a3c;\n --wui-color-surface-track: #444446;\n --wui-color-surface-menu: rgb(30 30 32 / 0.92);\n --wui-color-surface-glass: rgb(44 44 46 / 0.42);\n --wui-color-surface-glass-hover: color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));\n --wui-color-surface-glass-active: color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));\n --wui-color-surface-overlay: rgb(32 34 34 / 0.9);\n --wui-color-surface-segmented: #3a3a3c;\n --wui-color-surface-selected: #5c5c5e;\n --wui-color-text: #e9eaea;\n --wui-color-text-secondary: #a1a1a6;\n --wui-color-text-tertiary: color-mix(in srgb, var(--wui-color-text) 42%, transparent);\n --wui-color-text-disabled: color-mix(in srgb, var(--wui-color-text) 38%, transparent);\n --wui-color-state-layer-hover: color-mix(in srgb, var(--wui-color-text) 6%, transparent);\n --wui-color-state-layer-active: color-mix(in srgb, var(--wui-color-text) 15%, transparent);\n --wui-color-border: rgb(255 255 255 / 0.14);\n --wui-color-glass-border: rgb(255 255 255 / 0.05);\n --wui-color-glass-highlight: rgb(255 255 255 / 0.1);\n --wui-color-glass-corner: rgb(255 255 255 / 0.2);\n --wui-color-glass-shade: rgb(0 0 0 / 0.5);\n --wui-glass-brightness: 1.02;\n --wui-color-accent: #0a84ff;\n --wui-color-on-accent: #fff;\n --wui-color-on-control: #f2f2f7;\n --wui-color-success: #30d158;\n --wui-color-warning: #ff9f0a;\n --wui-color-danger: #ff453a;\n --wui-color-info: #64d2ff;\n --wui-color-backdrop: rgb(0 0 0 / 0.48);\n --wui-shadow-overlay: 0 18px 48px rgb(0 0 0 / 0.48);\n --wui-shadow-panel: 0 4px 16px rgb(0 0 0 / 0.32);\n --wui-shadow-glass: 0 8px 24px rgb(0 0 0 / 0.08);\n --wui-color-focus-ring: rgb(10 132 255 / 0.62);\n color-scheme: dark;\n}\n\n@media (prefers-color-scheme: dark) {\n :host([appearance='system']) {\n --wui-color-page: #242628;\n --wui-color-surface: #2c2c2e;\n --wui-color-surface-raised: #2c2c2e;\n --wui-color-surface-control: #3a3a3c;\n --wui-color-surface-track: #444446;\n --wui-color-surface-menu: rgb(30 30 32 / 0.92);\n --wui-color-surface-glass: rgb(44 44 46 / 0.42);\n --wui-color-surface-glass-hover: color-mix(in srgb, var(--wui-color-text) 6%, var(--wui-color-surface-glass));\n --wui-color-surface-glass-active: color-mix(in srgb, var(--wui-color-text) 15%, var(--wui-color-surface-glass));\n --wui-color-surface-overlay: rgb(32 34 34 / 0.9);\n --wui-color-surface-segmented: #3a3a3c;\n --wui-color-surface-selected: #5c5c5e;\n --wui-color-text: #e9eaea;\n --wui-color-text-secondary: #a1a1a6;\n --wui-color-text-tertiary: color-mix(in srgb, var(--wui-color-text) 42%, transparent);\n --wui-color-text-disabled: color-mix(in srgb, var(--wui-color-text) 38%, transparent);\n --wui-color-state-layer-hover: color-mix(in srgb, var(--wui-color-text) 6%, transparent);\n --wui-color-state-layer-active: color-mix(in srgb, var(--wui-color-text) 15%, transparent);\n --wui-color-border: rgb(255 255 255 / 0.14);\n --wui-color-glass-border: rgb(255 255 255 / 0.05);\n --wui-color-glass-highlight: rgb(255 255 255 / 0.1);\n --wui-color-glass-corner: rgb(255 255 255 / 0.2);\n --wui-color-glass-shade: rgb(0 0 0 / 0.5);\n --wui-glass-brightness: 1.02;\n --wui-color-accent: #0a84ff;\n --wui-color-on-accent: #fff;\n --wui-color-on-control: #f2f2f7;\n --wui-color-success: #30d158;\n --wui-color-warning: #ff9f0a;\n --wui-color-danger: #ff453a;\n --wui-color-info: #64d2ff;\n --wui-color-backdrop: rgb(0 0 0 / 0.48);\n --wui-shadow-overlay: 0 18px 48px rgb(0 0 0 / 0.48);\n --wui-shadow-panel: 0 4px 16px rgb(0 0 0 / 0.32);\n --wui-shadow-glass: 0 8px 24px rgb(0 0 0 / 0.08);\n --wui-color-focus-ring: rgb(10 132 255 / 0.62);\n color-scheme: dark;\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/toast/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([hidden]){display:none}.toast{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:var(--wui-radius-menu,18px);transform:translate(var(--toast-slide-x,0), var(--toast-slide-y,-8px)) scale(.97);width:min(320px, calc(100dvw - 2 * var(--wui-toast-viewport-gap,16px)));border-radius:var(--wui-radius-menu,18px);min-height:36px;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);opacity:0;background-color:var(--wui-color-surface-overlay,#f6f6f6d1);-webkit-backdrop-filter:blur(0) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(0) saturate(160%) brightness(var(--wui-glass-brightness,1.06));transition:opacity var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), -webkit-backdrop-filter var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), backdrop-filter var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));gap:8px;padding:8px;line-height:1.5;display:flex;position:relative}:host([visible]) .toast{opacity:1;-webkit-backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));transform:translate(0)scale(1)}:host(:not([visible])) .toast{transition-duration:var(--wui-duration-toast-exit,.2s)}web-ui-button.toast-close-btn{pointer-events:none;cursor:default;opacity:0;transition:opacity var(--wui-duration-trigger,.16s) ease;position:absolute;top:-8px;right:-8px}web-ui-button.toast-close-btn:focus-within{pointer-events:auto;opacity:1}@media (hover:hover) and (pointer:fine){web-ui-button.toast-close-btn:hover,.toast:hover web-ui-button.toast-close-btn{pointer-events:auto;opacity:1}}.toast web-ui-button[icon]{--wui-button-color:var(--wui-color-text-secondary,#6a6a6a)}.toast-icon{border-radius:var(--wui-radius-control,calc(infinity * 1px));flex-shrink:0;justify-content:center;align-items:center;width:20px;height:20px;margin-bottom:auto;display:flex}.toast.success .toast-icon{color:var(--wui-color-success,#16a34a);background-color:color-mix(in srgb, var(--wui-color-success,#16a34a) 10%, transparent)}.toast.info .toast-icon{color:var(--wui-color-info,#2563eb);background-color:color-mix(in srgb, var(--wui-color-info,#2563eb) 10%, transparent)}.toast.warning .toast-icon{color:var(--wui-color-warning,#d97706);background-color:color-mix(in srgb, var(--wui-color-warning,#d97706) 10%, transparent)}.toast.error .toast-icon{color:var(--wui-color-danger,#dc2626);background-color:color-mix(in srgb, var(--wui-color-danger,#dc2626) 10%, transparent)}.toast-body{flex:1;min-width:0}.toast-heading{font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;font-weight:600;line-height:1.4;overflow:hidden}.toast-message{-webkit-line-clamp:3;font-size:calc(var(--wui-font-size,14px) - 1px);color:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 55%, transparent);word-break:break-all;-webkit-box-orient:vertical;line-height:1.4;display:-webkit-box;overflow:hidden}.toast-time{color:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 30%, transparent);white-space:nowrap;font-size:12px}@media (prefers-reduced-motion:reduce){.toast,:host([visible]) .toast{transition-duration:var(--wui-duration-feedback,.1s);transform:none}}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([hidden]){display:none}.toast{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:var(--wui-radius-menu,18px);transform:translate(var(--toast-slide-x,0), var(--toast-slide-y,-8px)) scale(var(--wui-scale-enter,.95));width:min(320px, calc(100dvw - 2 * var(--wui-toast-viewport-gap,16px)));border-radius:var(--wui-radius-menu,18px);min-height:36px;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);opacity:0;background-color:var(--wui-color-surface-overlay,#f6f6f6d1);-webkit-backdrop-filter:blur(0) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(0) saturate(160%) brightness(var(--wui-glass-brightness,1.06));transition:opacity var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), -webkit-backdrop-filter var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), backdrop-filter var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-duration-toast-enter,.28s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));gap:8px;padding:8px;line-height:1.5;display:flex;position:relative}:host([visible]) .toast{opacity:1;-webkit-backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));transform:translate(0)scale(1)}:host(:not([visible])) .toast{transition-duration:var(--wui-duration-toast-exit,.2s)}web-ui-button.toast-close-btn{pointer-events:none;cursor:default;opacity:0;transition:opacity var(--wui-duration-trigger,.16s) ease;position:absolute;top:-8px;right:-8px}web-ui-button.toast-close-btn:focus-within{pointer-events:auto;opacity:1}@media (hover:hover) and (pointer:fine){web-ui-button.toast-close-btn:hover,.toast:hover web-ui-button.toast-close-btn{pointer-events:auto;opacity:1}}.toast web-ui-button[icon]{--wui-button-color:var(--wui-color-text-secondary,#6a6a6a)}.toast-icon{border-radius:var(--wui-radius-control,calc(infinity * 1px));flex-shrink:0;justify-content:center;align-items:center;width:20px;height:20px;margin-bottom:auto;display:flex}.toast.success .toast-icon{color:var(--wui-color-success,#16a34a);background-color:color-mix(in srgb, var(--wui-color-success,#16a34a) 10%, transparent)}.toast.info .toast-icon{color:var(--wui-color-info,#2563eb);background-color:color-mix(in srgb, var(--wui-color-info,#2563eb) 10%, transparent)}.toast.warning .toast-icon{color:var(--wui-color-warning,#d97706);background-color:color-mix(in srgb, var(--wui-color-warning,#d97706) 10%, transparent)}.toast.error .toast-icon{color:var(--wui-color-danger,#dc2626);background-color:color-mix(in srgb, var(--wui-color-danger,#dc2626) 10%, transparent)}.toast-body{flex:1;min-width:0}.toast-heading{font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;font-weight:600;line-height:1.4;overflow:hidden}.toast-message{-webkit-line-clamp:3;font-size:calc(var(--wui-font-size,14px) - 1px);color:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 55%, transparent);word-break:break-all;-webkit-box-orient:vertical;line-height:1.4;display:-webkit-box;overflow:hidden}.toast-time{color:color-mix(in srgb, var(--wui-color-text,#1b1b1b) 30%, transparent);white-space:nowrap;font-size:12px}@media (prefers-reduced-motion:reduce){.toast,:host([visible]) .toast{transition-duration:var(--wui-duration-feedback,.1s);transform:none}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/toast/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n:host([hidden]) {\n display: none;\n}\n\n/* ===== 入场 / 退场动画 ===== */\n\n/* 单层玻璃:.toast 自身承担背景/阴影/backdrop-filter。blur(0px) ↔ blur(4px) 平滑\n 插值(none↔blur 不可插值才是当年生硬跳变的根因),own opacity 过渡不禁用自身\n blur,因此 toast 直接 opacity + backdrop-filter + transform 同步过渡,无需双层。 */\n.toast {\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 position: relative;\n transform: translate(var(--toast-slide-x, 0), var(--toast-slide-y, -8px)) scale(0.97);\n\n display: flex;\n gap: 8px;\n\n width: min(320px, calc(100dvw - 2 * var(--wui-toast-viewport-gap, 16px)));\n min-height: 36px;\n padding: 8px;\n border-radius: var(--wui-radius-menu, 18px);\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n\n opacity: 0;\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82));\n\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(0) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n backdrop-filter: blur(0) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n\n transition:\n opacity var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n -webkit-backdrop-filter var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n backdrop-filter var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n:host([visible]) .toast {\n transform: translate(0, 0) scale(1);\n opacity: 1;\n\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n}\n\n:host(:not([visible])) .toast {\n transition-duration: var(--wui-duration-toast-exit, 200ms);\n}\n\n/* ===== 关闭按钮(放在 hover 规则之前,避免 specificity 降序) ===== */\n\nweb-ui-button.toast-close-btn {\n pointer-events: none;\n cursor: default;\n\n position: absolute;\n top: -8px;\n right: -8px;\n\n opacity: 0;\n\n transition: opacity var(--wui-duration-trigger, 160ms) ease;\n\n /* 内层原生按钮获得键盘焦点时宿主同样可见 */\n &:focus-within {\n pointer-events: auto;\n opacity: 1;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n web-ui-button.toast-close-btn:hover,\n .toast:hover web-ui-button.toast-close-btn {\n pointer-events: auto;\n opacity: 1;\n }\n}\n\n/* secondary 变体默认用文本色,恢复原关闭按钮的 muted 观感 */\n.toast web-ui-button[icon] {\n --wui-button-color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\n/* ===== 图标 ===== */\n\n.toast-icon {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 20px;\n height: 20px;\n margin-bottom: auto;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n.toast.success .toast-icon {\n color: var(--wui-color-success, #16a34a);\n background-color: color-mix(in srgb, var(--wui-color-success, #16a34a) 10%, transparent);\n}\n\n.toast.info .toast-icon {\n color: var(--wui-color-info, #2563eb);\n background-color: color-mix(in srgb, var(--wui-color-info, #2563eb) 10%, transparent);\n}\n\n.toast.warning .toast-icon {\n color: var(--wui-color-warning, #d97706);\n background-color: color-mix(in srgb, var(--wui-color-warning, #d97706) 10%, transparent);\n}\n\n.toast.error .toast-icon {\n color: var(--wui-color-danger, #dc2626);\n background-color: color-mix(in srgb, var(--wui-color-danger, #dc2626) 10%, transparent);\n}\n\n/* ===== 内容区 ===== */\n\n.toast-body {\n flex: 1;\n min-width: 0;\n}\n\n.toast-heading {\n overflow: hidden;\n\n font-size: var(--wui-font-size, 14px);\n font-weight: 600;\n line-height: 1.4;\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.toast-message {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 3;\n\n font-size: calc(var(--wui-font-size, 14px) - 1px);\n line-height: 1.4;\n color: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 55%, transparent);\n word-break: break-all;\n}\n\n/* ===== 时间戳 ===== */\n\n.toast-time {\n font-size: 12px;\n color: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 30%, transparent);\n white-space: nowrap;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .toast,\n :host([visible]) .toast {\n transform: none;\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/toast/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n:host([hidden]) {\n display: none;\n}\n\n/* ===== 入场 / 退场动画 ===== */\n\n/* 单层玻璃:.toast 自身承担背景/阴影/backdrop-filter。blur(0px) ↔ blur(4px) 平滑\n 插值(none↔blur 不可插值才是当年生硬跳变的根因),own opacity 过渡不禁用自身\n blur,因此 toast 直接 opacity + backdrop-filter + transform 同步过渡,无需双层。 */\n.toast {\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 position: relative;\n transform: translate(var(--toast-slide-x, 0), var(--toast-slide-y, -8px)) scale(var(--wui-scale-enter, 0.95));\n\n display: flex;\n gap: 8px;\n\n width: min(320px, calc(100dvw - 2 * var(--wui-toast-viewport-gap, 16px)));\n min-height: 36px;\n padding: 8px;\n border-radius: var(--wui-radius-menu, 18px);\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1.5;\n color: var(--wui-color-text, #1b1b1b);\n\n opacity: 0;\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82));\n backdrop-filter: blur(0) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n\n /* transition 列表需手写 -webkit-backdrop-filter:lightningcss 不会在 transition\n value 内追加 -webkit 项,iOS 16.4 上 blur 过渡依赖它(属性前缀会自动生成)。 */\n transition:\n opacity var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n -webkit-backdrop-filter var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n backdrop-filter var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-toast-enter, 280ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n:host([visible]) .toast {\n transform: translate(0, 0) scale(1);\n opacity: 1;\n backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n}\n\n:host(:not([visible])) .toast {\n transition-duration: var(--wui-duration-toast-exit, 200ms);\n}\n\n/* ===== 关闭按钮(放在 hover 规则之前,避免 specificity 降序) ===== */\n\nweb-ui-button.toast-close-btn {\n pointer-events: none;\n cursor: default;\n\n position: absolute;\n top: -8px;\n right: -8px;\n\n opacity: 0;\n\n transition: opacity var(--wui-duration-trigger, 160ms) ease;\n\n /* 内层原生按钮获得键盘焦点时宿主同样可见 */\n &:focus-within {\n pointer-events: auto;\n opacity: 1;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n web-ui-button.toast-close-btn:hover,\n .toast:hover web-ui-button.toast-close-btn {\n pointer-events: auto;\n opacity: 1;\n }\n}\n\n/* secondary 变体默认用文本色,恢复原关闭按钮的 muted 观感 */\n.toast web-ui-button[icon] {\n --wui-button-color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\n/* ===== 图标 ===== */\n\n.toast-icon {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n\n width: 20px;\n height: 20px;\n margin-bottom: auto;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n}\n\n.toast.success .toast-icon {\n color: var(--wui-color-success, #16a34a);\n background-color: color-mix(in srgb, var(--wui-color-success, #16a34a) 10%, transparent);\n}\n\n.toast.info .toast-icon {\n color: var(--wui-color-info, #2563eb);\n background-color: color-mix(in srgb, var(--wui-color-info, #2563eb) 10%, transparent);\n}\n\n.toast.warning .toast-icon {\n color: var(--wui-color-warning, #d97706);\n background-color: color-mix(in srgb, var(--wui-color-warning, #d97706) 10%, transparent);\n}\n\n.toast.error .toast-icon {\n color: var(--wui-color-danger, #dc2626);\n background-color: color-mix(in srgb, var(--wui-color-danger, #dc2626) 10%, transparent);\n}\n\n/* ===== 内容区 ===== */\n\n.toast-body {\n flex: 1;\n min-width: 0;\n}\n\n.toast-heading {\n overflow: hidden;\n\n font-size: var(--wui-font-size, 14px);\n font-weight: 600;\n line-height: 1.4;\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.toast-message {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 3;\n\n font-size: calc(var(--wui-font-size, 14px) - 1px);\n line-height: 1.4;\n color: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 55%, transparent);\n word-break: break-all;\n}\n\n/* ===== 时间戳 ===== */\n\n.toast-time {\n font-size: 12px;\n color: color-mix(in srgb, var(--wui-color-text, #1b1b1b) 30%, transparent);\n white-space: nowrap;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .toast,\n :host([visible]) .toast {\n transform: none;\n transition-duration: var(--wui-duration-feedback, 100ms);\n }\n}\n"],"mappings":""}
@@ -1,4 +1,4 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
3
  import t from "../../icons/generated/lucide-check.js";
4
4
  import n from "../../icons/generated/lucide-info.js";
@@ -1,4 +1,4 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
2
2
  import t from "../../assets/glass.js";
3
3
  import n from "../../assets/overlay-motion.js";
4
4
  import { normalizeLiteral as r, normalizeNumber as i } from "../../shared/normalize/index.js";
@@ -28,11 +28,14 @@ var _ = 0, v = class extends f {
28
28
  isPortal: () => this.portal,
29
29
  createPortal: () => this._createPortal()
30
30
  }), this._onPointerEnter = (e) => {
31
- e.pointerType !== "touch" && (this.disabled || (clearTimeout(this._hideTimer), this._showTimer = setTimeout(() => this._show(), _ > 0 ? 0 : this.showDelay)));
31
+ if (e.pointerType === "touch" || this.disabled) return;
32
+ clearTimeout(this._hideTimer);
33
+ let t = _ > 0;
34
+ this._showTimer = setTimeout(() => this._show(t), t ? 0 : this.showDelay);
32
35
  }, this._onPointerLeave = (e) => {
33
36
  e.pointerType !== "touch" && (this.disabled || (clearTimeout(this._showTimer), this._hideTimer = setTimeout(() => this._hide(), this.hideDelay)));
34
37
  }, this._onFocusIn = (e) => {
35
- this.disabled || !(e.target instanceof Element) || !e.target.matches(":focus-visible") || (clearTimeout(this._hideTimer), this._show(!0));
38
+ this.disabled || e.target instanceof Element && e.target.matches(":focus-visible") && (clearTimeout(this._hideTimer), this._show(!0));
36
39
  }, this._onFocusOut = () => {
37
40
  this.disabled || (clearTimeout(this._showTimer), this._hide());
38
41
  };
@@ -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 { defineOverlayLifecycle } from '@/shared/overlay/lifecycle'\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 private readonly _lifecycle = defineOverlayLifecycle().make({\n isConnected: () => this.isConnected,\n isOpen: () => this.open\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 })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._lifecycle.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 this._lifecycle.dispose()\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._lifecycle.invalidate()\n this._lifecycle.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._lifecycle.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 this._showTimer = setTimeout(() => this._show(), visibleTooltipCount > 0 ? 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 { defineOverlayLifecycle } from '@/shared/overlay/lifecycle'\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 private readonly _lifecycle = defineOverlayLifecycle().make({\n isConnected: () => this.isConnected,\n isOpen: () => this.open\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 })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._lifecycle.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 this._lifecycle.dispose()\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._lifecycle.invalidate()\n this._lifecycle.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._lifecycle.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":";;;;;;;;;;;;;;AAiBA,IAAI,IAAsB,GAGb,IAAN,cAA2B,EAAW;;EA4Jf,aAhJI,KAAA,aAAA,OAWX,KAAA,aAAA,KAWA,KAAA,aAAA,KAEkC,KAAA,WAAA,IAWrC,KAAA,UAAA,GAEoB,KAAA,UAAA,IAEa,KAAA,OAAA,IACE,KAAA,SAAA,IAKzB,KAAA,oBAAA,IACO,KAAA,kBAAA,IAAI,EAAqB,GAC7B,KAAA,uBAAA,IAED,KAAA,aAAA,EAAuB,CAAC,CAAC,KAAK;GAC1D,mBAAmB,KAAK;GACxB,cAAc,KAAK;EACrB,CAAC,GACyB,KAAA,SAAA,EAAoB,CAAC,CAAC,KAAK;GACnD,iBAAiB,KAAK,YAAY,cAA2B,kBAAkB,KAAK;GACpF,qBAAqB,KAAK,YAAY,cAA2B,gBAAgB,KAAK;GACtF,uBAAuB;IACrB,WAAW,KAAK;IAChB,QAAQ,KAAK;IACb,UAAU,KAAK,SAAS,UAAU;GACpC;GACA,gBAAgB,KAAK;GACrB,oBAAoB,KAAK,cAAc;EACzC,CAAC,GAyD0B,KAAA,mBAAA,MAAoB;GAE7C,IADI,EAAE,gBAAgB,WAClB,KAAK,UAAU;GACnB,aAAa,KAAK,UAAU;GAE5B,IAAM,IAAW,IAAsB;GACvC,KAAK,aAAa,iBAAiB,KAAK,MAAM,CAAQ,GAAG,IAAW,IAAI,KAAK,SAAS;EACxF,GAE2B,KAAA,mBAAA,MAAoB;GACzC,EAAE,gBAAgB,YAClB,KAAK,aACT,aAAa,KAAK,UAAU,GAC5B,KAAK,aAAa,iBAAiB,KAAK,MAAM,GAAG,KAAK,SAAS;EACjE,GAEsB,KAAA,cAAA,MAAsB;GACtC,KAAK,YACH,EAAM,kBAAkB,WAAa,EAAM,OAAO,QAAQ,gBAAgB,MAEhF,aAAa,KAAK,UAAU,GAC5B,KAAK,MAAM,EAAI;EACjB,GAE4B,KAAA,oBAAA;GACtB,KAAK,aACT,aAAa,KAAK,UAAU,GAC5B,KAAK,MAAM;EACb;;;EA/JyB,KAAA,SAAA;GAAC,EAAU,CAAK;GAAG,EAAU,CAAa;GAAG,EAAU,CAAK;EAAC;;CAEtF,IACI,YAAuB;EACzB,OAAO,KAAK;CACd;CACA,IAAI,UAAU,GAAW;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,aAAa,EAAiB,GAAG,GAAqB,KAAK,GAChE,KAAK,cAAc,aAAa,CAAG;CACrC;CAGA,IACI,YAAoB;EACtB,OAAO,KAAK;CACd;CACA,IAAI,UAAU,GAAW;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,aAAa,EAAgB,GAAG,GAAG,KAAM,GAAG,GACjD,KAAK,cAAc,aAAa,CAAG;CACrC;CAGA,IACI,YAAoB;EACtB,OAAO,KAAK;CACd;CACA,IAAI,UAAU,GAAW;EACvB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,aAAa,EAAgB,GAAG,GAAG,KAAM,GAAG,GACjD,KAAK,cAAc,aAAa,CAAG;CACrC;CAKA,IACI,SAAiB;EACnB,OAAO,KAAK;CACd;CACA,IAAI,OAAO,GAAW;EACpB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,UAAU,EAAgB,GAAG,GAAG,KAAK,CAAC,GAC3C,KAAK,cAAc,UAAU,CAAG;CAClC;CA+BA,IAAI,SAAkB;EACpB,OAAO,KAAK;CACd;CAEA,oBAA6B;EAM3B,AALA,MAAM,kBAAkB,GACxB,KAAK,WAAW,OAAO,GACvB,KAAK,iBAAiB,gBAAgB,KAAK,eAAe,GAC1D,KAAK,iBAAiB,gBAAgB,KAAK,eAAe,GAC1D,KAAK,iBAAiB,WAAW,KAAK,UAAU,GAChD,KAAK,iBAAiB,YAAY,KAAK,WAAW;CACpD;CAEA,uBAAgC;EAU9B,AATA,MAAM,qBAAqB,GAC3B,KAAK,oBAAoB,gBAAgB,KAAK,eAAe,GAC7D,KAAK,oBAAoB,gBAAgB,KAAK,eAAe,GAC7D,KAAK,oBAAoB,WAAW,KAAK,UAAU,GACnD,KAAK,oBAAoB,YAAY,KAAK,WAAW,GACrD,aAAa,KAAK,UAAU,GAC5B,aAAa,KAAK,UAAU,GAC5B,KAAK,WAAW,QAAQ,GACxB,KAAK,yBAAyB,EAAK,GACnC,KAAK,OAAO,QAAQ;CACtB;CAEA,eAAwB;EACtB,AAAI,KAAK,SACP,KAAK,aAAa,KAAK,oBAAoB,GAC3C,KAAK,uBAAuB;CAEhC;CAEA,QAA2B,GAA+B;EAmBxD,AAlBI,EAAQ,IAAI,QAAQ,KAAK,EAAQ,IAAI,kBAAkB,KAEzD,KAAK,WAAW,WAAW,GAC3B,KAAK,WAAW,oBAAoB,KAAK,oBAAoB,CAAC,MACrD,EAAQ,IAAI,WAAW,KAAK,EAAQ,IAAI,QAAQ,MACzD,4BAA4B,KAAK,OAAO,eAAe,CAAC,GAEtD,EAAQ,IAAI,MAAM,MACpB,KAAK,yBAAyB,KAAK,IAAI,GACnC,KAAK,QACP,KAAK,aAAa,KAAK,oBAAoB,GAC3C,KAAK,uBAAuB,OAE5B,KAAK,WAAW,WAAW,GAC3B,KAAU,cAAc,IAEtB,KAAK,gBAAgB,QAAQ,KAAG,KAAK,gBAAgB,KAAK,IAAI,IAEhE,EAAQ,IAAI,SAAS,KAAG,KAAK,mBAAmB;CACtD;CAgCA,MAAc,IAAY,IAAO;EAC3B,AAGJ,KAAK,UAFL,KAAK,uBAAuB,GAC5B,KAAK,gBAAgB,KAAK,GACd;CACd;CAEA,QAAgB;EACT,AAEL,KAAK,UADL,KAAK,gBAAgB,KAAK,GACd;CACd;CAEA,aAAqB,IAAY,IAAO;EACtC,KAAK,OAAO,KAAK,CAAS;CAC5B;CAEA,gBAAuC;EACrC,IAAM,IAAS,EAAoB,CAAC,CAAC,KAAK;GACxC,WAAW,KAAK;GAChB,QAAQ;GACR,OAAO,GAAG,EAAM,IAAI,EAAc,IAAI;GACtC,WAAW;GAIX,oBAAmB,MACjB,EAAW,QAAO,MAAQ,aAAgB,WAAW,EAAK,aAAa,MAAM,MAAM,SAAS;EAChG,CAAC;EAED,IADA,KAAK,UAAU,GACX,KAAK,SAAS;GAChB,IAAM,IAAO,SAAS,cAAc,MAAM;GAG1C,AAFA,EAAK,YAAY,gBACjB,EAAK,cAAc,KAAK,SACxB,EAAO,MAAM,OAAO,CAAI;EAC1B,OAAO,EAAO,YAAY,MAAM,KAAK,KAAK,iBAAiB,oBAAkB,CAAC,CAAC;EAE/E,OADA,EAAO,MAAM,aAAa,QAAQ,SAAS,GACpC;CACT;CAEA,MAAc,gBAAgB;EAC5B,MAAM,KAAK,OAAO,YAAY,KAAK,IAAI;CACzC;CAEA,sBAA8B;EAC5B,KAAK,OAAO,YAAY,KAAK,IAAI;CACnC;CAEA,qBAA6B;EAC3B,IAAI,CAAC,KAAK,UAAU,CAAC,KAAK,MAAM;EAChC,IAAM,IAAa,KAAK,OAAO,SAAS;EACxC,IAAI,CAAC,GAAY;EACjB,IAAM,IAAQ,KAAK,SAAS,SAAS,GAC/B,IAAO,EAAW,cAA2B,eAAe;EAClE,IAAI,GAAM;GACR,EAAK,cAAc,KAAK;GACxB;EACF;EACA,IAAI,CAAC,KAAK,SAAS;EACnB,EAAM,gBAAgB;EACtB,IAAM,IAAW,SAAS,cAAc,MAAM;EAG9C,AAFA,EAAS,YAAY,gBACrB,EAAS,cAAc,KAAK,SAC5B,EAAM,OAAO,CAAQ;CACvB;CAEA,gBAAwB,GAAe;EACrC,EAAwB,MAAM,CAAI;CACpC;CAEA,yBAAiC,GAAoB;EACnD,AAAI,KAAa,CAAC,KAAK,qBACrB,KAAuB,GACvB,KAAK,oBAAoB,MAChB,CAAC,KAAa,KAAK,sBAC5B,IAAsB,KAAK,IAAI,GAAG,IAAsB,CAAC,GACzD,KAAK,oBAAoB;CAE7B;CAEA,SAAkB;EAChB,OAAO,CAAI;;;;YAIH,KAAK,UAAU,CAAI,8BAA8B,KAAK,QAAQ,WAAW,CAAI,+BAA+B;;;;CAItH;AAKF;AA7PG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,IAAA,GAWxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,IAAA,GAWlD,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,IAAA,GAWlD,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAEzC,EAAA,CAAA,EAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,IAAA,GAWzB,EAAA,CAAA,EAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GAEzB,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,EAAE,WAAW,GAAM,CAAC,CAAA,GAAA,EAAA,WAAA,oBAAA,KAAA,CAAA,GAtD/B,IAAA,EAAA,CAAA,EAAc,gBAAgB,CAAA,GAAA,CAAA"}
@@ -21,7 +21,7 @@ function n(t) {
21
21
  },
22
22
  sync: o,
23
23
  reset() {
24
- !r || t.isStateManaged?.() || (t.setState(a(n)), o());
24
+ r && !t.isStateManaged?.() && (t.setState(a(n)), o());
25
25
  },
26
26
  restore(e) {
27
27
  t.isStateManaged?.() || (t.restoreState(e), o());
@@ -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,CAAC,KAAe,EAAQ,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\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"}
@@ -33,7 +33,7 @@ function s(e) {
33
33
  return e.composedPath().find((e) => e instanceof HTMLElement && e.matches("web-ui-dropdown-item")) ?? null;
34
34
  }
35
35
  function c(e) {
36
- !e || e.hasAttribute("disabled") || e.focusItem?.();
36
+ e && !e.hasAttribute("disabled") && e.focusItem?.();
37
37
  }
38
38
  function l(e) {
39
39
  return [...e].filter((e) => e !== void 0).flatMap((e) => Array.from(e.querySelectorAll(t))).find((e) => !!e.shadowRoot?.activeElement);
@@ -1 +1 @@
1
- {"version":3,"file":"menu-tree.js","names":[],"sources":["../../../src/shared/menu-portal/menu-tree.ts"],"sourcesContent":["export const MENU_CONTENT_SELECTOR = 'web-ui-dropdown-item, web-ui-dropdown-divider, web-ui-dropdown-header'\nexport const MENU_ITEM_SELECTOR = 'web-ui-dropdown-item'\n\nexport function getMenuChildren(container: ParentNode): HTMLElement[] {\n const children: HTMLElement[] = []\n for (const child of Array.from(container.children)) {\n if (!(child instanceof HTMLElement)) continue\n if (child.matches(MENU_CONTENT_SELECTOR)) {\n children.push(child)\n continue\n }\n\n // 框架条件渲染会用元素包裹自有节点,或留下注释锚点。搜索 wrapper,\n // 但不进入 menu item 内部;其子节点属于嵌套 submenu。\n children.push(...getMenuChildren(child))\n }\n return children\n}\n\nexport function getEnabledMenuItems(container: ParentNode): HTMLElement[] {\n return getMenuChildren(container).filter(item => item.matches(`${MENU_ITEM_SELECTOR}:not([disabled])`))\n}\n\nexport function getMovableMenuSubtrees(container: ParentNode): HTMLElement[] {\n const subtrees: HTMLElement[] = []\n for (const child of Array.from(container.children)) {\n if (!(child instanceof HTMLElement)) continue\n if (child.matches(MENU_CONTENT_SELECTOR) || getMenuChildren(child).length > 0) subtrees.push(child)\n }\n return subtrees\n}\n\nexport function moveMenuChildren(source: ParentNode, target: HTMLElement) {\n getMovableMenuSubtrees(source).forEach(subtree => {\n // 正常调用 source !== target,移走后项不再属于 source,天然收敛;\n // 这里兜底防御 source === target 的误用,避免 appendChild 自移动触发观察者刷新循环。\n if (subtree.parentNode === target) return\n target.appendChild(subtree)\n })\n}\n\nexport function hideNestedMenuChildren(root: ParentNode, slot: string) {\n root.querySelectorAll<HTMLElement>('web-ui-dropdown-item[submenu]').forEach(item => {\n getMenuChildren(item).forEach(child => child.setAttribute('slot', slot))\n })\n}\n\nexport function getMenuItemFromEvent(event: Event): HTMLElement | null {\n return (\n event\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.matches(MENU_ITEM_SELECTOR)) ?? null\n )\n}\n\nexport function focusMenuItem(item: HTMLElement | undefined) {\n if (!item || item.hasAttribute('disabled')) return\n ;(item as HTMLElement & { focusItem?: () => void }).focusItem?.()\n}\n\nexport function findFocusedMenuItem(panels: Iterable<HTMLElement | undefined>): HTMLElement | undefined {\n return [...panels]\n .filter((panel): panel is HTMLElement => panel !== undefined)\n .flatMap(panel => Array.from(panel.querySelectorAll<HTMLElement>(MENU_ITEM_SELECTOR)))\n .find(item => Boolean(item.shadowRoot?.activeElement))\n}\n\n/**\n * 托管菜单项的模板位锚:每个被迁入面板的项在宿主 light DOM 留一个 marker 注释,\n * 表示其模板位。宿主因此始终持有完整有序骨架(marker + 框架注释锚点 + 非菜单节点),\n * 框架(Vue/React 条件渲染)打开期的插入以宿主为容器、以真实锚点为基准;\n * 面板项的顺序按 marker 序重排;关闭时按 marker 位双向归还。\n * context-menu 与 dropdown 的打开期实时渲染共用本机制。\n */\nexport type MenuItemAnchors = Map<HTMLElement, Comment>\n\n/**\n * 全集 reconcile:以「content 现有元素 ∪ 宿主元素」为托管全集。\n * 框架(如 Vue 的 v-if 翻转)可能不经宿主直接改写 portal 内节点——卸载旧项留下\n * 注释锚点、把新项直接插进 content——它们都会被这里收编(补 marker + 补隐藏由调用方负责),\n * 已被框架删除/移出两处的条目则清理 marker。最后把宿主中尚存的托管项移入 content。\n */\nexport function reconcileManagedMenuItems(\n host: HTMLElement,\n content: HTMLElement,\n anchors: MenuItemAnchors,\n markerText: string\n): void {\n // 宿主与 portal 面板分别位于不同容器,结构上不相交且收集只看直接子层,\n // 两个集合不会重复。\n const inContent = getMovableMenuSubtrees(content)\n const inHost = getMovableMenuSubtrees(host)\n const managed = new Set([...inContent, ...inHost])\n\n // 清理已失效条目:托管元素既不在 content 也不在宿主,说明已被框架删除。\n // 仍在 content 的元素必被上面收集进 managed,故这里只需处理宿主侧。\n anchors.forEach((marker, subtree) => {\n if (managed.has(subtree)) return\n marker.remove()\n anchors.delete(subtree)\n })\n\n // 确保每个托管元素都有 marker:框架直接插入 content 的项在此收编。\n // content 项按其当前 DOM 序(框架语义序)**反向**处理,新 marker 插到后继项 marker 之前——\n // 这样补建的 marker 序无需重排即可与 content 对齐;宿主项的 marker 原地补插。\n const ensureMarker = (subtree: HTMLElement, inHost: boolean, before?: Comment) => {\n const existing = anchors.get(subtree)\n if (existing && existing.parentNode === host) return existing\n existing?.remove()\n const marker = document.createComment(markerText)\n if (inHost) {\n host.insertBefore(marker, subtree)\n } else if (before && before.parentNode === host) {\n host.insertBefore(marker, before)\n } else {\n host.appendChild(marker)\n }\n anchors.set(subtree, marker)\n return marker\n }\n for (let index = inContent.length - 1; index >= 0; index--) {\n const subtree = inContent[index]\n const next = inContent[index + 1]\n const nextMarker = next ? anchors.get(next) : undefined\n ensureMarker(subtree, false, nextMarker)\n }\n for (const subtree of inHost) {\n ensureMarker(subtree, true)\n }\n\n // 宿主中尚存的托管项移入 content。\n for (const subtree of inHost) {\n content.appendChild(subtree)\n }\n}\n\n/** 按宿主 marker 序重排 content 项;顺序已一致时早退。 */\nexport function orderManagedMenuItems(\n host: HTMLElement,\n content: HTMLElement,\n anchors: MenuItemAnchors,\n markerText: string\n): void {\n const targetItems: HTMLElement[] = []\n for (const node of Array.from(host.childNodes)) {\n if (node.nodeType !== Node.COMMENT_NODE || node.textContent !== markerText) continue\n anchors.forEach((marker, subtree) => {\n if (marker !== node || subtree.parentNode !== content) return\n targetItems.push(subtree)\n })\n }\n\n if (targetItems.length === 0) return\n\n const currentItems = Array.from(content.children)\n if (currentItems.length === targetItems.length && currentItems.every((item, index) => item === targetItems[index]))\n return\n\n // 把每个元素移动到目标序中下一个元素之前,而不是 appendChild 全部移到末尾。\n // appendChild 会把元素越过 content 中的框架注释锚点(v-if 锚点),导致锚点脱离\n // 模板位置,下次框架翻转时据此锚点插入新分支项就会落错位;insertBefore 只重排\n // 元素相对顺序,锚点保持在原模板位置。锚点复位由 restoreFrameworkAnchors 独立完成。\n for (let index = targetItems.length - 1; index >= 0; index--) {\n const item = targetItems[index]\n const next = targetItems[index + 1]\n if (next) {\n if (item.nextElementSibling !== next) content.insertBefore(item, next)\n } else {\n content.appendChild(item)\n }\n }\n}\n\n/**\n * 捕获框架 v-if 注释锚点相对其后继元素的绑定,供重排后复位。\n * 后继以 nextElementSibling 解析(跳过注释/文本,多个相邻锚点绑定同一后继)。\n * 锚点在 content 末尾、无后继元素时记为 null(尾部锚点,复位时保持末尾)。\n */\nexport function captureFrameworkAnchors(content: HTMLElement, markerText: string): Map<Comment, HTMLElement | null> {\n const anchors = new Map<Comment, HTMLElement | null>()\n for (const node of Array.from(content.childNodes)) {\n if (node instanceof Comment && node.textContent !== markerText) {\n const nextEl = node.nextElementSibling\n anchors.set(node, nextEl instanceof HTMLElement ? nextEl : null)\n }\n }\n return anchors\n}\n\n/**\n * 把锚点复位到捕获时其后继元素之前(尾部锚点保持末尾)。\n * 元素重排用 insertBefore/appendChild 不会移动注释,锚点必须显式复位,\n * 否则脱离模板位置后 Vue 下次 v-if 翻转会把新分支项插到错误插入点。\n */\nexport function restoreFrameworkAnchors(content: HTMLElement, anchors: Map<Comment, HTMLElement | null>): void {\n for (const [anchor, successor] of anchors) {\n if (anchor.parentNode !== content) continue\n if (successor && successor.parentNode === content) {\n if (anchor.nextElementSibling !== successor) content.insertBefore(anchor, successor)\n } else {\n // 尾部锚点:重排可能把元素 append 到末尾越过锚点,恢复其末尾位置。\n content.appendChild(anchor)\n }\n }\n}\n\n/**\n * 关闭恢复:按 content 子节点序双向归还——元素回到宿主中自己的 marker 位,\n * 框架 v-if 注释锚点插到对应元素之前。Vue 仍持有这些锚点的 vnode.el 引用,\n * 随元素一起迁回宿主可确保框架下次 patch 以宿主为容器,不会因 parentNode === null 崩溃。\n * 归还后清除全部 marker 与登记。\n */\nexport function returnManagedMenuItemsToSlot(host: HTMLElement, content: HTMLElement, anchors: MenuItemAnchors): void {\n const pending: Comment[] = []\n for (const node of Array.from(content.childNodes)) {\n // instanceof 收窄:Comment 接口为空,nodeType 继承自 Node 的 number,无法用 === 收窄\n if (node instanceof Comment) {\n pending.push(node)\n continue\n }\n if (!(node instanceof HTMLElement)) continue\n const marker = anchors.get(node)\n if (!marker) continue\n for (const c of pending) {\n if (marker.parentNode === host) host.insertBefore(c, marker)\n else host.appendChild(c)\n }\n pending.length = 0\n if (marker.parentNode === host) {\n host.insertBefore(node, marker)\n } else {\n host.appendChild(node)\n }\n marker.remove()\n anchors.delete(node)\n }\n // 尾部框架锚点追加到宿主末尾\n for (const c of pending) host.appendChild(c)\n // 映射中剩余 = 已不在 content 的条目(如翻转中被框架卸载的),仅清理 marker\n anchors.forEach(marker => marker.remove())\n anchors.clear()\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"menu-tree.js","names":[],"sources":["../../../src/shared/menu-portal/menu-tree.ts"],"sourcesContent":["export const MENU_CONTENT_SELECTOR = 'web-ui-dropdown-item, web-ui-dropdown-divider, web-ui-dropdown-header'\nexport const MENU_ITEM_SELECTOR = 'web-ui-dropdown-item'\n\nexport function getMenuChildren(container: ParentNode): HTMLElement[] {\n const children: HTMLElement[] = []\n for (const child of Array.from(container.children)) {\n if (!(child instanceof HTMLElement)) continue\n if (child.matches(MENU_CONTENT_SELECTOR)) {\n children.push(child)\n continue\n }\n\n // 框架条件渲染会用元素包裹自有节点,或留下注释锚点。搜索 wrapper,\n // 但不进入 menu item 内部;其子节点属于嵌套 submenu。\n children.push(...getMenuChildren(child))\n }\n return children\n}\n\nexport function getEnabledMenuItems(container: ParentNode): HTMLElement[] {\n return getMenuChildren(container).filter(item => item.matches(`${MENU_ITEM_SELECTOR}:not([disabled])`))\n}\n\nexport function getMovableMenuSubtrees(container: ParentNode): HTMLElement[] {\n const subtrees: HTMLElement[] = []\n for (const child of Array.from(container.children)) {\n if (!(child instanceof HTMLElement)) continue\n if (child.matches(MENU_CONTENT_SELECTOR) || getMenuChildren(child).length > 0) subtrees.push(child)\n }\n return subtrees\n}\n\nexport function moveMenuChildren(source: ParentNode, target: HTMLElement) {\n getMovableMenuSubtrees(source).forEach(subtree => {\n // 正常调用 source !== target,移走后项不再属于 source,天然收敛;\n // 这里兜底防御 source === target 的误用,避免 appendChild 自移动触发观察者刷新循环。\n if (subtree.parentNode === target) return\n target.appendChild(subtree)\n })\n}\n\nexport function hideNestedMenuChildren(root: ParentNode, slot: string) {\n root.querySelectorAll<HTMLElement>('web-ui-dropdown-item[submenu]').forEach(item => {\n getMenuChildren(item).forEach(child => child.setAttribute('slot', slot))\n })\n}\n\nexport function getMenuItemFromEvent(event: Event): HTMLElement | null {\n return (\n event\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.matches(MENU_ITEM_SELECTOR)) ?? null\n )\n}\n\nexport function focusMenuItem(item: HTMLElement | undefined) {\n if (!item || item.hasAttribute('disabled')) return\n ;(item as HTMLElement & { focusItem?: () => void }).focusItem?.()\n}\n\nexport function findFocusedMenuItem(panels: Iterable<HTMLElement | undefined>): HTMLElement | undefined {\n return [...panels]\n .filter((panel): panel is HTMLElement => panel !== undefined)\n .flatMap(panel => Array.from(panel.querySelectorAll<HTMLElement>(MENU_ITEM_SELECTOR)))\n .find(item => Boolean(item.shadowRoot?.activeElement))\n}\n\n/**\n * 托管菜单项的模板位锚:每个被迁入面板的项在宿主 light DOM 留一个 marker 注释,\n * 表示其模板位。宿主因此始终持有完整有序骨架(marker + 框架注释锚点 + 非菜单节点),\n * 框架(Vue/React 条件渲染)打开期的插入以宿主为容器、以真实锚点为基准;\n * 面板项的顺序按 marker 序重排;关闭时按 marker 位双向归还。\n * context-menu 与 dropdown 的打开期实时渲染共用本机制。\n */\nexport type MenuItemAnchors = Map<HTMLElement, Comment>\n\n/**\n * 全集 reconcile:以「content 现有元素 ∪ 宿主元素」为托管全集。\n * 框架(如 Vue 的 v-if 翻转)可能不经宿主直接改写 portal 内节点——卸载旧项留下\n * 注释锚点、把新项直接插进 content——它们都会被这里收编(补 marker + 补隐藏由调用方负责),\n * 已被框架删除/移出两处的条目则清理 marker。最后把宿主中尚存的托管项移入 content。\n */\nexport function reconcileManagedMenuItems(\n host: HTMLElement,\n content: HTMLElement,\n anchors: MenuItemAnchors,\n markerText: string\n): void {\n // 宿主与 portal 面板分别位于不同容器,结构上不相交且收集只看直接子层,\n // 两个集合不会重复。\n const inContent = getMovableMenuSubtrees(content)\n const inHost = getMovableMenuSubtrees(host)\n const managed = new Set([...inContent, ...inHost])\n\n // 清理已失效条目:托管元素既不在 content 也不在宿主,说明已被框架删除。\n // 仍在 content 的元素必被上面收集进 managed,故这里只需处理宿主侧。\n anchors.forEach((marker, subtree) => {\n if (managed.has(subtree)) return\n marker.remove()\n anchors.delete(subtree)\n })\n\n // 确保每个托管元素都有 marker:框架直接插入 content 的项在此收编。\n // content 项按其当前 DOM 序(框架语义序)**反向**处理,新 marker 插到后继项 marker 之前——\n // 这样补建的 marker 序无需重排即可与 content 对齐;宿主项的 marker 原地补插。\n const ensureMarker = (subtree: HTMLElement, inHost: boolean, before?: Comment) => {\n const existing = anchors.get(subtree)\n if (existing && existing.parentNode === host) return existing\n existing?.remove()\n const marker = document.createComment(markerText)\n if (inHost) {\n host.insertBefore(marker, subtree)\n } else if (before && before.parentNode === host) {\n host.insertBefore(marker, before)\n } else {\n host.appendChild(marker)\n }\n anchors.set(subtree, marker)\n return marker\n }\n for (let index = inContent.length - 1; index >= 0; index--) {\n const subtree = inContent[index]\n const next = inContent[index + 1]\n const nextMarker = next ? anchors.get(next) : undefined\n ensureMarker(subtree, false, nextMarker)\n }\n for (const subtree of inHost) {\n ensureMarker(subtree, true)\n }\n\n // 宿主中尚存的托管项移入 content。\n for (const subtree of inHost) {\n content.appendChild(subtree)\n }\n}\n\n/** 按宿主 marker 序重排 content 项;顺序已一致时早退。 */\nexport function orderManagedMenuItems(\n host: HTMLElement,\n content: HTMLElement,\n anchors: MenuItemAnchors,\n markerText: string\n): void {\n const targetItems: HTMLElement[] = []\n for (const node of Array.from(host.childNodes)) {\n if (node.nodeType !== Node.COMMENT_NODE || node.textContent !== markerText) continue\n anchors.forEach((marker, subtree) => {\n if (marker !== node || subtree.parentNode !== content) return\n targetItems.push(subtree)\n })\n }\n\n if (targetItems.length === 0) return\n\n const currentItems = Array.from(content.children)\n if (currentItems.length === targetItems.length && currentItems.every((item, index) => item === targetItems[index]))\n return\n\n // 把每个元素移动到目标序中下一个元素之前,而不是 appendChild 全部移到末尾。\n // appendChild 会把元素越过 content 中的框架注释锚点(v-if 锚点),导致锚点脱离\n // 模板位置,下次框架翻转时据此锚点插入新分支项就会落错位;insertBefore 只重排\n // 元素相对顺序,锚点保持在原模板位置。锚点复位由 restoreFrameworkAnchors 独立完成。\n for (let index = targetItems.length - 1; index >= 0; index--) {\n const item = targetItems[index]\n const next = targetItems[index + 1]\n if (next) {\n if (item.nextElementSibling !== next) content.insertBefore(item, next)\n } else {\n content.appendChild(item)\n }\n }\n}\n\n/**\n * 捕获框架 v-if 注释锚点相对其后继元素的绑定,供重排后复位。\n * 后继以 nextElementSibling 解析(跳过注释/文本,多个相邻锚点绑定同一后继)。\n * 锚点在 content 末尾、无后继元素时记为 null(尾部锚点,复位时保持末尾)。\n */\nexport function captureFrameworkAnchors(content: HTMLElement, markerText: string): Map<Comment, HTMLElement | null> {\n const anchors = new Map<Comment, HTMLElement | null>()\n for (const node of Array.from(content.childNodes)) {\n if (node instanceof Comment && node.textContent !== markerText) {\n const nextEl = node.nextElementSibling\n anchors.set(node, nextEl instanceof HTMLElement ? nextEl : null)\n }\n }\n return anchors\n}\n\n/**\n * 把锚点复位到捕获时其后继元素之前(尾部锚点保持末尾)。\n * 元素重排用 insertBefore/appendChild 不会移动注释,锚点必须显式复位,\n * 否则脱离模板位置后 Vue 下次 v-if 翻转会把新分支项插到错误插入点。\n */\nexport function restoreFrameworkAnchors(content: HTMLElement, anchors: Map<Comment, HTMLElement | null>): void {\n for (const [anchor, successor] of anchors) {\n if (anchor.parentNode !== content) continue\n if (successor && successor.parentNode === content) {\n if (anchor.nextElementSibling !== successor) content.insertBefore(anchor, successor)\n } else {\n // 尾部锚点:重排可能把元素 append 到末尾越过锚点,恢复其末尾位置。\n content.appendChild(anchor)\n }\n }\n}\n\n/**\n * 关闭恢复:按 content 子节点序双向归还——元素回到宿主中自己的 marker 位,\n * 框架 v-if 注释锚点插到对应元素之前。Vue 仍持有这些锚点的 vnode.el 引用,\n * 随元素一起迁回宿主可确保框架下次 patch 以宿主为容器,不会因 parentNode === null 崩溃。\n * 归还后清除全部 marker 与登记。\n */\nexport function returnManagedMenuItemsToSlot(host: HTMLElement, content: HTMLElement, anchors: MenuItemAnchors): void {\n const pending: Comment[] = []\n for (const node of Array.from(content.childNodes)) {\n // instanceof 收窄:Comment 接口为空,nodeType 继承自 Node 的 number,无法用 === 收窄\n if (node instanceof Comment) {\n pending.push(node)\n continue\n }\n if (!(node instanceof HTMLElement)) continue\n const marker = anchors.get(node)\n if (!marker) continue\n for (const c of pending) {\n if (marker.parentNode === host) host.insertBefore(c, marker)\n else host.appendChild(c)\n }\n pending.length = 0\n if (marker.parentNode === host) {\n host.insertBefore(node, marker)\n } else {\n host.appendChild(node)\n }\n marker.remove()\n anchors.delete(node)\n }\n // 尾部框架锚点追加到宿主末尾\n for (const c of pending) host.appendChild(c)\n // 映射中剩余 = 已不在 content 的条目(如翻转中被框架卸载的),仅清理 marker\n anchors.forEach(marker => marker.remove())\n anchors.clear()\n}\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ var n = () => t((t) => {
8
8
  r !== void 0 && (cancelAnimationFrame(r), r = void 0);
9
9
  }, c = () => {
10
10
  let e = t.getDialog();
11
- !e || !i || t.isOpen() || (o(), i = !1, e.classList.remove("is-closing", "is-visible"), e.open && (a = !0, e.close?.()));
11
+ e && i && !t.isOpen() && (o(), i = !1, e.classList.remove("is-closing", "is-visible"), e.open && (a = !0, e.close?.()));
12
12
  }, l = () => {
13
13
  let e = t.getDialog();
14
14
  if (e) {
@@ -16,7 +16,7 @@ var n = () => t((t) => {
16
16
  e.showModal?.();
17
17
  } catch {}
18
18
  e.offsetWidth, s(), r = requestAnimationFrame(() => {
19
- r = void 0, !(!t.isConnected() || !t.isOpen() || !e.open) && e.classList.add("is-visible");
19
+ r = void 0, t.isConnected() && t.isOpen() && e.open && e.classList.add("is-visible");
20
20
  });
21
21
  }
22
22
  }, u = () => {