@greypan/web-ui 2.1.7 → 2.1.8

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 (90) hide show
  1. package/README.CN.md +51 -35
  2. package/README.md +54 -35
  3. package/dist/assets/glass.js.map +1 -1
  4. package/dist/components/avatar/index.js +1 -1
  5. package/dist/components/avatar/index.js.map +1 -1
  6. package/dist/components/back-top/index.js +1 -1
  7. package/dist/components/back-top/index.js.map +1 -1
  8. package/dist/components/button/index.d.ts +6 -1
  9. package/dist/components/button/index.js +35 -14
  10. package/dist/components/button/index.js.map +1 -1
  11. package/dist/components/button/style.js +1 -1
  12. package/dist/components/button/style.js.map +1 -1
  13. package/dist/components/checkbox/index.d.ts +0 -3
  14. package/dist/components/checkbox/index.js.map +1 -1
  15. package/dist/components/context-menu/index.d.ts +4 -3
  16. package/dist/components/context-menu/index.js +47 -50
  17. package/dist/components/context-menu/index.js.map +1 -1
  18. package/dist/components/dialog/index.d.ts +1 -1
  19. package/dist/components/dialog/index.js +20 -19
  20. package/dist/components/dialog/index.js.map +1 -1
  21. package/dist/components/drawer/index.d.ts +2 -3
  22. package/dist/components/drawer/index.js +41 -31
  23. package/dist/components/drawer/index.js.map +1 -1
  24. package/dist/components/drawer/style.js +1 -1
  25. package/dist/components/drawer/style.js.map +1 -1
  26. package/dist/components/dropdown/index.d.ts +2 -9
  27. package/dist/components/dropdown/index.js +55 -51
  28. package/dist/components/dropdown/index.js.map +1 -1
  29. package/dist/components/dropdown-item/index.d.ts +0 -1
  30. package/dist/components/dropdown-item/index.js.map +1 -1
  31. package/dist/components/empty/index.js.map +1 -1
  32. package/dist/components/input/index.d.ts +1 -0
  33. package/dist/components/input/index.js +27 -14
  34. package/dist/components/input/index.js.map +1 -1
  35. package/dist/components/input/style.js +1 -1
  36. package/dist/components/input/style.js.map +1 -1
  37. package/dist/components/input-number/index.js.map +1 -1
  38. package/dist/components/option/index.js +1 -1
  39. package/dist/components/option/index.js.map +1 -1
  40. package/dist/components/popover/index.d.ts +1 -5
  41. package/dist/components/popover/index.js +41 -36
  42. package/dist/components/popover/index.js.map +1 -1
  43. package/dist/components/radio/index.d.ts +0 -3
  44. package/dist/components/radio/index.js.map +1 -1
  45. package/dist/components/segmented/index.js +6 -2
  46. package/dist/components/segmented/index.js.map +1 -1
  47. package/dist/components/segmented-trigger/index.js +1 -1
  48. package/dist/components/segmented-trigger/index.js.map +1 -1
  49. package/dist/components/segmented-trigger/style.js +1 -1
  50. package/dist/components/segmented-trigger/style.js.map +1 -1
  51. package/dist/components/select/index.js +5 -3
  52. package/dist/components/select/index.js.map +1 -1
  53. package/dist/components/slider/index.d.ts +0 -2
  54. package/dist/components/slider/index.js +1 -1
  55. package/dist/components/slider/index.js.map +1 -1
  56. package/dist/components/spinner/index.d.ts +0 -2
  57. package/dist/components/spinner/index.js.map +1 -1
  58. package/dist/components/svg-draw-lines/index.d.ts +0 -2
  59. package/dist/components/svg-draw-lines/index.js.map +1 -1
  60. package/dist/components/switch/index.d.ts +0 -1
  61. package/dist/components/switch/index.js.map +1 -1
  62. package/dist/components/switch/style.js +1 -1
  63. package/dist/components/switch/style.js.map +1 -1
  64. package/dist/components/textarea/index.d.ts +1 -0
  65. package/dist/components/textarea/index.js +47 -33
  66. package/dist/components/textarea/index.js.map +1 -1
  67. package/dist/components/textarea/style.js +1 -1
  68. package/dist/components/textarea/style.js.map +1 -1
  69. package/dist/components/theme/index.d.ts +0 -2
  70. package/dist/components/theme/index.js.map +1 -1
  71. package/dist/components/toast/manager.js.map +1 -1
  72. package/dist/components/toast/style.js +1 -1
  73. package/dist/components/toast/style.js.map +1 -1
  74. package/dist/components/toast/toast.d.ts +0 -4
  75. package/dist/components/toast/toast.js +14 -6
  76. package/dist/components/toast/toast.js.map +1 -1
  77. package/dist/components/toast/types.d.ts +0 -3
  78. package/dist/components/tooltip/index.d.ts +1 -0
  79. package/dist/components/tooltip/index.js +31 -30
  80. package/dist/components/tooltip/index.js.map +1 -1
  81. package/dist/shared/events/user-change.js +17 -0
  82. package/dist/shared/events/user-change.js.map +1 -0
  83. package/dist/shared/normalize/index.js.map +1 -1
  84. package/dist/shared/overlay/native-dialog-presence.js +8 -3
  85. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  86. package/dist/shared/overlay/overlay.js.map +1 -1
  87. package/dist/shared/overlay/portal.js +3 -1
  88. package/dist/shared/overlay/portal.js.map +1 -1
  89. package/dist/shared/overlay/presence.js.map +1 -1
  90. package/package.json +9 -4
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/slider/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport { normalizeNumber } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-slider')\nexport class WebUiSlider extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n static formAssociated = true\n\n // ElementInternals 实例,在 connectedCallback 中初始化\n private _internals?: ElementInternals\n @state() private _formDisabled = false\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) marks = false\n @property({ type: Boolean, reflect: true }) vertical = false\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Boolean, reflect: true }) required = false\n\n // value 使用访问器模式同步 ElementInternals\n private _value = 0\n private _initialValue = 0\n @property({ type: Number, reflect: true })\n get value(): number {\n return this._value\n }\n set value(v: number) {\n const normalized = normalizeNumber(v, -Infinity, Infinity, 0)\n const old = this._value\n this._value = normalized\n this._internals?.setFormValue?.(String(normalized))\n this.requestUpdate('value', old)\n }\n\n private _min = 0\n @property({ type: Number, reflect: true })\n get min(): number {\n return this._min\n }\n set min(v: number) {\n this._min = normalizeNumber(v, -Infinity, Infinity, 0)\n }\n\n private _max = 100\n @property({ type: Number, reflect: true })\n get max(): number {\n return this._max\n }\n set max(v: number) {\n this._max = normalizeNumber(v, -Infinity, Infinity, 100)\n }\n\n private _step = 1\n @property({ type: Number, reflect: true })\n get step(): number {\n return this._step\n }\n set step(v: number) {\n this._step = normalizeNumber(v, -Infinity, Infinity, 1)\n }\n\n @state() private _dragging = false\n // 避免未改变数值的点击被误认为一次表单提交\n private _interactionStartValue: number | undefined\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._internals = this.attachInternals()\n this._initialValue = Number(this.getAttribute('value')) || 0\n this._internals?.setFormValue?.(String(this._value))\n }\n\n override willUpdate(changed: Map<string, unknown>) {\n if (changed.has('value') || changed.has('min') || changed.has('max') || changed.has('step')) {\n const normalizedValue = this._normalizeValue(this.value)\n if (normalizedValue !== this.value) this.value = normalizedValue\n }\n }\n\n formResetCallback() {\n this.value = this._initialValue\n }\n\n formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n }\n\n override updated() {\n if (!this._internals || typeof this._internals.setValidity !== 'function') return\n if (this._isDisabled || !this.required) this._internals.setValidity({})\n else this._internals.setValidity({})\n }\n\n /** 将焦点移至滑块,供表单或外部控制使用 */\n override focus(options?: FocusOptions) {\n this._slider?.focus(options)\n }\n\n /** 移除滑块焦点 */\n override blur() {\n this._slider?.blur()\n }\n\n private get _slider(): HTMLDivElement | null {\n return this.renderRoot.querySelector<HTMLDivElement>('[role=\"slider\"]')\n }\n\n private get _range(): number {\n return Math.max(0, this.max - this.min)\n }\n\n private get _percent(): number {\n return this._range === 0 ? 0 : ((this.value - this.min) / this._range) * 100\n }\n\n private get _markValues(): number[] {\n if (!this.marks || this._range === 0) return []\n const count = Math.min(100, Math.floor(this._range / this._safeStep))\n return Array.from({ length: count + 1 }, (_, index) => this.min + index * this._safeStep)\n }\n\n private get _safeStep(): number {\n return Number.isFinite(this.step) && this.step > 0 ? this.step : 1\n }\n\n private _normalizeValue(value: number): number {\n if (!Number.isFinite(value)) return this.min\n const lower = Math.min(this.min, this.max)\n const upper = Math.max(this.min, this.max)\n const clamped = Math.min(upper, Math.max(lower, value))\n const steps = Math.round((clamped - lower) / this._safeStep)\n return Number((lower + steps * this._safeStep).toFixed(this._precision))\n }\n\n private get _precision(): number {\n return Math.max(this._decimalPlaces(this.min), this._decimalPlaces(this.max), this._decimalPlaces(this._safeStep))\n }\n\n private _decimalPlaces(value: number): number {\n const [, decimal = ''] = String(value).split('.')\n return decimal.length\n }\n\n private _setValue(value: number): boolean {\n if (this._isDisabled) return false\n const nextValue = this._normalizeValue(value)\n if (nextValue === this.value) return false\n this.value = nextValue\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n return true\n }\n\n private _setValueFromPointer(event: PointerEvent): boolean {\n const track = event.currentTarget as HTMLElement\n const rect = track.getBoundingClientRect()\n if (this.vertical) {\n if (rect.height <= 0) return false\n // 视觉上的数值从下往上增长,与坐标系相反。\n const ratio = Math.min(1, Math.max(0, 1 - (event.clientY - rect.top) / rect.height))\n return this._setValue(this.min + ratio * this._range)\n }\n if (rect.width <= 0) return false\n const ratio = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width))\n return this._setValue(this.min + ratio * this._range)\n }\n\n private _handlePointerDown(event: PointerEvent) {\n if (this._isDisabled) return\n const track = event.currentTarget as HTMLElement\n track.setPointerCapture?.(event.pointerId)\n this._interactionStartValue = this.value\n this._dragging = true\n this._setValueFromPointer(event)\n }\n\n private _handlePointerMove(event: PointerEvent) {\n if (!this._dragging) return\n this._setValueFromPointer(event)\n }\n\n private _handlePointerUp(event: PointerEvent) {\n if (!this._dragging) return\n this._setValueFromPointer(event)\n this._dragging = false\n if (this._interactionStartValue !== this.value) {\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n this._interactionStartValue = undefined\n }\n\n private _handleKeyDown(event: KeyboardEvent) {\n if (this._isDisabled) return\n const pageStep = this._safeStep * 10\n const keyValues: Record<string, number> = {\n ArrowDown: this.value - this._safeStep,\n ArrowLeft: this.value - this._safeStep,\n ArrowUp: this.value + this._safeStep,\n ArrowRight: this.value + this._safeStep,\n PageDown: this.value - pageStep,\n PageUp: this.value + pageStep,\n Home: this.min,\n End: this.max\n }\n const nextValue = keyValues[event.key]\n if (nextValue === undefined) return\n event.preventDefault()\n if (this._setValue(nextValue)) this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n override render() {\n const trackClass = classMap({\n 'wui-slider-track': true,\n 'is-disabled': this._isDisabled\n })\n const thumbClass = classMap({\n 'wui-slider-thumb': true,\n 'wui-glass': true,\n 'is-dragging': this._dragging\n })\n const trackStyle = styleMap({ '--percent': `${this._percent}%` })\n\n return html`\n <div\n class=${trackClass}\n style=${trackStyle}\n role=\"slider\"\n tabindex=${this._isDisabled ? -1 : 0}\n aria-label=\"滑块\"\n aria-orientation=${this.vertical ? 'vertical' : 'horizontal'}\n aria-valuemin=${this.min}\n aria-valuemax=${this.max}\n aria-valuenow=${this.value}\n aria-disabled=${String(this._isDisabled)}\n @keydown=${this._handleKeyDown}\n @pointerdown=${this._handlePointerDown}\n @pointermove=${this._handlePointerMove}\n @pointerup=${this._handlePointerUp}\n @pointercancel=${this._handlePointerUp}\n >\n <div class=\"wui-slider-progress\"></div>\n <div class=\"wui-slider-marks\">\n ${this._markValues.map(\n mark =>\n html`<span\n class=\"wui-slider-mark\"\n style=${styleMap({ '--percent': `${((mark - this.min) / this._range) * 100}%` })}\n ></span>`\n )}\n </div>\n <div class=${thumbClass}></div>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-slider': WebUiSlider\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/slider/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport { normalizeNumber } from '@/shared/normalize'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-slider')\nexport class WebUiSlider extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n static formAssociated = true\n\n // ElementInternals 实例,在 connectedCallback 中初始化\n private _internals?: ElementInternals\n @state() private _formDisabled = false\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) marks = false\n @property({ type: Boolean, reflect: true }) vertical = false\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Boolean, reflect: true }) required = false\n\n // value 使用访问器模式同步 ElementInternals\n private _value = 0\n private _initialValue = 0\n @property({ type: Number, reflect: true })\n get value(): number {\n return this._value\n }\n set value(v: number) {\n const normalized = normalizeNumber(v, -Infinity, Infinity, 0)\n const old = this._value\n this._value = normalized\n this._internals?.setFormValue?.(String(normalized))\n this.requestUpdate('value', old)\n }\n\n private _min = 0\n @property({ type: Number, reflect: true })\n get min(): number {\n return this._min\n }\n set min(v: number) {\n this._min = normalizeNumber(v, -Infinity, Infinity, 0)\n }\n\n private _max = 100\n @property({ type: Number, reflect: true })\n get max(): number {\n return this._max\n }\n set max(v: number) {\n this._max = normalizeNumber(v, -Infinity, Infinity, 100)\n }\n\n private _step = 1\n @property({ type: Number, reflect: true })\n get step(): number {\n return this._step\n }\n set step(v: number) {\n this._step = normalizeNumber(v, -Infinity, Infinity, 1)\n }\n\n @state() private _dragging = false\n // 避免未改变数值的点击被误认为一次表单提交\n private _interactionStartValue: number | undefined\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._internals = this.attachInternals()\n this._initialValue = Number(this.getAttribute('value')) || 0\n this._internals?.setFormValue?.(String(this._value))\n }\n\n override willUpdate(changed: Map<string, unknown>) {\n if (changed.has('value') || changed.has('min') || changed.has('max') || changed.has('step')) {\n const normalizedValue = this._normalizeValue(this.value)\n if (normalizedValue !== this.value) this.value = normalizedValue\n }\n }\n\n formResetCallback() {\n this.value = this._initialValue\n }\n\n formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n }\n\n override updated() {\n if (!this._internals || typeof this._internals.setValidity !== 'function') return\n if (this._isDisabled || !this.required) this._internals.setValidity({})\n else this._internals.setValidity({})\n }\n\n // 将焦点移至滑块,供表单或外部控制使用\n override focus(options?: FocusOptions) {\n this._slider?.focus(options)\n }\n\n // 移除滑块焦点\n override blur() {\n this._slider?.blur()\n }\n\n private get _slider(): HTMLDivElement | null {\n return this.renderRoot.querySelector<HTMLDivElement>('[role=\"slider\"]')\n }\n\n private get _range(): number {\n return Math.max(0, this.max - this.min)\n }\n\n private get _percent(): number {\n return this._range === 0 ? 0 : ((this.value - this.min) / this._range) * 100\n }\n\n private get _markValues(): number[] {\n if (!this.marks || this._range === 0) return []\n const count = Math.min(100, Math.floor(this._range / this._safeStep))\n return Array.from({ length: count + 1 }, (_, index) => this.min + index * this._safeStep)\n }\n\n private get _safeStep(): number {\n return Number.isFinite(this.step) && this.step > 0 ? this.step : 1\n }\n\n private _normalizeValue(value: number): number {\n if (!Number.isFinite(value)) return this.min\n const lower = Math.min(this.min, this.max)\n const upper = Math.max(this.min, this.max)\n const clamped = Math.min(upper, Math.max(lower, value))\n const steps = Math.round((clamped - lower) / this._safeStep)\n return Number((lower + steps * this._safeStep).toFixed(this._precision))\n }\n\n private get _precision(): number {\n return Math.max(this._decimalPlaces(this.min), this._decimalPlaces(this.max), this._decimalPlaces(this._safeStep))\n }\n\n private _decimalPlaces(value: number): number {\n const [, decimal = ''] = String(value).split('.')\n return decimal.length\n }\n\n private _setValue(value: number): boolean {\n if (this._isDisabled) return false\n const nextValue = this._normalizeValue(value)\n if (nextValue === this.value) return false\n this.value = nextValue\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n return true\n }\n\n private _setValueFromPointer(event: PointerEvent): boolean {\n const track = event.currentTarget as HTMLElement\n const rect = track.getBoundingClientRect()\n if (this.vertical) {\n if (rect.height <= 0) return false\n // 视觉上的数值从下往上增长,与坐标系相反。\n const ratio = Math.min(1, Math.max(0, 1 - (event.clientY - rect.top) / rect.height))\n return this._setValue(this.min + ratio * this._range)\n }\n if (rect.width <= 0) return false\n const ratio = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width))\n return this._setValue(this.min + ratio * this._range)\n }\n\n private _handlePointerDown(event: PointerEvent) {\n if (this._isDisabled) return\n const track = event.currentTarget as HTMLElement\n track.setPointerCapture?.(event.pointerId)\n this._interactionStartValue = this.value\n this._dragging = true\n this._setValueFromPointer(event)\n }\n\n private _handlePointerMove(event: PointerEvent) {\n if (!this._dragging) return\n this._setValueFromPointer(event)\n }\n\n private _handlePointerUp(event: PointerEvent) {\n if (!this._dragging) return\n this._setValueFromPointer(event)\n this._dragging = false\n if (this._interactionStartValue !== this.value) {\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n this._interactionStartValue = undefined\n }\n\n private _handleKeyDown(event: KeyboardEvent) {\n if (this._isDisabled) return\n const pageStep = this._safeStep * 10\n const keyValues: Record<string, number> = {\n ArrowDown: this.value - this._safeStep,\n ArrowLeft: this.value - this._safeStep,\n ArrowUp: this.value + this._safeStep,\n ArrowRight: this.value + this._safeStep,\n PageDown: this.value - pageStep,\n PageUp: this.value + pageStep,\n Home: this.min,\n End: this.max\n }\n const nextValue = keyValues[event.key]\n if (nextValue === undefined) return\n event.preventDefault()\n if (this._setValue(nextValue)) this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n override render() {\n const trackClass = classMap({\n 'wui-slider-track': true,\n 'is-disabled': this._isDisabled\n })\n const thumbClass = classMap({\n 'wui-slider-thumb': true,\n 'wui-glass': true,\n 'is-dragging': this._dragging\n })\n const trackStyle = styleMap({ '--percent': `${this._percent}%` })\n\n return html`\n <div\n class=${trackClass}\n style=${trackStyle}\n role=\"slider\"\n tabindex=${this._isDisabled ? '-1' : '0'}\n aria-label=\"滑块\"\n aria-orientation=${this.vertical ? 'vertical' : 'horizontal'}\n aria-valuemin=${this.min}\n aria-valuemax=${this.max}\n aria-valuenow=${this.value}\n aria-disabled=${String(this._isDisabled)}\n @keydown=${this._handleKeyDown}\n @pointerdown=${this._handlePointerDown}\n @pointermove=${this._handlePointerMove}\n @pointerup=${this._handlePointerUp}\n @pointercancel=${this._handlePointerUp}\n >\n <div class=\"wui-slider-progress\"></div>\n <div class=\"wui-slider-marks\">\n ${this._markValues.map(\n mark =>\n html`<span\n class=\"wui-slider-mark\"\n style=${styleMap({ '--percent': `${((mark - this.min) / this._range) * 100}%` })}\n ></span>`\n )}\n </div>\n <div class=${thumbClass}></div>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-slider': WebUiSlider\n }\n}\n"],"mappings":"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"}
@@ -3,13 +3,11 @@ export declare class WebUiSpinner extends LitElement {
3
3
  static styles: import('lit').CSSResult;
4
4
  size: number;
5
5
  description: string;
6
- /** 显示全屏居中 spinner(自动创建并挂载) */
7
6
  static show(options?: {
8
7
  size?: number;
9
8
  duration?: number;
10
9
  description?: string;
11
10
  }): WebUiSpinner;
12
- /** 隐藏并销毁全屏 spinner */
13
11
  static hide(): void;
14
12
  /** @internal 当前命令式实例 */
15
13
  static _current?: WebUiSpinner;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/spinner/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\n\nimport style from './style.css?inline'\n\nconst LEAF_COUNT = 8\n\nexport class WebUiSpinner extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Number, reflect: true }) size = 24\n @property({ type: String }) description = ''\n\n /** 显示全屏居中 spinner(自动创建并挂载) */\n static show(options?: { size?: number; duration?: number; description?: string }): WebUiSpinner {\n const el = document.createElement('web-ui-spinner')\n el._imperative = true\n if (options?.size) el.size = options.size\n if (options?.description) el.description = options.description\n document.body.appendChild(el)\n if (options?.duration && options.duration > 0) {\n el._timer = window.setTimeout(() => WebUiSpinner.hide(), options.duration)\n }\n return el\n }\n\n /** 隐藏并销毁全屏 spinner */\n static hide() {\n if (WebUiSpinner._current?._timer) {\n clearTimeout(WebUiSpinner._current._timer)\n WebUiSpinner._current._timer = undefined\n }\n WebUiSpinner._current?.remove()\n WebUiSpinner._current = undefined\n }\n\n /** @internal 当前命令式实例 */\n static _current?: WebUiSpinner\n\n /** @internal */\n _imperative = false\n /** @internal */\n _timer?: ReturnType<typeof setTimeout>\n\n override connectedCallback() {\n super.connectedCallback()\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'status')\n }\n if (!this.hasAttribute('aria-label')) {\n this.setAttribute('aria-label', '加载中')\n }\n if (this._imperative) {\n WebUiSpinner._current?.remove()\n WebUiSpinner._current = this\n this.classList.add('wui-spinner-overlay')\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n if (this._timer) {\n clearTimeout(this._timer)\n this._timer = undefined\n }\n }\n\n protected override updated(props: PropertyValues) {\n super.updated(props)\n if (props.has('size')) {\n this.style.setProperty('--wui-spinner-size', `${this.size}px`)\n }\n }\n\n override render() {\n const spinner = html`\n <div class=\"wui-spinner\">\n ${repeat(\n Array.from({ length: LEAF_COUNT }, (_, i) => i),\n i =>\n html`<span\n style=\"transform:rotate(${i * 45}deg);animation-delay:calc(-${LEAF_COUNT - i} / ${LEAF_COUNT} * 0.8s)\"\n ></span>`\n )}\n </div>\n ${this.description ? html`<div class=\"spinner-description\">${this.description}</div>` : nothing}\n <slot name=\"description\"></slot>\n `\n return this._imperative ? html`<div class=\"wui-spinner-overlay\">${spinner}</div>` : spinner\n }\n\n declare readonly $events: Record<string, never>\n}\n\n@customElement('web-ui-spinner')\nexport class WebUiSpinnerElement extends WebUiSpinner {}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-spinner': WebUiSpinner\n }\n}\n"],"mappings":";;;;;;AAMA,IAAM,IAAa,GAEN,IAAb,MAAa,UAAqB,EAAW;;EAiC7B,aA9BoC,KAAA,OAAA,IACR,KAAA,cAAA,IA6B5B,KAAA,cAAA;;;EAhCW,KAAA,SAAA,EAAU,CAAK;;CAMxC,OAAO,KAAK,GAAoF;EAC9F,IAAM,IAAK,SAAS,cAAc,gBAAgB;EAQlD,OAPA,EAAG,cAAc,IACb,GAAS,SAAM,EAAG,OAAO,EAAQ,OACjC,GAAS,gBAAa,EAAG,cAAc,EAAQ,cACnD,SAAS,KAAK,YAAY,CAAE,GACxB,GAAS,YAAY,EAAQ,WAAW,MAC1C,EAAG,SAAS,OAAO,iBAAiB,EAAa,KAAK,GAAG,EAAQ,QAAQ,IAEpE;CACT;CAGA,OAAO,OAAO;EAMZ,AALI,EAAa,UAAU,WACzB,aAAa,EAAa,SAAS,MAAM,GACzC,EAAa,SAAS,SAAS,KAAA,IAEjC,EAAa,UAAU,OAAO,GAC9B,EAAa,WAAW,KAAA;CAC1B;CAUA,oBAA6B;EAQ3B,AAPA,MAAM,kBAAkB,GACnB,KAAK,aAAa,MAAM,KAC3B,KAAK,aAAa,QAAQ,QAAQ,GAE/B,KAAK,aAAa,YAAY,KACjC,KAAK,aAAa,cAAc,KAAK,GAEnC,KAAK,gBACP,EAAa,UAAU,OAAO,GAC9B,EAAa,WAAW,MACxB,KAAK,UAAU,IAAI,qBAAqB;CAE5C;CAEA,uBAAgC;EAE9B,AADA,MAAM,qBAAqB,GAC3B,AAEE,KAAK,YADL,aAAa,KAAK,MAAM,GACV,KAAA;CAElB;CAEA,QAA2B,GAAuB;EAEhD,AADA,MAAM,QAAQ,CAAK,GACf,EAAM,IAAI,MAAM,KAClB,KAAK,MAAM,YAAY,sBAAsB,GAAG,KAAK,KAAK,GAAG;CAEjE;CAEA,SAAkB;EAChB,IAAM,IAAU,CAAI;;UAEd,EACA,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAAM,CAAC,IAC9C,MACE,CAAI;wCACwB,IAAI,GAAG,6BAA6B,IAAa,EAAE,KAAK,EAAW;qBAEnG,EAAE;;QAEF,KAAK,cAAc,CAAI,oCAAoC,KAAK,YAAY,UAAU,EAAQ;;;EAGlG,OAAO,KAAK,cAAc,CAAI,oCAAoC,EAAQ,UAAU;CACtF;AAGF;AAlFG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA;AAoFrB,IAAM,IAAN,cAAkC,EAAa,CAAC;AADtD,IAAA,EAAA,CAAA,EAAc,gBAAgB,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/spinner/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\n\nimport style from './style.css?inline'\n\nconst LEAF_COUNT = 8\n\nexport class WebUiSpinner extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Number, reflect: true }) size = 24\n @property({ type: String }) description = ''\n\n // 显示全屏居中 spinner(自动创建并挂载)\n static show(options?: { size?: number; duration?: number; description?: string }): WebUiSpinner {\n const el = document.createElement('web-ui-spinner')\n el._imperative = true\n if (options?.size) el.size = options.size\n if (options?.description) el.description = options.description\n document.body.appendChild(el)\n if (options?.duration && options.duration > 0) {\n el._timer = window.setTimeout(() => WebUiSpinner.hide(), options.duration)\n }\n return el\n }\n\n // 隐藏并销毁全屏 spinner\n static hide() {\n if (WebUiSpinner._current?._timer) {\n clearTimeout(WebUiSpinner._current._timer)\n WebUiSpinner._current._timer = undefined\n }\n WebUiSpinner._current?.remove()\n WebUiSpinner._current = undefined\n }\n\n /** @internal 当前命令式实例 */\n static _current?: WebUiSpinner\n\n /** @internal */\n _imperative = false\n /** @internal */\n _timer?: ReturnType<typeof setTimeout>\n\n override connectedCallback() {\n super.connectedCallback()\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'status')\n }\n if (!this.hasAttribute('aria-label')) {\n this.setAttribute('aria-label', '加载中')\n }\n if (this._imperative) {\n WebUiSpinner._current?.remove()\n WebUiSpinner._current = this\n this.classList.add('wui-spinner-overlay')\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n if (this._timer) {\n clearTimeout(this._timer)\n this._timer = undefined\n }\n }\n\n protected override updated(props: PropertyValues) {\n super.updated(props)\n if (props.has('size')) {\n this.style.setProperty('--wui-spinner-size', `${this.size}px`)\n }\n }\n\n override render() {\n const spinner = html`\n <div class=\"wui-spinner\">\n ${repeat(\n Array.from({ length: LEAF_COUNT }, (_, i) => i),\n i =>\n html`<span\n style=\"transform:rotate(${i * 45}deg);animation-delay:calc(-${LEAF_COUNT - i} / ${LEAF_COUNT} * 0.8s)\"\n ></span>`\n )}\n </div>\n ${this.description ? html`<div class=\"spinner-description\">${this.description}</div>` : nothing}\n <slot name=\"description\"></slot>\n `\n return this._imperative ? html`<div class=\"wui-spinner-overlay\">${spinner}</div>` : spinner\n }\n\n declare readonly $events: Record<string, never>\n}\n\n@customElement('web-ui-spinner')\nexport class WebUiSpinnerElement extends WebUiSpinner {}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-spinner': WebUiSpinner\n }\n}\n"],"mappings":";;;;;;AAMA,IAAM,IAAa,GAEN,IAAb,MAAa,UAAqB,EAAW;;EAiC7B,aA9BoC,KAAA,OAAA,IACR,KAAA,cAAA,IA6B5B,KAAA,cAAA;;;EAhCW,KAAA,SAAA,EAAU,CAAK;;CAMxC,OAAO,KAAK,GAAoF;EAC9F,IAAM,IAAK,SAAS,cAAc,gBAAgB;EAQlD,OAPA,EAAG,cAAc,IACb,GAAS,SAAM,EAAG,OAAO,EAAQ,OACjC,GAAS,gBAAa,EAAG,cAAc,EAAQ,cACnD,SAAS,KAAK,YAAY,CAAE,GACxB,GAAS,YAAY,EAAQ,WAAW,MAC1C,EAAG,SAAS,OAAO,iBAAiB,EAAa,KAAK,GAAG,EAAQ,QAAQ,IAEpE;CACT;CAGA,OAAO,OAAO;EAMZ,AALI,EAAa,UAAU,WACzB,aAAa,EAAa,SAAS,MAAM,GACzC,EAAa,SAAS,SAAS,KAAA,IAEjC,EAAa,UAAU,OAAO,GAC9B,EAAa,WAAW,KAAA;CAC1B;CAUA,oBAA6B;EAQ3B,AAPA,MAAM,kBAAkB,GACnB,KAAK,aAAa,MAAM,KAC3B,KAAK,aAAa,QAAQ,QAAQ,GAE/B,KAAK,aAAa,YAAY,KACjC,KAAK,aAAa,cAAc,KAAK,GAEnC,KAAK,gBACP,EAAa,UAAU,OAAO,GAC9B,EAAa,WAAW,MACxB,KAAK,UAAU,IAAI,qBAAqB;CAE5C;CAEA,uBAAgC;EAE9B,AADA,MAAM,qBAAqB,GAC3B,AAEE,KAAK,YADL,aAAa,KAAK,MAAM,GACV,KAAA;CAElB;CAEA,QAA2B,GAAuB;EAEhD,AADA,MAAM,QAAQ,CAAK,GACf,EAAM,IAAI,MAAM,KAClB,KAAK,MAAM,YAAY,sBAAsB,GAAG,KAAK,KAAK,GAAG;CAEjE;CAEA,SAAkB;EAChB,IAAM,IAAU,CAAI;;UAEd,EACA,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAAM,CAAC,IAC9C,MACE,CAAI;wCACwB,IAAI,GAAG,6BAA6B,IAAa,EAAE,KAAK,EAAW;qBAEnG,EAAE;;QAEF,KAAK,cAAc,CAAI,oCAAoC,KAAK,YAAY,UAAU,EAAQ;;;EAGlG,OAAO,KAAK,cAAc,CAAI,oCAAoC,EAAQ,UAAU;CACtF;AAGF;AAlFG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA;AAoFrB,IAAM,IAAN,cAAkC,EAAa,CAAC;AADtD,IAAA,EAAA,CAAA,EAAc,gBAAgB,CAAA,GAAA,CAAA"}
@@ -22,9 +22,7 @@ export declare class WebUiSvgDrawLines extends LitElement {
22
22
  */
23
23
  private collectGeometryElements;
24
24
  private animateElement;
25
- /** Z → explicit line back to start + 0.1px extra, forcing render of the closing segment */
26
25
  private fixPathGap;
27
- /** 首次 slot 内容稳定后自动播放一次 */
28
26
  private handleSlotChange;
29
27
  disconnectedCallback(): void;
30
28
  render(): import('lit').TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/svg-draw-lines/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { normalizeNumber } from '@/shared/normalize'\nimport { findNearestTheme } from '@/shared/theme/theme-scope'\n\nimport style from './style.css?inline'\n\nconst GEOMETRY_SELECTOR = 'path, rect, circle, line, polyline, polygon, ellipse'\n\ninterface AnimationRun {\n animations: Animation[]\n restoreQueue: Map<SVGGeometryElement, { dasharray: string | null; dashoffset: string | null }>\n patchedD: Map<SVGGeometryElement, string>\n}\n\n@customElement('web-ui-svg-draw-lines')\nexport class WebUiSvgDrawLines extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Number, reflect: true })\n get duration(): number {\n return this._duration\n }\n set duration(v: number) {\n const old = this._duration\n this._duration = normalizeNumber(v, 0, 30000, 1000)\n this.requestUpdate('duration', old)\n }\n private _duration = 1000\n\n @property({ type: String, reflect: true }) easing = 'linear'\n\n private _activeRun: AnimationRun | undefined\n private _hasAutoPlayed = false\n /**\n * 停止当前播放并重新开始。每次调用重新收集子树中的几何元素。\n * 所有元素同时开始并行的 stroke-dashoffset 动画。\n * 无目标或当前主题范围启用 reduced motion 时立即 resolve。\n */\n async replay(): Promise<void> {\n this.cancelAll()\n\n if (this._isReducedMotion()) return\n\n const targets = this.collectGeometryElements()\n if (targets.length === 0) return\n\n const run: AnimationRun = {\n animations: [],\n restoreQueue: new Map(),\n patchedD: new Map()\n }\n this._activeRun = run\n\n await Promise.all(targets.map(el => this.animateElement(el, run)))\n\n // A later replay owns the current DOM state and must not be cleaned up here.\n if (this._activeRun === run) this.finishRun(run)\n }\n\n private cancelAll() {\n if (this._activeRun) this.finishRun(this._activeRun)\n }\n\n private _isReducedMotion(): boolean {\n const theme = findNearestTheme(this)\n if (theme) return theme.isReducedMotion()\n\n try {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n }\n\n private finishRun(run: AnimationRun) {\n run.animations.forEach(anim => anim.cancel())\n\n // The animation temporarily mutates consumer-owned SVG nodes, so always restore them.\n for (const [el, cached] of run.restoreQueue) {\n el.style.strokeDasharray = cached.dasharray ?? ''\n el.style.strokeDashoffset = cached.dashoffset ?? ''\n }\n\n for (const [el, d] of run.patchedD) {\n el.setAttribute('d', d)\n }\n\n if (this._activeRun === run) this._activeRun = undefined\n }\n\n /**\n * 深度遍历组件的 light DOM 子节点与开放 Shadow Root,\n * 收集所有 SVGGeometryElement。closed shadow root 跳过。\n */\n private collectGeometryElements(): SVGGeometryElement[] {\n const elements: SVGGeometryElement[] = []\n const seen = new Set<SVGGeometryElement>()\n\n const walk = (root: Node) => {\n // Collect SVG geometry from this subtree\n if (root instanceof Element || root instanceof DocumentFragment) {\n root.querySelectorAll(GEOMETRY_SELECTOR).forEach(el => {\n // instanceof SVGGeometryElement 在 jsdom 中未定义,使用 duck-type 检查\n if (\n typeof (el as unknown as Record<string, unknown>).getTotalLength === 'function' &&\n !seen.has(el as unknown as SVGGeometryElement)\n ) {\n seen.add(el as unknown as SVGGeometryElement)\n elements.push(el as unknown as SVGGeometryElement)\n }\n })\n }\n\n // Recurse into children and open shadow roots\n if (root instanceof Element) {\n for (const child of root.children) walk(child)\n if (root.shadowRoot) walk(root.shadowRoot)\n } else if (root instanceof ShadowRoot) {\n for (const child of root.children) walk(child)\n }\n }\n\n for (const child of this.children) walk(child)\n return elements\n }\n\n private animateElement(el: SVGGeometryElement, run: AnimationRun): Promise<void> {\n return new Promise(resolve => {\n // Save inline styles once per animation cycle\n if (!run.restoreQueue.has(el)) {\n run.restoreQueue.set(el, {\n dasharray: el.style.strokeDasharray,\n dashoffset: el.style.strokeDashoffset\n })\n }\n\n // Gap fix for paths ending with Z/z\n if (el.tagName === 'path') {\n const d = el.getAttribute('d')\n if (d && /[Zz]\\s*$/.test(d) && !run.patchedD.has(el)) {\n run.patchedD.set(el, d)\n el.setAttribute('d', this.fixPathGap(el, d))\n }\n }\n\n const strokeWidth = parseFloat(getComputedStyle(el).strokeWidth) || 0\n const len = el.getTotalLength() + strokeWidth\n\n el.style.strokeDasharray = `${len}`\n el.style.strokeDashoffset = `${len}`\n\n const anim = el.animate([{ strokeDashoffset: `${len}` }, { strokeDashoffset: '0' }], {\n duration: this.duration,\n easing: this.easing,\n fill: 'forwards'\n })\n\n run.animations.push(anim)\n\n anim.onfinish = () => {\n resolve()\n }\n\n anim.oncancel = () => {\n resolve()\n }\n })\n }\n\n /** Z → explicit line back to start + 0.1px extra, forcing render of the closing segment */\n private fixPathGap(pathEl: SVGPathElement, d: string): string {\n pathEl.setAttribute('d', d)\n const p0 = pathEl.getPointAtLength(0)\n const p1 = pathEl.getPointAtLength(0.1)\n return d.replace(/[Zz]\\s*$/, `L${p0.x.toFixed(3)} ${p0.y.toFixed(3)} L${p1.x.toFixed(3)} ${p1.y.toFixed(3)}`)\n }\n\n /** 首次 slot 内容稳定后自动播放一次 */\n private handleSlotChange() {\n if (this._hasAutoPlayed) return\n this._hasAutoPlayed = true\n void this.replay()\n }\n\n override disconnectedCallback() {\n this.cancelAll()\n super.disconnectedCallback()\n }\n\n override render() {\n return html`<slot @slotchange=${this.handleSlotChange}></slot>`\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-svg-draw-lines': WebUiSvgDrawLines\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/svg-draw-lines/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { normalizeNumber } from '@/shared/normalize'\nimport { findNearestTheme } from '@/shared/theme/theme-scope'\n\nimport style from './style.css?inline'\n\nconst GEOMETRY_SELECTOR = 'path, rect, circle, line, polyline, polygon, ellipse'\n\ninterface AnimationRun {\n animations: Animation[]\n restoreQueue: Map<SVGGeometryElement, { dasharray: string | null; dashoffset: string | null }>\n patchedD: Map<SVGGeometryElement, string>\n}\n\n@customElement('web-ui-svg-draw-lines')\nexport class WebUiSvgDrawLines extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Number, reflect: true })\n get duration(): number {\n return this._duration\n }\n set duration(v: number) {\n const old = this._duration\n this._duration = normalizeNumber(v, 0, 30000, 1000)\n this.requestUpdate('duration', old)\n }\n private _duration = 1000\n\n @property({ type: String, reflect: true }) easing = 'linear'\n\n private _activeRun: AnimationRun | undefined\n private _hasAutoPlayed = false\n /**\n * 停止当前播放并重新开始。每次调用重新收集子树中的几何元素。\n * 所有元素同时开始并行的 stroke-dashoffset 动画。\n * 无目标或当前主题范围启用 reduced motion 时立即 resolve。\n */\n async replay(): Promise<void> {\n this.cancelAll()\n\n if (this._isReducedMotion()) return\n\n const targets = this.collectGeometryElements()\n if (targets.length === 0) return\n\n const run: AnimationRun = {\n animations: [],\n restoreQueue: new Map(),\n patchedD: new Map()\n }\n this._activeRun = run\n\n await Promise.all(targets.map(el => this.animateElement(el, run)))\n\n // A later replay owns the current DOM state and must not be cleaned up here.\n if (this._activeRun === run) this.finishRun(run)\n }\n\n private cancelAll() {\n if (this._activeRun) this.finishRun(this._activeRun)\n }\n\n private _isReducedMotion(): boolean {\n const theme = findNearestTheme(this)\n if (theme) return theme.isReducedMotion()\n\n try {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n }\n\n private finishRun(run: AnimationRun) {\n run.animations.forEach(anim => anim.cancel())\n\n // The animation temporarily mutates consumer-owned SVG nodes, so always restore them.\n for (const [el, cached] of run.restoreQueue) {\n el.style.strokeDasharray = cached.dasharray ?? ''\n el.style.strokeDashoffset = cached.dashoffset ?? ''\n }\n\n for (const [el, d] of run.patchedD) {\n el.setAttribute('d', d)\n }\n\n if (this._activeRun === run) this._activeRun = undefined\n }\n\n /**\n * 深度遍历组件的 light DOM 子节点与开放 Shadow Root,\n * 收集所有 SVGGeometryElement。closed shadow root 跳过。\n */\n private collectGeometryElements(): SVGGeometryElement[] {\n const elements: SVGGeometryElement[] = []\n const seen = new Set<SVGGeometryElement>()\n\n const walk = (root: Node) => {\n // Collect SVG geometry from this subtree\n if (root instanceof Element || root instanceof DocumentFragment) {\n root.querySelectorAll(GEOMETRY_SELECTOR).forEach(el => {\n // instanceof SVGGeometryElement 在 jsdom 中未定义,使用 duck-type 检查\n if (\n typeof (el as unknown as Record<string, unknown>).getTotalLength === 'function' &&\n !seen.has(el as unknown as SVGGeometryElement)\n ) {\n seen.add(el as unknown as SVGGeometryElement)\n elements.push(el as unknown as SVGGeometryElement)\n }\n })\n }\n\n // Recurse into children and open shadow roots\n if (root instanceof Element) {\n for (const child of root.children) walk(child)\n if (root.shadowRoot) walk(root.shadowRoot)\n } else if (root instanceof ShadowRoot) {\n for (const child of root.children) walk(child)\n }\n }\n\n for (const child of this.children) walk(child)\n return elements\n }\n\n private animateElement(el: SVGGeometryElement, run: AnimationRun): Promise<void> {\n return new Promise(resolve => {\n // Save inline styles once per animation cycle\n if (!run.restoreQueue.has(el)) {\n run.restoreQueue.set(el, {\n dasharray: el.style.strokeDasharray,\n dashoffset: el.style.strokeDashoffset\n })\n }\n\n // Gap fix for paths ending with Z/z\n if (el.tagName === 'path') {\n const d = el.getAttribute('d')\n if (d && /[Zz]\\s*$/.test(d) && !run.patchedD.has(el)) {\n run.patchedD.set(el, d)\n el.setAttribute('d', this.fixPathGap(el, d))\n }\n }\n\n const strokeWidth = parseFloat(getComputedStyle(el).strokeWidth) || 0\n const len = el.getTotalLength() + strokeWidth\n\n el.style.strokeDasharray = `${len}`\n el.style.strokeDashoffset = `${len}`\n\n const anim = el.animate([{ strokeDashoffset: `${len}` }, { strokeDashoffset: '0' }], {\n duration: this.duration,\n easing: this.easing,\n fill: 'forwards'\n })\n\n run.animations.push(anim)\n\n anim.onfinish = () => {\n resolve()\n }\n\n anim.oncancel = () => {\n resolve()\n }\n })\n }\n\n // Z → explicit line back to start + 0.1px extra, forcing render of the closing segment\n private fixPathGap(pathEl: SVGPathElement, d: string): string {\n pathEl.setAttribute('d', d)\n const p0 = pathEl.getPointAtLength(0)\n const p1 = pathEl.getPointAtLength(0.1)\n return d.replace(/[Zz]\\s*$/, `L${p0.x.toFixed(3)} ${p0.y.toFixed(3)} L${p1.x.toFixed(3)} ${p1.y.toFixed(3)}`)\n }\n\n // 首次 slot 内容稳定后自动播放一次\n private handleSlotChange() {\n if (this._hasAutoPlayed) return\n this._hasAutoPlayed = true\n void this.replay()\n }\n\n override disconnectedCallback() {\n this.cancelAll()\n super.disconnectedCallback()\n }\n\n override render() {\n return html`<slot @slotchange=${this.handleSlotChange}></slot>`\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-svg-draw-lines': WebUiSvgDrawLines\n }\n}\n"],"mappings":"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"}
@@ -19,7 +19,6 @@ export declare class WebUiSwitch extends LitElement {
19
19
  formDisabledCallback(disabled: boolean): void;
20
20
  updated(): void;
21
21
  private _syncFormValue;
22
- /** 用户点击切换开关状态,阻止 label 默认行为避免原生 checkbox 重复触发 */
23
22
  private handleClick;
24
23
  private handlePointerDown;
25
24
  private handlePointerUp;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/switch/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\n\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideLoaderCircle } from '@/icons'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-switch')\nexport class WebUiSwitch extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n static formAssociated = true\n\n private _internals?: ElementInternals\n @state() private _formDisabled = false\n\n @state() private _checked = false\n\n get checked(): boolean {\n return this._checked\n }\n\n set checked(v: boolean) {\n const old = this._checked\n this._checked = v\n this._syncFormValue()\n this.requestUpdate('checked', old)\n }\n\n @property({ type: String, reflect: true }) name = ''\n @property({ type: String }) value = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) loading = false\n @state() private pressed = false\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n override connectedCallback() {\n super.connectedCallback()\n if (this._internals) return\n this._internals = this.attachInternals()\n if (this.hasAttribute('checked')) {\n this._checked = true\n }\n this._syncFormValue()\n }\n\n formResetCallback() {\n this.checked = this.hasAttribute('checked')\n }\n\n formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n }\n\n override updated() {\n this._syncFormValue()\n if (!this._internals || typeof this._internals.setValidity !== 'function') return\n if (this._isDisabled || !this.required || this._checked) this._internals.setValidity({})\n else this._internals.setValidity({ valueMissing: true }, '请启用此项')\n }\n\n private _syncFormValue() {\n this._internals?.setFormValue?.(this._checked ? this.value || 'on' : null)\n }\n\n /** 用户点击切换开关状态,阻止 label 默认行为避免原生 checkbox 重复触发 */\n private handleClick(e: Event) {\n e.preventDefault()\n if (this._isDisabled || this.loading) return\n const old = this._checked\n this._checked = !old\n this._syncFormValue()\n this.requestUpdate('checked', old)\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private handlePointerDown() {\n if (this._isDisabled || this.loading) return\n this.pressed = true\n }\n\n private handlePointerUp() {\n this.pressed = false\n }\n\n private handlePointerLeave() {\n this.pressed = false\n }\n\n override render() {\n const trackCls = {\n 'wui-switch-track': true,\n 'is-open': this._checked,\n 'is-disabled': this._isDisabled || this.loading\n }\n const thumbCls = {\n 'wui-switch-thumb': true,\n 'wui-glass': this.pressed,\n 'is-pressed': this.pressed\n }\n\n return html`\n <label\n class=${classMap(trackCls)}\n role=\"switch\"\n aria-checked=${String(this._checked)}\n @click=${this.handleClick}\n @pointerdown=${this.handlePointerDown}\n @pointerup=${this.handlePointerUp}\n @pointercancel=${this.handlePointerUp}\n @pointerleave=${this.handlePointerLeave}\n >\n <input\n type=\"checkbox\"\n .checked=${this._checked}\n ?disabled=${this._isDisabled || this.loading}\n class=\"sr-only\"\n />\n <div class=${classMap(thumbCls)}>\n ${this.loading\n ? html`<div class=\"wui-switch-loading\">\n <web-ui-icon .icon=${lucideLoaderCircle} size=\"14\" color=\"#08f\" spin></web-ui-icon>\n </div>`\n : ''}\n </div>\n </label>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-switch': WebUiSwitch\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/switch/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\n\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { lucideLoaderCircle } from '@/icons'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-switch')\nexport class WebUiSwitch extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n static formAssociated = true\n\n private _internals?: ElementInternals\n @state() private _formDisabled = false\n\n @state() private _checked = false\n\n get checked(): boolean {\n return this._checked\n }\n\n set checked(v: boolean) {\n const old = this._checked\n this._checked = v\n this._syncFormValue()\n this.requestUpdate('checked', old)\n }\n\n @property({ type: String, reflect: true }) name = ''\n @property({ type: String }) value = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) loading = false\n @state() private pressed = false\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n override connectedCallback() {\n super.connectedCallback()\n if (this._internals) return\n this._internals = this.attachInternals()\n if (this.hasAttribute('checked')) {\n this._checked = true\n }\n this._syncFormValue()\n }\n\n formResetCallback() {\n this.checked = this.hasAttribute('checked')\n }\n\n formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n }\n\n override updated() {\n this._syncFormValue()\n if (!this._internals || typeof this._internals.setValidity !== 'function') return\n if (this._isDisabled || !this.required || this._checked) this._internals.setValidity({})\n else this._internals.setValidity({ valueMissing: true }, '请启用此项')\n }\n\n private _syncFormValue() {\n this._internals?.setFormValue?.(this._checked ? this.value || 'on' : null)\n }\n\n // 用户点击切换开关状态,阻止 label 默认行为避免原生 checkbox 重复触发\n private handleClick(e: Event) {\n e.preventDefault()\n if (this._isDisabled || this.loading) return\n const old = this._checked\n this._checked = !old\n this._syncFormValue()\n this.requestUpdate('checked', old)\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private handlePointerDown() {\n if (this._isDisabled || this.loading) return\n this.pressed = true\n }\n\n private handlePointerUp() {\n this.pressed = false\n }\n\n private handlePointerLeave() {\n this.pressed = false\n }\n\n override render() {\n const trackCls = {\n 'wui-switch-track': true,\n 'is-open': this._checked,\n 'is-disabled': this._isDisabled || this.loading\n }\n const thumbCls = {\n 'wui-switch-thumb': true,\n 'wui-glass': this.pressed,\n 'is-pressed': this.pressed\n }\n\n return html`\n <label\n class=${classMap(trackCls)}\n role=\"switch\"\n aria-checked=${String(this._checked)}\n @click=${this.handleClick}\n @pointerdown=${this.handlePointerDown}\n @pointerup=${this.handlePointerUp}\n @pointercancel=${this.handlePointerUp}\n @pointerleave=${this.handlePointerLeave}\n >\n <input\n type=\"checkbox\"\n .checked=${this._checked}\n ?disabled=${this._isDisabled || this.loading}\n class=\"sr-only\"\n />\n <div class=${classMap(thumbCls)}>\n ${this.loading\n ? html`<div class=\"wui-switch-loading\">\n <web-ui-icon .icon=${lucideLoaderCircle} size=\"14\" color=\"#08f\" spin></web-ui-icon>\n </div>`\n : ''}\n </div>\n </label>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-switch': WebUiSwitch\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/switch/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-block}:host([disabled]){cursor:not-allowed}.sr-only{white-space:nowrap;clip-path:inset(50%);border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.wui-switch-track{cursor:pointer;-webkit-user-select:none;user-select:none;background-color:var(--wui-color-surface-raised-deep,#e5e5ea);outline-offset:2px;width:48px;height:24px;transition:background-color var(--wui-duration-trigger,.16s) ease;border-radius:2147483647px;outline:3px solid #0000;justify-content:space-between;align-items:center;display:flex;position:relative}.wui-switch-track:focus-visible{outline-color:var(--wui-focus-ring,#08f6)}.wui-switch-track.is-open{background-color:var(--wui-color-accent,#08f)}.wui-switch-track.is-disabled{cursor:not-allowed;opacity:.4}.wui-switch-thumb{width:20px;height:20px;transition:width var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), transform var(--wui-duration-trigger,.16s) cubic-bezier(.4, 0, .2, 1), border-radius var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), background-color var(--wui-duration-press,80ms) ease;border-radius:2147483647px;position:absolute;top:2px;left:2px;overflow:hidden}.wui-switch-thumb.is-pressed{background-color:#0000;border-radius:2147483647px;width:32px}.wui-switch-thumb:not(.is-pressed){background-color:var(--wui-color-surface,#fff);box-shadow:1px 2px 6px #0003}.wui-switch-track.is-open .wui-switch-thumb{transform:translate(24px)}.wui-switch-track.is-open .wui-switch-thumb.is-pressed{transform:translate(12px)}.wui-switch-loading{pointer-events:none;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-block}:host([disabled]){cursor:not-allowed}.sr-only{white-space:nowrap;clip-path:inset(50%);border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.wui-switch-track{cursor:pointer;-webkit-user-select:none;user-select:none;background-color:var(--wui-color-surface-raised-deep,#e5e5ea);outline-offset:2px;width:48px;height:24px;transition:background-color var(--wui-duration-trigger,.16s) ease;border-radius:2147483647px;outline:3px solid #0000;justify-content:space-between;align-items:center;display:flex;position:relative}.wui-switch-track:focus-within{outline-color:var(--wui-focus-ring,#08f6)}.wui-switch-track.is-open{background-color:var(--wui-color-accent,#08f)}.wui-switch-track.is-disabled{cursor:not-allowed;opacity:.4}.wui-switch-thumb{width:20px;height:20px;transition:width var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), transform var(--wui-duration-trigger,.16s) cubic-bezier(.4, 0, .2, 1), border-radius var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), background-color var(--wui-duration-press,80ms) ease;border-radius:2147483647px;position:absolute;top:2px;left:2px;overflow:hidden}.wui-switch-thumb.is-pressed{background-color:#0000;border-radius:2147483647px;width:32px}.wui-switch-thumb:not(.is-pressed){background-color:var(--wui-color-surface,#fff);box-shadow:1px 2px 6px #0003}.wui-switch-track.is-open .wui-switch-thumb{transform:translate(24px)}.wui-switch-track.is-open .wui-switch-thumb.is-pressed{transform:translate(12px)}.wui-switch-loading{pointer-events:none;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -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 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 cursor: pointer;\n user-select: none;\n\n position: relative;\n\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n width: 48px;\n height: 24px;\n border-radius: calc(infinity * 1px);\n\n background-color: var(--wui-color-surface-raised-deep, #e5e5ea);\n outline: 3px solid transparent;\n outline-offset: 2px;\n\n transition: background-color var(--wui-duration-trigger, 160ms) ease;\n\n &:focus-visible {\n outline-color: var(--wui-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 position: absolute;\n top: 2px;\n left: 2px;\n\n overflow: hidden;\n\n width: 20px;\n height: 20px;\n border-radius: 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\n &.is-pressed {\n width: 32px;\n border-radius: calc(infinity * 1px);\n background-color: transparent;\n }\n\n &:not(.is-pressed) {\n background-color: var(--wui-color-surface, #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(24px);\n\n &.is-pressed {\n transform: translateX(12px);\n }\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 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 cursor: pointer;\n user-select: none;\n\n position: relative;\n\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n width: 48px;\n height: 24px;\n border-radius: calc(infinity * 1px);\n\n background-color: var(--wui-color-surface-raised-deep, #e5e5ea);\n outline: 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-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 position: absolute;\n top: 2px;\n left: 2px;\n\n overflow: hidden;\n\n width: 20px;\n height: 20px;\n border-radius: 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\n &.is-pressed {\n width: 32px;\n border-radius: calc(infinity * 1px);\n background-color: transparent;\n }\n\n &:not(.is-pressed) {\n background-color: var(--wui-color-surface, #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(24px);\n\n &.is-pressed {\n transform: translateX(12px);\n }\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":""}
@@ -14,6 +14,7 @@ export declare class WebUiTextarea extends LitElement {
14
14
  minlength: number | undefined;
15
15
  maxlength: number | undefined;
16
16
  autosize: boolean;
17
+ maxHeight: number;
17
18
  ariaLabel: string | null;
18
19
  ariaLabelledby: string | undefined;
19
20
  private _value;
@@ -2,21 +2,23 @@ import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate
2
2
  import "../icon/index.js";
3
3
  import t from "../../assets/glass.js";
4
4
  import n from "../../icons/generated/jam-close-circle-f.js";
5
+ import "../button/index.js";
5
6
  import r from "./style.js";
6
- import { LitElement as i, html as a, unsafeCSS as o } from "lit";
7
- import { customElement as s, property as c, state as l } from "lit/decorators.js";
8
- import { classMap as u } from "lit/directives/class-map.js";
9
- import { ifDefined as d } from "lit/directives/if-defined.js";
7
+ import { LitElement as i, html as a, nothing as o, unsafeCSS as s } from "lit";
8
+ import { customElement as c, property as l, state as u } from "lit/decorators.js";
9
+ import { classMap as d } from "lit/directives/class-map.js";
10
+ import { ifDefined as f } from "lit/directives/if-defined.js";
11
+ import { styleMap as p } from "lit/directives/style-map.js";
10
12
  //#region src/components/textarea/index.ts
11
- var f = class extends i {
13
+ var m = class extends i {
12
14
  constructor(...e) {
13
- super(...e), this.placeholder = "", this.name = "", this.disabled = !1, this.readonly = !1, this.required = !1, this.full = !1, this.clearable = !1, this.borderless = !1, this.rows = 3, this.autosize = !1, this.ariaLabel = null, this._value = "", this._focused = !1, this._formDisabled = !1, this._hasPrefix = !1, this._hasSuffix = !1, this._textarea = null, this._resizeObserver = null;
15
+ super(...e), this.placeholder = "", this.name = "", this.disabled = !1, this.readonly = !1, this.required = !1, this.full = !1, this.clearable = !1, this.borderless = !1, this.rows = 3, this.autosize = !1, this.maxHeight = 0, this.ariaLabel = null, this._value = "", this._focused = !1, this._formDisabled = !1, this._hasPrefix = !1, this._hasSuffix = !1, this._textarea = null, this._resizeObserver = null;
14
16
  }
15
17
  static {
16
18
  this.formAssociated = !0;
17
19
  }
18
20
  static {
19
- this.styles = [o(t), o(r)];
21
+ this.styles = [s(t), s(r)];
20
22
  }
21
23
  get value() {
22
24
  return this._value;
@@ -81,7 +83,7 @@ var f = class extends i {
81
83
  _autosize() {
82
84
  if (!this._textarea || !this.autosize) return;
83
85
  this._textarea.style.height = "auto";
84
- let e = this.rows * 20, t = this._textarea.scrollHeight, n = Math.min(Math.max(t, e), 300);
86
+ let e = this.rows * 20, t = this._textarea.scrollHeight, n = Math.max(t, e);
85
87
  this._textarea.style.height = `${n}px`;
86
88
  }
87
89
  handleInput(e) {
@@ -126,79 +128,91 @@ var f = class extends i {
126
128
  let e = this.clearable && this._value;
127
129
  return a`
128
130
  <div class="wui-glass wui-textarea-inner" @click=${this.focusTextarea}>
129
- <slot name="prefix" class=${u({ empty: !this._hasPrefix })} @slotchange=${this._onSlotChange}></slot>
131
+ <slot name="prefix" class=${d({ empty: !this._hasPrefix })} @slotchange=${this._onSlotChange}></slot>
130
132
  <textarea
131
133
  placeholder=${this.placeholder}
132
134
  name=${this.name}
133
- aria-label=${d(this.ariaLabel)}
134
- aria-labelledby=${d(this.ariaLabelledby)}
135
+ aria-label=${f(this.ariaLabel)}
136
+ aria-labelledby=${f(this.ariaLabelledby)}
135
137
  .rows=${this.rows}
136
- minlength=${d(this.minlength)}
137
- maxlength=${d(this.maxlength)}
138
+ minlength=${f(this.minlength)}
139
+ maxlength=${f(this.maxlength)}
138
140
  ?disabled=${this._isDisabled}
139
141
  ?readonly=${this.readonly}
140
142
  ?required=${this.required}
141
143
  .value=${this._value}
144
+ style=${this.maxHeight > 0 ? p({ "max-height": `${this.maxHeight}px` }) : o}
142
145
  @input=${this.handleInput}
143
146
  @change=${this.handleNativeChange}
144
147
  @focus=${this.handleFocus}
145
148
  @blur=${this.handleBlur}
146
149
  ></textarea>
147
- ${e ? a`<span class="clear" @pointerdown=${this.preventMouseDownBlur} @click=${this.handleClear}>
150
+ ${e ? a`<web-ui-button
151
+ icon
152
+ variant="ghost"
153
+ size="24"
154
+ aria-label="清除"
155
+ @pointerdown=${this.preventMouseDownBlur}
156
+ @click=${this.handleClear}
157
+ >
148
158
  <web-ui-icon .icon=${n}></web-ui-icon>
149
- </span>` : ""}
150
- <slot name="suffix" class=${u({ empty: !this._hasSuffix })} @slotchange=${this._onSlotChange}></slot>
159
+ </web-ui-button>` : ""}
160
+ <slot name="suffix" class=${d({ empty: !this._hasSuffix })} @slotchange=${this._onSlotChange}></slot>
151
161
  </div>
152
162
  `;
153
163
  }
154
164
  };
155
- e([c({
165
+ e([l({
156
166
  type: String,
157
167
  reflect: !0
158
- })], f.prototype, "placeholder", void 0), e([c({
168
+ })], m.prototype, "placeholder", void 0), e([l({
159
169
  type: String,
160
170
  reflect: !0
161
- })], f.prototype, "name", void 0), e([c({
171
+ })], m.prototype, "name", void 0), e([l({
162
172
  type: Boolean,
163
173
  reflect: !0
164
- })], f.prototype, "disabled", void 0), e([c({
174
+ })], m.prototype, "disabled", void 0), e([l({
165
175
  type: Boolean,
166
176
  reflect: !0
167
- })], f.prototype, "readonly", void 0), e([c({
177
+ })], m.prototype, "readonly", void 0), e([l({
168
178
  type: Boolean,
169
179
  reflect: !0
170
- })], f.prototype, "required", void 0), e([c({
180
+ })], m.prototype, "required", void 0), e([l({
171
181
  type: Boolean,
172
182
  reflect: !0
173
- })], f.prototype, "full", void 0), e([c({
183
+ })], m.prototype, "full", void 0), e([l({
174
184
  type: Boolean,
175
185
  reflect: !0
176
- })], f.prototype, "clearable", void 0), e([c({
186
+ })], m.prototype, "clearable", void 0), e([l({
177
187
  type: Boolean,
178
188
  reflect: !0
179
- })], f.prototype, "borderless", void 0), e([c({
189
+ })], m.prototype, "borderless", void 0), e([l({
180
190
  type: Number,
181
191
  reflect: !0
182
- })], f.prototype, "rows", void 0), e([c({
192
+ })], m.prototype, "rows", void 0), e([l({
183
193
  type: Number,
184
194
  reflect: !0
185
- })], f.prototype, "minlength", void 0), e([c({
195
+ })], m.prototype, "minlength", void 0), e([l({
186
196
  type: Number,
187
197
  reflect: !0
188
- })], f.prototype, "maxlength", void 0), e([c({
198
+ })], m.prototype, "maxlength", void 0), e([l({
189
199
  type: Boolean,
190
200
  reflect: !0
191
- })], f.prototype, "autosize", void 0), e([c({
201
+ })], m.prototype, "autosize", void 0), e([l({
202
+ type: Number,
203
+ reflect: !0,
204
+ attribute: "max-height"
205
+ })], m.prototype, "maxHeight", void 0), e([l({
192
206
  type: String,
193
207
  attribute: "aria-label"
194
- })], f.prototype, "ariaLabel", void 0), e([c({
208
+ })], m.prototype, "ariaLabel", void 0), e([l({
195
209
  type: String,
196
210
  attribute: "aria-labelledby"
197
- })], f.prototype, "ariaLabelledby", void 0), e([l()], f.prototype, "_value", void 0), e([l()], f.prototype, "_focused", void 0), e([l()], f.prototype, "_formDisabled", void 0), e([l()], f.prototype, "_hasPrefix", void 0), e([l()], f.prototype, "_hasSuffix", void 0), e([c({
211
+ })], m.prototype, "ariaLabelledby", void 0), e([u()], m.prototype, "_value", void 0), e([u()], m.prototype, "_focused", void 0), e([u()], m.prototype, "_formDisabled", void 0), e([u()], m.prototype, "_hasPrefix", void 0), e([u()], m.prototype, "_hasSuffix", void 0), e([l({
198
212
  type: String,
199
213
  reflect: !0
200
- })], f.prototype, "value", null), f = e([s("web-ui-textarea")], f);
214
+ })], m.prototype, "value", null), m = e([c("web-ui-textarea")], m);
201
215
  //#endregion
202
- export { f as WebUiTextarea };
216
+ export { m as WebUiTextarea };
203
217
 
204
218
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/textarea/index.ts"],"sourcesContent":["import { html, LitElement, 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'\n\n// web-ui-icon 必须注册(Rolldown tree-shake 副作用 import,引用类名阻止删除)\nimport '@/components/icon'\nimport glass from '@/assets/glass.css?inline'\nimport { jamCloseCircleF } from '@/icons'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-textarea')\nexport class WebUiTextarea extends LitElement {\n static formAssociated = true\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 @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 _formDisabled = 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 private _internals?: ElementInternals\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._internals?.setFormValue?.(v)\n this.requestUpdate('value', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n override connectedCallback() {\n super.connectedCallback()\n if (!this._internals) {\n this._internals = this.attachInternals()\n }\n this._internals.setFormValue?.(this._value)\n }\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 formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n }\n\n formResetCallback() {\n this.value = this.getAttribute('value') || ''\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n if (typeof state === 'string') this.value = state\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._internals\n const textarea = this._getTextarea()\n if (!internals || !textarea || typeof internals.setValidity !== 'function') return\n\n if (this._isDisabled || textarea.validity.valid) {\n internals.setValidity({})\n return\n }\n\n const validity: ValidityStateFlags = {}\n if (textarea.validity.valueMissing) validity.valueMissing = true\n if (textarea.validity.tooShort) validity.tooShort = true\n if (textarea.validity.tooLong) validity.tooLong = true\n internals.setValidity(validity, textarea.validationMessage, textarea)\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 const computedMin = this.rows * 20\n const computedMax = 300\n const scrollH = this._textarea.scrollHeight\n const clamped = Math.min(Math.max(scrollH, computedMin), computedMax)\n this._textarea.style.height = `${clamped}px`\n }\n\n private handleInput(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._internals?.setFormValue?.(this._value)\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 private handleNativeChange(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._internals?.setFormValue?.(this._value)\n this._syncValidity()\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) return\n this._value = ''\n this._internals?.setFormValue?.('')\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 const showClear = this.clearable && this._value\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 @input=${this.handleInput}\n @change=${this.handleNativeChange}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n ></textarea>\n ${showClear\n ? html`<span class=\"clear\" @pointerdown=${this.preventMouseDownBlur} @click=${this.handleClear}>\n <web-ui-icon .icon=${jamCloseCircleF}></web-ui-icon>\n </span>`\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'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-textarea')\nexport class WebUiTextarea extends LitElement {\n static formAssociated = true\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 _formDisabled = 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 private _internals?: ElementInternals\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._internals?.setFormValue?.(v)\n this.requestUpdate('value', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formDisabled\n }\n\n override connectedCallback() {\n super.connectedCallback()\n if (!this._internals) {\n this._internals = this.attachInternals()\n }\n this._internals.setFormValue?.(this._value)\n }\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 formDisabledCallback(disabled: boolean) {\n this._formDisabled = disabled\n }\n\n formResetCallback() {\n this.value = this.getAttribute('value') || ''\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n if (typeof state === 'string') this.value = state\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._internals\n const textarea = this._getTextarea()\n if (!internals || !textarea || typeof internals.setValidity !== 'function') return\n\n if (this._isDisabled || textarea.validity.valid) {\n internals.setValidity({})\n return\n }\n\n const validity: ValidityStateFlags = {}\n if (textarea.validity.valueMissing) validity.valueMissing = true\n if (textarea.validity.tooShort) validity.tooShort = true\n if (textarea.validity.tooLong) validity.tooLong = true\n internals.setValidity(validity, textarea.validationMessage, textarea)\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 const computedMin = this.rows * 20\n const scrollH = this._textarea.scrollHeight\n // 上限由 CSS max-height(maxHeight 属性)钳制,这里只负责随内容增高,默认无限\n const height = Math.max(scrollH, computedMin)\n this._textarea.style.height = `${height}px`\n }\n\n private handleInput(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._internals?.setFormValue?.(this._value)\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 private handleNativeChange(e: Event) {\n if (!(e.target instanceof HTMLTextAreaElement)) return\n this._value = e.target.value\n this._internals?.setFormValue?.(this._value)\n this._syncValidity()\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) return\n this._value = ''\n this._internals?.setFormValue?.('')\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 const showClear = this.clearable && this._value\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 ${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 <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":";;;;;;;;;;;;AAcO,IAAM,IAAN,cAA4B,EAAW;;EA4BK,aAxBQ,KAAA,cAAA,IACP,KAAA,OAAA,IACK,KAAA,WAAA,IACA,KAAA,WAAA,IACA,KAAA,WAAA,IACJ,KAAA,OAAA,IACK,KAAA,YAAA,IACC,KAAA,aAAA,IACP,KAAA,OAAA,GAGK,KAAA,WAAA,IAEyB,KAAA,YAAA,GACS,KAAA,YAAA,MAG/D,KAAA,SAAA,IACE,KAAA,WAAA,IACK,KAAA,gBAAA,IACH,KAAA,aAAA,IACA,KAAA,aAAA,IAEkB,KAAA,YAAA,MACC,KAAA,kBAAA;;;EA3BzB,KAAA,iBAAA;;;EACC,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CA6B5D,IACI,QAAgB;EAClB,OAAO,KAAK;CACd;CAEA,IAAI,MAAM,GAAW;EACnB,IAAM,IAAM,KAAK;EAGjB,AAFA,KAAK,SAAS,GACd,KAAK,YAAY,eAAe,CAAC,GACjC,KAAK,cAAc,SAAS,CAAG;CACjC;CAEA,IAAY,cAAuB;EACjC,OAAO,KAAK,YAAY,KAAK;CAC/B;CAEA,oBAA6B;EAK3B,AAJA,MAAM,kBAAkB,GACxB,AACE,KAAK,eAAa,KAAK,gBAAgB,GAEzC,KAAK,WAAW,eAAe,KAAK,MAAM;CAC5C;CAEA,uBAAgC;EAE9B,AADA,MAAM,qBAAqB,GAC3B,KAAK,kBAAkB;CACzB;CAEA,eAAwB;EACtB,KAAK,YAAY,KAAK,YAAY,cAAc,UAAU,KAAK;CACjE;CAEA,QAAiB,GAA+B;EAC9C,IAAI,EAAQ,IAAI,QAAQ,GAAG;GACzB,IAAM,IAAW,KAAK,aAAa;GACnC,AAAI,KAAY,EAAS,UAAU,KAAK,WACtC,EAAS,QAAQ,KAAK;EAE1B;EASA,AARI,EAAQ,IAAI,UAAU,MACpB,KAAK,WACP,KAAK,eAAe,IAEpB,KAAK,kBAAkB,EAAI,IAG/B,KAAK,cAAc,GACnB,KAAK,gBAAgB,WAAW,KAAK,QAAQ;CAC/C;CAEA,qBAAqB,GAAmB;EACtC,KAAK,gBAAgB;CACvB;CAEA,oBAAoB;EAClB,KAAK,QAAQ,KAAK,aAAa,OAAO,KAAK;CAC7C;CAEA,yBAAyB,GAAwC;EAC/D,AAAI,OAAO,KAAU,aAAU,KAAK,QAAQ;CAC9C;CAEA,eAAmD;EAEjD,OADA,KAAK,cAAc,KAAK,YAAY,cAAc,UAAU,KAAK,MAC1D,KAAK;CACd;CAEA,gBAAwB;EACtB,IAAM,IAAY,KAAK,YACjB,IAAW,KAAK,aAAa;EACnC,IAAI,CAAC,KAAa,CAAC,KAAY,OAAO,EAAU,eAAgB,YAAY;EAE5E,IAAI,KAAK,eAAe,EAAS,SAAS,OAAO;GAC/C,EAAU,YAAY,CAAC,CAAC;GACxB;EACF;EAEA,IAAM,IAA+B,CAAC;EAItC,AAHI,EAAS,SAAS,iBAAc,EAAS,eAAe,KACxD,EAAS,SAAS,aAAU,EAAS,WAAW,KAChD,EAAS,SAAS,YAAS,EAAS,UAAU,KAClD,EAAU,YAAY,GAAU,EAAS,mBAAmB,CAAQ;CACtE;CAEA,iBAAyB;EAEvB,IADA,KAAK,kBAAkB,GACnB,OAAO,iBAAmB,KAAa;GACzC,KAAK,UAAU;GACf;EACF;EAKA,AAJA,KAAK,kBAAkB,IAAI,qBAAqB;GAC9C,KAAK,UAAU;EACjB,CAAC,GACG,KAAK,aAAW,KAAK,gBAAgB,QAAQ,KAAK,SAAS,GAC/D,KAAK,UAAU;CACjB;CAEA,kBAA0B,IAAc,IAAO;EAG7C,AAFA,KAAK,iBAAiB,WAAW,GACjC,KAAK,kBAAkB,MACnB,KAAa,KAAK,WAAW,MAAM,eAAe,QAAQ;CAChE;CAEA,YAAoB;EAClB,IAAI,CAAC,KAAK,aAAa,CAAC,KAAK,UAAU;EACvC,KAAK,UAAU,MAAM,SAAS;EAC9B,IAAM,IAAc,KAAK,OAAO,IAC1B,IAAU,KAAK,UAAU,cAEzB,IAAS,KAAK,IAAI,GAAS,CAAW;EAC5C,KAAK,UAAU,MAAM,SAAS,GAAG,EAAO;CAC1C;CAEA,YAAoB,GAAU;EACtB,EAAE,kBAAkB,wBAC1B,KAAK,SAAS,EAAE,OAAO,OACvB,KAAK,YAAY,eAAe,KAAK,MAAM,GAC3C,KAAK,cAAc,GACnB,KAAK,UAAU;CACjB;CAEA,cAAsB;EACpB,AAAK,KAAK,gBAAa,KAAK,WAAW;CACzC;CAEA,aAAqB;EACnB,KAAK,WAAW;CAClB;CAEA,mBAA2B,GAAU;EAC7B,EAAE,kBAAkB,wBAC1B,KAAK,SAAS,EAAE,OAAO,OACvB,KAAK,YAAY,eAAe,KAAK,MAAM,GAC3C,KAAK,cAAc;CACrB;CAEA,QAAiB;EACf,KAAK,YAAY,cAAc,UAAU,CAAC,EAAE,MAAM;CACpD;CAEA,OAAgB;EACd,KAAK,YAAY,cAAc,UAAU,CAAC,EAAE,KAAK;CACnD;CAEA,SAAS;EACP,KAAK,YAAY,cAAc,UAAU,CAAC,EAAE,OAAO;CACrD;CAEA,gBAAwB;EAClB,KAAK,eACT,KAAK,YAAY,cAAc,UAAU,CAAC,EAAE,MAAM;CACpD;CAEA,cAAsB,GAAU;EAC9B,IAAI,EAAE,EAAE,kBAAkB,kBAAkB;EAC5C,IAAM,IAAO,EAAE,QACT,IAAa,EAAK,iBAAiB,CAAC,CAAC,SAAS;EAEpD,AADI,EAAK,SAAS,aAAU,KAAK,aAAa,IAC1C,EAAK,SAAS,aAAU,KAAK,aAAa;CAChD;CAEA,cAAsB;EAChB,KAAK,gBACT,KAAK,SAAS,IACd,KAAK,YAAY,eAAe,EAAE,GAClC,KAAK,cAAc,IAAI,MAAM,SAAS;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;CAC1E;CAEA,qBAA6B,GAAU;EACrC,EAAE,eAAe;CACnB;CAEA,SAAkB;EAChB,IAAM,IAAY,KAAK,aAAa,KAAK;EAEzC,OAAO,CAAI;yDAC0C,KAAK,cAAc;oCACxC,EAAS,EAAE,OAAO,CAAC,KAAK,WAAW,CAAC,EAAE,eAAe,KAAK,cAAc;;wBAEpF,KAAK,YAAY;iBACxB,KAAK,KAAK;uBACJ,EAAU,KAAK,SAAS,EAAE;4BACrB,EAAU,KAAK,cAAc,EAAE;kBACzC,KAAK,KAAK;sBACN,EAAU,KAAK,SAAS,EAAE;sBAC1B,EAAU,KAAK,SAAS,EAAE;sBAC1B,KAAK,YAAY;sBACjB,KAAK,SAAS;sBACd,KAAK,SAAS;mBACjB,KAAK,OAAO;kBACb,KAAK,YAAY,IAAI,EAAS,EAAE,cAAc,GAAG,KAAK,UAAU,IAAI,CAAC,IAAI,EAAQ;mBAChF,KAAK,YAAY;oBAChB,KAAK,mBAAmB;mBACzB,KAAK,YAAY;kBAClB,KAAK,WAAW;;UAExB,IACE,CAAI;;;;;6BAKa,KAAK,qBAAqB;uBAChC,KAAK,YAAY;;mCAEL,EAAgB;gCAEvC,GAAG;oCACqB,EAAS,EAAE,OAAO,CAAC,KAAK,WAAW,CAAC,EAAE,eAAe,KAAK,cAAc;;;CAG1G;AAQF;AAvPG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,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,aAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAEzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,WAAW;AAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GACjE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAClD,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,WAAW;AAAkB,CAAC,CAAA,GAAA,EAAA,WAAA,kBAAA,KAAA,CAAA,GAEvD,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,UAAA,KAAA,CAAA,GACN,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACN,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,iBAAA,KAAA,CAAA,GACN,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GACN,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GAMN,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,SAAA,IAAA,GAhC1C,IAAA,EAAA,CAAA,EAAc,iBAAiB,CAAA,GAAA,CAAA"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/textarea/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-textarea-inner{box-sizing:border-box;width:var(--wui-textarea-width,200px);min-width:var(--wui-button-size,40px);transition:border-color var(--wui-duration-focus,.2s), box-shadow var(--wui-duration-focus,.2s);border-radius:20px;align-items:flex-start;gap:8px;padding:9px 18px;display:flex;position:relative}:host([full]) .wui-textarea-inner{width:100%}:host([borderless]) .wui-textarea-inner{-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;background:0 0;border:none;padding:9px 0}:host([focused]) .wui-textarea-inner{--wui-glass-shadow:var(--wui-shadow-glass,0 2px 16px #0000000f), 0 0 0 3px var(--wui-focus-ring,#08f6);border-color:var(--wui-color-border-strong,#006ee680)}:host([borderless][focused]) .wui-textarea-inner{box-shadow:none;border-color:#0000}textarea{resize:vertical;box-sizing:border-box;width:100%;min-height:60px;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background:0 0;border:none;outline:none;flex:1;padding:0;line-height:1.5;display:block}textarea::placeholder{color:var(--wui-color-text-muted,#6a6a6a)}textarea:disabled{cursor:not-allowed}textarea:read-only{cursor:default}slot{font-size:var(--wui-font-size,14px);color:var(--wui-color-text-muted,#6a6a6a);flex-shrink:0;align-items:center;display:flex}slot.empty{display:none}.clear{cursor:pointer;color:var(--wui-color-text-muted,#6a6a6a);flex-shrink:0;justify-content:center;align-self:flex-start;align-items:center;margin-top:2px;display:flex}.clear:hover{color:var(--wui-color-text-muted,#6a6a6a)}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-textarea-inner{box-sizing:border-box;width:var(--wui-textarea-width,200px);min-width:var(--wui-button-size,40px);transition:border-color var(--wui-duration-focus,.2s), box-shadow var(--wui-duration-focus,.2s);border-radius:20px;align-items:flex-start;gap:8px;padding:9px 12px;display:flex;position:relative}:host([full]) .wui-textarea-inner{width:100%}:host([borderless]) .wui-textarea-inner{-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;background:0 0;border:none;padding:9px 0}:host([focused]) .wui-textarea-inner{--wui-glass-shadow:var(--wui-shadow-glass,0 2px 16px #0000000f), 0 0 0 3px var(--wui-focus-ring,#08f6);border-color:var(--wui-color-border-strong,#006ee680)}:host([borderless][focused]) .wui-textarea-inner{box-shadow:none;border-color:#0000}textarea{resize:vertical;box-sizing:border-box;width:100%;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background:0 0;border:none;outline:none;flex:1;padding:0;line-height:1.5;display:block}textarea::placeholder{color:var(--wui-color-text-muted,#6a6a6a)}textarea:disabled{cursor:not-allowed}textarea:read-only{cursor:default}slot{font-size:var(--wui-font-size,14px);color:var(--wui-color-text-muted,#6a6a6a);flex-shrink:0;align-items:center;display:flex}slot.empty{display:none}.wui-textarea-inner web-ui-button[variant=ghost]{--wui-button-color:var(--wui-color-text-muted,#6a6a6a);margin-top:calc((var(--wui-font-size,14px) * 1.5 - 24px) / 2);margin-left:-8px}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -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 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 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-button-size, 40px);\n padding: 9px 18px;\n border-radius: 20px;\n\n transition:\n border-color var(--wui-duration-focus, 200ms),\n box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([full]) .wui-textarea-inner {\n width: 100%;\n}\n\n/* ===== Borderless ===== */\n\n:host([borderless]) .wui-textarea-inner {\n padding: 9px 0;\n border: none;\n\n background: transparent;\n backdrop-filter: none;\n box-shadow: none;\n}\n\n:host([focused]) .wui-textarea-inner {\n --wui-glass-shadow:\n var(--wui-shadow-glass, 0 2px 16px rgb(0 0 0 / 0.06)), 0 0 0 3px var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n border-color: var(--wui-color-border-strong, rgb(0 110 230 / 0.5));\n}\n\n:host([borderless][focused]) .wui-textarea-inner {\n border-color: transparent;\n box-shadow: none;\n}\n\ntextarea {\n resize: vertical;\n\n display: block;\n flex: 1;\n\n box-sizing: border-box;\n width: 100%;\n min-height: 60px;\n padding: 0;\n border: none;\n\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-muted, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n }\n\n &:read-only {\n cursor: default;\n }\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-muted, #6a6a6a);\n}\n\nslot.empty {\n display: none;\n}\n\n/* ===== Clear button ===== */\n\n.clear {\n cursor: pointer;\n\n display: flex;\n flex-shrink: 0;\n align-items: center;\n align-self: flex-start;\n justify-content: center;\n\n margin-top: 2px;\n\n color: var(--wui-color-text-muted, #6a6a6a);\n\n &:hover {\n color: var(--wui-color-text-muted, #6a6a6a);\n }\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 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 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-button-size, 40px);\n padding: 9px 12px;\n border-radius: 20px;\n\n transition:\n border-color var(--wui-duration-focus, 200ms),\n box-shadow var(--wui-duration-focus, 200ms);\n}\n\n:host([full]) .wui-textarea-inner {\n width: 100%;\n}\n\n/* ===== Borderless ===== */\n\n:host([borderless]) .wui-textarea-inner {\n padding: 9px 0;\n border: none;\n\n background: transparent;\n backdrop-filter: none;\n box-shadow: none;\n}\n\n:host([focused]) .wui-textarea-inner {\n --wui-glass-shadow:\n var(--wui-shadow-glass, 0 2px 16px rgb(0 0 0 / 0.06)), 0 0 0 3px var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n border-color: var(--wui-color-border-strong, rgb(0 110 230 / 0.5));\n}\n\n:host([borderless][focused]) .wui-textarea-inner {\n border-color: transparent;\n box-shadow: none;\n}\n\ntextarea {\n resize: vertical;\n\n display: block;\n flex: 1;\n\n box-sizing: border-box;\n width: 100%;\n padding: 0;\n border: none;\n\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-muted, #6a6a6a);\n }\n\n &:disabled {\n cursor: not-allowed;\n }\n\n &:read-only {\n cursor: default;\n }\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-muted, #6a6a6a);\n}\n\nslot.empty {\n display: none;\n}\n\n/* ===== Clear button ===== */\n\n/* 复用 web-ui-button icon ghost:仅覆盖颜色为 muted 并对齐首行,保持原清除图标观感;\n 负 margin-left 抵消容器 8px flex gap,让清除按钮紧贴文本域内容 */\n.wui-textarea-inner web-ui-button[variant='ghost'] {\n --wui-button-color: var(--wui-color-text-muted, #6a6a6a);\n\n /* 与首行文字垂直居中对齐:容器 align-items: flex-start 使按钮贴内容区顶部(9px 留白处),\n 而首行中心在 9px + 行高半程;要让 24px 按钮(18px 图标居中)的图标中心落在首行中心,\n 需上移 (行高 − 按钮高度) / 2,行高 = font-size × 1.5(与 textarea 的 line-height 一致) */\n margin-top: calc((var(--wui-font-size, 14px) * 1.5 - 24px) / 2);\n margin-left: -8px;\n}\n"],"mappings":""}
@@ -12,9 +12,7 @@ export declare class WebUiTheme extends LitElement {
12
12
  private _warned;
13
13
  connectedCallback(): void;
14
14
  protected updated(): void;
15
- /** 返回此主题范围内的浮层挂载点;未设置 appearance 时不创建。 */
16
15
  getOverlayRoot(): HTMLElement | undefined;
17
- /** 当前范围是否应减少动效;`system` 跟随用户的系统偏好。 */
18
16
  isReducedMotion(): boolean;
19
17
  render(): import('lit').TemplateResult<1>;
20
18
  firstUpdated(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/theme/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { normalizeLiteral } from '@/shared/normalize'\nimport { applyOverlayRootStyles } from '@/shared/theme/overlay-root'\n\nimport style from './style.css?inline'\n\nexport type ThemeAppearance = 'light' | 'dark' | 'system'\nexport type ThemeMotion = 'full' | 'reduced' | 'system'\n\nconst APPEARANCES = ['light', 'dark', 'system'] as const\nconst MOTIONS = ['full', 'reduced', 'system'] as const\n\n@customElement('web-ui-theme')\nexport class WebUiTheme extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: String, reflect: true })\n get appearance(): ThemeAppearance | undefined {\n return this._appearance\n }\n set appearance(v: string | undefined) {\n const old = this._appearance\n this._appearance = v !== undefined ? (normalizeLiteral(v, APPEARANCES, 'light') as ThemeAppearance) : undefined\n this.requestUpdate('appearance', old)\n }\n private _appearance?: ThemeAppearance\n\n @property({ type: String, reflect: true })\n get motion(): ThemeMotion {\n return this._motion\n }\n set motion(v: string) {\n const old = this._motion\n this._motion = normalizeLiteral(v, MOTIONS, 'system') as ThemeMotion\n this.requestUpdate('motion', old)\n }\n private _motion: ThemeMotion = 'system'\n\n private _warned = false\n\n override connectedCallback() {\n super.connectedCallback()\n this._warnWhenAppearanceIsMissing()\n }\n\n protected override updated() {\n this._warnWhenAppearanceIsMissing()\n }\n\n /** 返回此主题范围内的浮层挂载点;未设置 appearance 时不创建。 */\n getOverlayRoot(): HTMLElement | undefined {\n if (!this._hasAppearance()) return undefined\n return this.renderRoot.querySelector<HTMLElement>('[data-wui-overlay-container]') ?? undefined\n }\n\n /** 当前范围是否应减少动效;`system` 跟随用户的系统偏好。 */\n isReducedMotion(): boolean {\n if (this.motion === 'reduced') return true\n if (this.motion === 'full') return false\n\n try {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n }\n\n override render() {\n return html`<slot></slot>${this._hasAppearance() ? html`<div data-wui-overlay-container></div>` : nothing}`\n }\n\n override firstUpdated() {\n if (this.renderRoot instanceof ShadowRoot) {\n applyOverlayRootStyles(this.renderRoot)\n }\n }\n\n private _hasAppearance(): this is this & { appearance: ThemeAppearance } {\n return this.appearance !== undefined && (APPEARANCES as readonly string[]).includes(this.appearance)\n }\n\n private _warnWhenAppearanceIsMissing() {\n if (this._hasAppearance() || this._warned || !import.meta.env.DEV) return\n this._warned = true\n console.warn('[web-ui-theme] appearance is required; this theme scope is inactive until it is set.')\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-theme': WebUiTheme\n }\n}\n"],"mappings":";;;;;;;AAWA,IAAM,IAAc;CAAC;CAAS;CAAQ;AAAQ,GACxC,IAAU;CAAC;CAAQ;CAAW;AAAQ,GAG/B,IAAN,cAAyB,EAAW;;EAyBvB,aAFa,KAAA,UAAA,UAEb,KAAA,UAAA;;;EAxBO,KAAA,SAAA,EAAU,CAAK;;CAExC,IACI,aAA0C;EAC5C,OAAO,KAAK;CACd;CACA,IAAI,WAAW,GAAuB;EACpC,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,cAAc,MAAM,KAAA,IAA6E,KAAA,IAAhE,EAAiB,GAAG,GAAa,OAAO,GAC9E,KAAK,cAAc,cAAc,CAAG;CACtC;CAGA,IACI,SAAsB;EACxB,OAAO,KAAK;CACd;CACA,IAAI,OAAO,GAAW;EACpB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,UAAU,EAAiB,GAAG,GAAS,QAAQ,GACpD,KAAK,cAAc,UAAU,CAAG;CAClC;CAKA,oBAA6B;EAE3B,AADA,MAAM,kBAAkB,GACxB,KAAK,6BAA6B;CACpC;CAEA,UAA6B;EAC3B,KAAK,6BAA6B;CACpC;CAGA,iBAA0C;EACnC,SAAK,eAAe,GACzB,OAAO,KAAK,WAAW,cAA2B,8BAA8B,KAAK,KAAA;CACvF;CAGA,kBAA2B;EACzB,IAAI,KAAK,WAAW,WAAW,OAAO;EACtC,IAAI,KAAK,WAAW,QAAQ,OAAO;EAEnC,IAAI;GACF,OAAO,OAAO,WAAW,kCAAkC,CAAC,CAAC;EAC/D,QAAQ;GACN,OAAO;EACT;CACF;CAEA,SAAkB;EAChB,OAAO,CAAI,gBAAgB,KAAK,eAAe,IAAI,CAAI,2CAA2C;CACpG;CAEA,eAAwB;EACtB,AAAI,KAAK,sBAAsB,cAC7B,EAAuB,KAAK,UAAU;CAE1C;CAEA,iBAAyE;EACvE,OAAO,KAAK,eAAe,KAAA,KAAc,EAAkC,SAAS,KAAK,UAAU;CACrG;CAEA,+BAAuC;EACjC,KAAK,eAAe,KAAK,KAAK;CAGpC;AAGF;AAxEG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,IAAA,GAWxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,IAAA,GAf1C,IAAA,EAAA,CAAA,EAAc,cAAc,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/theme/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { normalizeLiteral } from '@/shared/normalize'\nimport { applyOverlayRootStyles } from '@/shared/theme/overlay-root'\n\nimport style from './style.css?inline'\n\nexport type ThemeAppearance = 'light' | 'dark' | 'system'\nexport type ThemeMotion = 'full' | 'reduced' | 'system'\n\nconst APPEARANCES = ['light', 'dark', 'system'] as const\nconst MOTIONS = ['full', 'reduced', 'system'] as const\n\n@customElement('web-ui-theme')\nexport class WebUiTheme extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: String, reflect: true })\n get appearance(): ThemeAppearance | undefined {\n return this._appearance\n }\n set appearance(v: string | undefined) {\n const old = this._appearance\n this._appearance = v !== undefined ? (normalizeLiteral(v, APPEARANCES, 'light') as ThemeAppearance) : undefined\n this.requestUpdate('appearance', old)\n }\n private _appearance?: ThemeAppearance\n\n @property({ type: String, reflect: true })\n get motion(): ThemeMotion {\n return this._motion\n }\n set motion(v: string) {\n const old = this._motion\n this._motion = normalizeLiteral(v, MOTIONS, 'system') as ThemeMotion\n this.requestUpdate('motion', old)\n }\n private _motion: ThemeMotion = 'system'\n\n private _warned = false\n\n override connectedCallback() {\n super.connectedCallback()\n this._warnWhenAppearanceIsMissing()\n }\n\n protected override updated() {\n this._warnWhenAppearanceIsMissing()\n }\n\n // 返回此主题范围内的浮层挂载点;未设置 appearance 时不创建。\n getOverlayRoot(): HTMLElement | undefined {\n if (!this._hasAppearance()) return undefined\n return this.renderRoot.querySelector<HTMLElement>('[data-wui-overlay-container]') ?? undefined\n }\n\n // 当前范围是否应减少动效;`system` 跟随用户的系统偏好。\n isReducedMotion(): boolean {\n if (this.motion === 'reduced') return true\n if (this.motion === 'full') return false\n\n try {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n } catch {\n return false\n }\n }\n\n override render() {\n return html`<slot></slot>${this._hasAppearance() ? html`<div data-wui-overlay-container></div>` : nothing}`\n }\n\n override firstUpdated() {\n if (this.renderRoot instanceof ShadowRoot) {\n applyOverlayRootStyles(this.renderRoot)\n }\n }\n\n private _hasAppearance(): this is this & { appearance: ThemeAppearance } {\n return this.appearance !== undefined && (APPEARANCES as readonly string[]).includes(this.appearance)\n }\n\n private _warnWhenAppearanceIsMissing() {\n if (this._hasAppearance() || this._warned || !import.meta.env.DEV) return\n this._warned = true\n console.warn('[web-ui-theme] appearance is required; this theme scope is inactive until it is set.')\n }\n\n declare readonly $events: Record<string, never>\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-theme': WebUiTheme\n }\n}\n"],"mappings":";;;;;;;AAWA,IAAM,IAAc;CAAC;CAAS;CAAQ;AAAQ,GACxC,IAAU;CAAC;CAAQ;CAAW;AAAQ,GAG/B,IAAN,cAAyB,EAAW;;EAyBvB,aAFa,KAAA,UAAA,UAEb,KAAA,UAAA;;;EAxBO,KAAA,SAAA,EAAU,CAAK;;CAExC,IACI,aAA0C;EAC5C,OAAO,KAAK;CACd;CACA,IAAI,WAAW,GAAuB;EACpC,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,cAAc,MAAM,KAAA,IAA6E,KAAA,IAAhE,EAAiB,GAAG,GAAa,OAAO,GAC9E,KAAK,cAAc,cAAc,CAAG;CACtC;CAGA,IACI,SAAsB;EACxB,OAAO,KAAK;CACd;CACA,IAAI,OAAO,GAAW;EACpB,IAAM,IAAM,KAAK;EAEjB,AADA,KAAK,UAAU,EAAiB,GAAG,GAAS,QAAQ,GACpD,KAAK,cAAc,UAAU,CAAG;CAClC;CAKA,oBAA6B;EAE3B,AADA,MAAM,kBAAkB,GACxB,KAAK,6BAA6B;CACpC;CAEA,UAA6B;EAC3B,KAAK,6BAA6B;CACpC;CAGA,iBAA0C;EACnC,SAAK,eAAe,GACzB,OAAO,KAAK,WAAW,cAA2B,8BAA8B,KAAK,KAAA;CACvF;CAGA,kBAA2B;EACzB,IAAI,KAAK,WAAW,WAAW,OAAO;EACtC,IAAI,KAAK,WAAW,QAAQ,OAAO;EAEnC,IAAI;GACF,OAAO,OAAO,WAAW,kCAAkC,CAAC,CAAC;EAC/D,QAAQ;GACN,OAAO;EACT;CACF;CAEA,SAAkB;EAChB,OAAO,CAAI,gBAAgB,KAAK,eAAe,IAAI,CAAI,2CAA2C;CACpG;CAEA,eAAwB;EACtB,AAAI,KAAK,sBAAsB,cAC7B,EAAuB,KAAK,UAAU;CAE1C;CAEA,iBAAyE;EACvE,OAAO,KAAK,eAAe,KAAA,KAAc,EAAkC,SAAS,KAAK,UAAU;CACrG;CAEA,+BAAuC;EACjC,KAAK,eAAe,KAAK,KAAK;CAGpC;AAGF;AAxEG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,IAAA,GAWxC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,IAAA,GAf1C,IAAA,EAAA,CAAA,EAAc,cAAc,CAAA,GAAA,CAAA"}