@greypan/web-ui 6.4.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.CN.md +211 -50
- package/README.md +222 -61
- package/dist/assets/glass.js +1 -1
- package/dist/assets/glass.js.map +1 -1
- package/dist/assets/selection-control.js +6 -0
- package/dist/assets/selection-control.js.map +1 -0
- package/dist/assets/toast-containers.js.map +1 -1
- package/dist/components/autocomplete/index.d.ts +19 -5
- package/dist/components/autocomplete/index.js +142 -108
- package/dist/components/autocomplete/index.js.map +1 -1
- package/dist/components/autocomplete/style.js +1 -1
- package/dist/components/autocomplete/style.js.map +1 -1
- package/dist/components/avatar/index.js +4 -4
- package/dist/components/badge/style.js.map +1 -1
- package/dist/components/button/index.js +15 -15
- package/dist/components/button/style.js.map +1 -1
- package/dist/components/button-group/index.js +5 -5
- package/dist/components/checkbox/index.d.ts +9 -2
- package/dist/components/checkbox/index.js +50 -26
- package/dist/components/checkbox/index.js.map +1 -1
- package/dist/components/checkbox/style.js +1 -1
- package/dist/components/checkbox/style.js.map +1 -1
- package/dist/components/checkbox-group/index.d.ts +3 -0
- package/dist/components/checkbox-group/index.js +27 -16
- package/dist/components/checkbox-group/index.js.map +1 -1
- package/dist/components/checkbox-group/style.js +1 -1
- package/dist/components/checkbox-group/style.js.map +1 -1
- package/dist/components/collapse/index.js.map +1 -1
- package/dist/components/context-menu/index.d.ts +10 -0
- package/dist/components/context-menu/index.js +51 -34
- package/dist/components/context-menu/index.js.map +1 -1
- package/dist/components/dialog/index.d.ts +6 -0
- package/dist/components/dialog/index.js +49 -21
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/dialog/style.js +1 -1
- package/dist/components/dialog/style.js.map +1 -1
- package/dist/components/drawer/index.d.ts +22 -4
- package/dist/components/drawer/index.js +141 -110
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/style.js +1 -1
- package/dist/components/drawer/style.js.map +1 -1
- package/dist/components/dropdown/index.d.ts +21 -1
- package/dist/components/dropdown/index.js +77 -51
- package/dist/components/dropdown/index.js.map +1 -1
- package/dist/components/editable-text/index.d.ts +471 -0
- package/dist/components/editable-text/index.js +206 -0
- package/dist/components/editable-text/index.js.map +1 -0
- package/dist/components/editable-text/style.js +6 -0
- package/dist/components/editable-text/style.js.map +1 -0
- package/dist/components/image-preview/index.js +103 -80
- package/dist/components/image-preview/index.js.map +1 -1
- package/dist/components/image-preview/style.js +1 -1
- package/dist/components/image-preview/style.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +39 -38
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/index.js +12 -6
- package/dist/components/input/index.js.map +1 -1
- package/dist/components/input/style.js.map +1 -1
- package/dist/components/input-number/index.js +15 -15
- package/dist/components/layout/index.js +9 -9
- package/dist/components/layout/index.js.map +1 -1
- package/dist/components/layout/style.js +1 -1
- package/dist/components/layout/style.js.map +1 -1
- package/dist/components/popover/index.d.ts +8 -2
- package/dist/components/popover/index.js +53 -55
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/radio/index.d.ts +1 -1
- package/dist/components/radio/index.js +22 -21
- package/dist/components/radio/index.js.map +1 -1
- package/dist/components/radio/style.js +1 -1
- package/dist/components/radio/style.js.map +1 -1
- package/dist/components/radio-group/index.d.ts +3 -0
- package/dist/components/radio-group/index.js +27 -16
- package/dist/components/radio-group/index.js.map +1 -1
- package/dist/components/radio-group/style.js +1 -1
- package/dist/components/radio-group/style.js.map +1 -1
- package/dist/components/segmented/index.d.ts +4 -1
- package/dist/components/segmented/index.js +42 -29
- package/dist/components/segmented/index.js.map +1 -1
- package/dist/components/segmented/style.js +1 -1
- package/dist/components/segmented/style.js.map +1 -1
- package/dist/components/segmented-trigger/style.js +1 -1
- package/dist/components/segmented-trigger/style.js.map +1 -1
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +38 -34
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/slider/index.js +11 -11
- package/dist/components/slider/index.js.map +1 -1
- package/dist/components/slider/style.js +1 -1
- package/dist/components/slider/style.js.map +1 -1
- package/dist/components/svg-draw-lines/index.d.ts +13 -2
- package/dist/components/svg-draw-lines/index.js +44 -31
- package/dist/components/svg-draw-lines/index.js.map +1 -1
- package/dist/components/switch/index.js +12 -12
- package/dist/components/switch/index.js.map +1 -1
- package/dist/components/switch/style.js.map +1 -1
- package/dist/components/textarea/index.js +6 -6
- package/dist/components/textarea/index.js.map +1 -1
- package/dist/components/textarea/style.js.map +1 -1
- package/dist/components/theme/index.d.ts +15 -0
- package/dist/components/theme/index.js +178 -21
- package/dist/components/theme/index.js.map +1 -1
- package/dist/components/theme/style.js +1 -1
- package/dist/components/theme/style.js.map +1 -1
- package/dist/components/toast/index.d.ts +1 -1
- package/dist/components/toast/manager.d.ts +1 -3
- package/dist/components/toast/manager.js +92 -49
- package/dist/components/toast/manager.js.map +1 -1
- package/dist/components/toast/style.js.map +1 -1
- package/dist/components/toast/toast.d.ts +37 -0
- package/dist/components/toast/toast.js +74 -21
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/components/toast/types.d.ts +0 -4
- package/dist/components/tooltip/index.d.ts +6 -1
- package/dist/components/tooltip/index.js +21 -19
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/shared/gesture/drag-gesture.js +66 -64
- package/dist/shared/gesture/drag-gesture.js.map +1 -1
- package/dist/shared/gesture/physics.js +7 -29
- package/dist/shared/gesture/physics.js.map +1 -1
- package/dist/shared/menu-behavior/index.js +3 -4
- package/dist/shared/menu-behavior/index.js.map +1 -1
- package/dist/shared/option-portal/combobox-shell.js +48 -7
- package/dist/shared/option-portal/combobox-shell.js.map +1 -1
- package/dist/shared/option-portal/index.js +9 -9
- package/dist/shared/overlay/anchored-panel.js +36 -31
- package/dist/shared/overlay/anchored-panel.js.map +1 -1
- package/dist/shared/overlay/native-dialog-presence.js +16 -0
- package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
- package/dist/shared/overlay/nested-drawer-layers.js +7 -4
- package/dist/shared/overlay/nested-drawer-layers.js.map +1 -1
- package/dist/shared/overlay/open-overlay.js +198 -0
- package/dist/shared/overlay/open-overlay.js.map +1 -0
- package/dist/shared/overlay/presence.js +19 -22
- package/dist/shared/overlay/presence.js.map +1 -1
- package/dist/shared/theme/duration.js +9 -0
- package/dist/shared/theme/duration.js.map +1 -0
- package/dist/shared/theme/reduced-motion.js +15 -0
- package/dist/shared/theme/reduced-motion.js.map +1 -0
- package/dist/shared/theme/root-sync.js +42 -0
- package/dist/shared/theme/root-sync.js.map +1 -0
- package/package.json +1 -1
- package/dist/shared/overlay/composition.js +0 -57
- package/dist/shared/overlay/composition.js.map +0 -1
- package/dist/shared/overlay/lifecycle.js +0 -41
- package/dist/shared/overlay/lifecycle.js.map +0 -1
- package/dist/vite.svg +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/segmented/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 { installPointerFocusSuppression } from '@/shared/focus/pointer-focus'\nimport { FormAssociated, defineFormAssociation, FormAssociationController } from '@/shared/form-association'\nimport { attachDragGesture, type DragGestureHandle } from '@/shared/gesture/drag-gesture'\nimport { clamp, snapToNearest } from '@/shared/gesture/physics'\nimport { defineGroupCoordinator, GroupController } from '@/shared/group-management'\n\nimport type { WebUiSegmentedTrigger } from '../segmented-trigger'\n\nimport style from './style.css?inline'\n\ninstallPointerFocusSuppression()\n\n@customElement('web-ui-segmented')\nexport class WebUiSegmented extends FormAssociated(LitElement) {\n static override styles = unsafeCSS(style)\n @property({ type: String, reflect: true }) name = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) required = false\n\n @state() private _value = ''\n @state() private _indicatorReady = false\n @state() private _pressed = false\n @state() private _isDragging = false\n\n private _dragGestureHandle: DragGestureHandle | null = null\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._dragGestureHandle?.destroy()\n this._dragGestureHandle = null\n }\n\n private readonly _groupController = new GroupController(\n this,\n defineGroupCoordinator<WebUiSegmentedTrigger, string>({\n host: this,\n getItems: () => [...this.querySelectorAll<WebUiSegmentedTrigger>('web-ui-segmented-trigger')],\n getValue: () => this._value,\n setValue: value => {\n this.value = value\n },\n getDisabled: () => this._isDisabled,\n isItem: (target): target is WebUiSegmentedTrigger =>\n target instanceof HTMLElement && target.matches('web-ui-segmented-trigger'),\n isItemSelected: (trigger, value) => trigger.value === value,\n getNextValue: (trigger, value) => (trigger.checked ? trigger.value : value),\n valuesEqual: (a, b) => a === b,\n copyValue: value => value,\n setItemSelected: (trigger, selected) => {\n trigger.checked = selected\n },\n dispatchValueChange: () => {\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n }).make(),\n { afterSync: () => requestAnimationFrame(() => this._updateIndicator()) }\n )\n\n get value(): string {\n return this._value\n }\n\n set value(v: string) {\n const old = this._value\n this._value = v\n this._formAssociation.sync()\n this.requestUpdate('value', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formAssociation.isFormDisabled()\n }\n\n private _updateIndicator() {\n const triggers = this.querySelectorAll<WebUiSegmentedTrigger>('web-ui-segmented-trigger')\n let left = 0\n let width = 0\n\n triggers.forEach(trigger => {\n if (trigger.value === this._value) {\n const triggerRect = trigger.getBoundingClientRect()\n const groupRect = this.getBoundingClientRect()\n left = triggerRect.left - groupRect.left\n width = triggerRect.width\n }\n })\n\n this.style.setProperty('--indicator-left', `${left}px`)\n this.style.setProperty('--indicator-width', `${width}px`)\n\n // 首帧只完成定位:先把当前定位以「未启用 left/width transition」状态提交为 before 值,\n // 再打开移动动画。若同一趟里 set 定位与启用 transition,浏览器会把 0→选项 当作一次过渡。\n if (!this._indicatorReady) {\n const indicator = this.renderRoot.querySelector<HTMLElement>('.wui-segmented-indicator')\n void indicator?.offsetWidth\n this._indicatorReady = true\n }\n }\n\n private handlePointerDown(e: PointerEvent) {\n if (this._isDisabled) return\n const triggers = [...this.querySelectorAll<WebUiSegmentedTrigger>('web-ui-segmented-trigger')]\n const enabledTriggers = triggers.filter(t => !t.disabled)\n if (enabledTriggers.length === 0) return\n\n // 必须按下当前选中的 trigger 才能启动指示器拖拽\n const activeTrigger = triggers.find(t => t.value === this._value)\n if (!activeTrigger || activeTrigger.disabled) return\n\n const activeTriggerRect = activeTrigger.getBoundingClientRect()\n const isPressedOnActive =\n e.clientX >= activeTriggerRect.left &&\n e.clientX <= activeTriggerRect.right &&\n e.clientY >= activeTriggerRect.top &&\n e.clientY <= activeTriggerRect.bottom\n\n if (!isPressedOnActive) return\n\n this._pressed = true\n\n const groupRect = this.getBoundingClientRect()\n const initialTriggerRect = activeTrigger.getBoundingClientRect()\n const initialLeft = initialTriggerRect.left - groupRect.left\n const initialWidth = initialTriggerRect.width\n\n const firstTriggerRect = triggers[0].getBoundingClientRect()\n const lastTriggerRect = triggers[triggers.length - 1].getBoundingClientRect()\n const minLeft = firstTriggerRect.left - groupRect.left\n const maxLeft = lastTriggerRect.right - groupRect.left - initialWidth\n\n const enabledCenters = enabledTriggers.map(t => {\n const r = t.getBoundingClientRect()\n return r.left - groupRect.left + r.width / 2\n })\n\n this._dragGestureHandle?.destroy()\n this._dragGestureHandle = attachDragGesture(e, {\n axis: 'x',\n threshold: 6,\n onMove: info => {\n this._isDragging = true\n const currentLeft = clamp(initialLeft + info.deltaX, minLeft, maxLeft)\n this.style.setProperty('--indicator-left', `${currentLeft}px`)\n this.style.setProperty('--indicator-width', `${initialWidth}px`)\n },\n onEnd: info => {\n const wasDragging = this._isDragging\n this._isDragging = false\n this._pressed = false\n\n if (wasDragging) {\n const currentLeft = clamp(initialLeft + info.deltaX, minLeft, maxLeft)\n const currentCenter = currentLeft + initialWidth / 2\n\n let targetTrigger = activeTrigger\n if (info.velocityX > 300) {\n const currentIdx = enabledTriggers.indexOf(activeTrigger)\n if (currentIdx !== -1 && currentIdx < enabledTriggers.length - 1) {\n targetTrigger = enabledTriggers[currentIdx + 1]\n } else {\n targetTrigger = enabledTriggers[enabledTriggers.length - 1]\n }\n } else if (info.velocityX < -300) {\n const currentIdx = enabledTriggers.indexOf(activeTrigger)\n if (currentIdx > 0) {\n targetTrigger = enabledTriggers[currentIdx - 1]\n } else {\n targetTrigger = enabledTriggers[0]\n }\n } else {\n const nearestIdx = snapToNearest(currentCenter, enabledCenters)\n if (nearestIdx !== -1 && enabledTriggers[nearestIdx]) {\n targetTrigger = enabledTriggers[nearestIdx]\n }\n }\n\n if (targetTrigger.value !== this._value) {\n this.value = targetTrigger.value\n this._groupController.sync()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n } else {\n this._updateIndicator()\n }\n }\n this.requestUpdate()\n },\n onCancel: () => {\n this._isDragging = false\n this._pressed = false\n this._updateIndicator()\n this.requestUpdate()\n }\n })\n }\n\n private handlePointerUp() {\n this._pressed = false\n }\n\n private handlePointerLeave() {\n if (!this._dragGestureHandle?.isDragging()) {\n this._pressed = false\n }\n }\n\n private readonly _formAssociation = defineFormAssociation<string>({\n host: this,\n initialize: () => {\n const attrValue = this.getAttribute('value')\n if (attrValue !== null && this._value === '') this._value = attrValue\n },\n getState: () => this._value,\n setState: value => {\n this.value = value\n },\n getFormValue: () => (this.name && this._value ? this._value : null),\n getFormState: () => this._value,\n restoreState: state => {\n if (typeof state === 'string') this.value = state\n }\n }).make()\n\n private readonly _formAssociationController = new FormAssociationController(this, this._formAssociation)\n\n override formDisabledCallback(disabled: boolean) {\n this._formAssociation.setDisabled(disabled)\n this._groupController.sync()\n }\n\n override render() {\n return html`\n <div\n class=${classMap({\n 'wui-segmented': true,\n 'is-disabled': this._isDisabled,\n 'is-pressed': this._pressed,\n 'is-dragging': this._isDragging,\n 'is-indicator-ready': this._indicatorReady\n })}\n role=\"listbox\"\n aria-orientation=\"horizontal\"\n @pointerdown=${this.handlePointerDown}\n @pointerup=${this.handlePointerUp}\n @pointercancel=${this.handlePointerUp}\n @pointerleave=${this.handlePointerLeave}\n >\n <span class=\"wui-segmented-indicator\"></span>\n <slot></slot>\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-segmented': WebUiSegmented\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/segmented/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 glass from '@/assets/glass.css?inline'\nimport { installPointerFocusSuppression } from '@/shared/focus/pointer-focus'\nimport { FormAssociated, defineFormAssociation, FormAssociationController } from '@/shared/form-association'\nimport { attachDragGesture, type DragGestureHandle } from '@/shared/gesture/drag-gesture'\nimport { clamp, snapToNearest } from '@/shared/gesture/physics'\nimport { defineGroupCoordinator, GroupController } from '@/shared/group-management'\nimport { normalizeLiteral } from '@/shared/normalize'\n\nimport type { WebUiSegmentedTrigger } from '../segmented-trigger'\n\nimport style from './style.css?inline'\n\ninstallPointerFocusSuppression()\n\nconst ALLOWED_VARIANTS = ['inset', 'raised'] as const\n\n@customElement('web-ui-segmented')\nexport class WebUiSegmented extends FormAssociated(LitElement) {\n // 轨道是不透明实体面:底色取 surface(浅色即 page,深色即 surface-raised 档)、无\n // backdrop blur,描边环与投影仍由\n // .wui-glass 提供且全状态同值;指示器恒挂同一配方,静止态由 surface-segmented 实色\n // 盖住玻璃输出,按压与拖拽态才透出玻璃。\n // variant=\"raised\" 切回经典形态:flat 灰轨道(surface-segmented、无环无投影)+\n // 实体白指示器(surface-selected + 柔投影),按压/拖拽态两变体同为透明玻璃;\n // 视觉差异全部由 :host([variant=...]) 规则承载,见 style.css。\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n @property({ type: String, reflect: true }) name = ''\n\n @property({ type: String, reflect: true })\n get variant(): 'inset' | 'raised' {\n return this._variant\n }\n set variant(v: string) {\n const old = this._variant\n this._variant = normalizeLiteral(v, ALLOWED_VARIANTS, 'inset')\n this.requestUpdate('variant', old)\n }\n private _variant: 'inset' | 'raised' = 'inset'\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) required = false\n\n @state() private _value = ''\n @state() private _indicatorReady = false\n @state() private _pressed = false\n @state() private _isDragging = false\n\n private _dragGestureHandle: DragGestureHandle | null = null\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._dragGestureHandle?.destroy()\n this._dragGestureHandle = null\n }\n\n private readonly _groupController = new GroupController(\n this,\n defineGroupCoordinator<WebUiSegmentedTrigger, string>({\n host: this,\n getItems: () => [...this.querySelectorAll<WebUiSegmentedTrigger>('web-ui-segmented-trigger')],\n getValue: () => this._value,\n setValue: value => {\n this.value = value\n },\n getDisabled: () => this._isDisabled,\n isItem: (target): target is WebUiSegmentedTrigger =>\n target instanceof HTMLElement && target.matches('web-ui-segmented-trigger'),\n isItemSelected: (trigger, value) => trigger.value === value,\n getNextValue: (trigger, value) => (trigger.checked ? trigger.value : value),\n valuesEqual: (a, b) => a === b,\n copyValue: value => value,\n setItemSelected: (trigger, selected) => {\n trigger.checked = selected\n },\n dispatchValueChange: () => {\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n }).make(),\n { afterSync: () => requestAnimationFrame(() => this._updateIndicator()) }\n )\n\n get value(): string {\n return this._value\n }\n\n set value(v: string) {\n const old = this._value\n this._value = v\n this._formAssociation.sync()\n this.requestUpdate('value', old)\n }\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formAssociation.isFormDisabled()\n }\n\n private _updateIndicator() {\n const triggers = this.querySelectorAll<WebUiSegmentedTrigger>('web-ui-segmented-trigger')\n let left = 0\n let width = 0\n\n triggers.forEach(trigger => {\n if (trigger.value === this._value) {\n const triggerRect = trigger.getBoundingClientRect()\n const groupRect = this.getBoundingClientRect()\n left = triggerRect.left - groupRect.left\n width = triggerRect.width\n }\n })\n\n this.style.setProperty('--indicator-left', `${left}px`)\n this.style.setProperty('--indicator-width', `${width}px`)\n\n // 首帧只完成定位:先把当前定位以「未启用 left/width transition」状态提交为 before 值,\n // 再打开移动动画。若同一趟里 set 定位与启用 transition,浏览器会把 0→选项 当作一次过渡。\n if (!this._indicatorReady) {\n const indicator = this.renderRoot.querySelector<HTMLElement>('.wui-segmented-indicator')\n void indicator?.offsetWidth\n this._indicatorReady = true\n }\n }\n\n private handlePointerDown(e: PointerEvent) {\n if (this._isDisabled) return\n const triggers = [...this.querySelectorAll<WebUiSegmentedTrigger>('web-ui-segmented-trigger')]\n const enabledTriggers = triggers.filter(t => !t.disabled)\n if (enabledTriggers.length === 0) return\n\n // 必须按下当前选中的 trigger 才能启动指示器拖拽\n const activeTrigger = triggers.find(t => t.value === this._value)\n if (!activeTrigger || activeTrigger.disabled) return\n\n const activeTriggerRect = activeTrigger.getBoundingClientRect()\n const isPressedOnActive =\n e.clientX >= activeTriggerRect.left &&\n e.clientX <= activeTriggerRect.right &&\n e.clientY >= activeTriggerRect.top &&\n e.clientY <= activeTriggerRect.bottom\n\n if (!isPressedOnActive) return\n\n this._pressed = true\n\n const groupRect = this.getBoundingClientRect()\n const initialTriggerRect = activeTrigger.getBoundingClientRect()\n const initialLeft = initialTriggerRect.left - groupRect.left\n const initialWidth = initialTriggerRect.width\n\n const firstTriggerRect = triggers[0].getBoundingClientRect()\n const lastTriggerRect = triggers[triggers.length - 1].getBoundingClientRect()\n const minLeft = firstTriggerRect.left - groupRect.left\n const maxLeft = lastTriggerRect.right - groupRect.left - initialWidth\n\n const enabledCenters = enabledTriggers.map(t => {\n const r = t.getBoundingClientRect()\n return r.left - groupRect.left + r.width / 2\n })\n\n this._dragGestureHandle?.destroy()\n this._dragGestureHandle = attachDragGesture(e, {\n axis: 'x',\n threshold: 6,\n onMove: info => {\n this._isDragging = true\n const currentLeft = clamp(initialLeft + info.deltaX, minLeft, maxLeft)\n this.style.setProperty('--indicator-left', `${currentLeft}px`)\n this.style.setProperty('--indicator-width', `${initialWidth}px`)\n },\n onEnd: info => {\n const wasDragging = this._isDragging\n this._isDragging = false\n this._pressed = false\n\n if (wasDragging) {\n const currentLeft = clamp(initialLeft + info.deltaX, minLeft, maxLeft)\n const currentCenter = currentLeft + initialWidth / 2\n\n let targetTrigger = activeTrigger\n if (info.velocityX > 300) {\n const currentIdx = enabledTriggers.indexOf(activeTrigger)\n if (currentIdx !== -1 && currentIdx < enabledTriggers.length - 1) {\n targetTrigger = enabledTriggers[currentIdx + 1]\n } else {\n targetTrigger = enabledTriggers[enabledTriggers.length - 1]\n }\n } else if (info.velocityX < -300) {\n const currentIdx = enabledTriggers.indexOf(activeTrigger)\n if (currentIdx > 0) {\n targetTrigger = enabledTriggers[currentIdx - 1]\n } else {\n targetTrigger = enabledTriggers[0]\n }\n } else {\n const nearestIdx = snapToNearest(currentCenter, enabledCenters)\n if (nearestIdx !== -1 && enabledTriggers[nearestIdx]) {\n targetTrigger = enabledTriggers[nearestIdx]\n }\n }\n\n if (targetTrigger.value !== this._value) {\n this.value = targetTrigger.value\n this._groupController.sync()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n } else {\n this._updateIndicator()\n }\n }\n this.requestUpdate()\n },\n onCancel: () => {\n this._isDragging = false\n this._pressed = false\n this._updateIndicator()\n this.requestUpdate()\n }\n })\n }\n\n private handlePointerUp() {\n this._pressed = false\n }\n\n private handlePointerLeave() {\n if (!this._dragGestureHandle?.isDragging()) {\n this._pressed = false\n }\n }\n\n private readonly _formAssociation = defineFormAssociation<string>({\n host: this,\n initialize: () => {\n const attrValue = this.getAttribute('value')\n if (attrValue !== null && this._value === '') this._value = attrValue\n },\n getState: () => this._value,\n setState: value => {\n this.value = value\n },\n getFormValue: () => (this.name && this._value ? this._value : null),\n getFormState: () => this._value,\n restoreState: state => {\n if (typeof state === 'string') this.value = state\n }\n }).make()\n\n private readonly _formAssociationController = new FormAssociationController(this, this._formAssociation)\n\n override formDisabledCallback(disabled: boolean) {\n this._formAssociation.setDisabled(disabled)\n this._groupController.sync()\n }\n\n override render() {\n return html`\n <div\n class=${classMap({\n 'wui-glass': true,\n 'wui-segmented': true,\n 'is-disabled': this._isDisabled,\n 'is-pressed': this._pressed,\n 'is-dragging': this._isDragging,\n 'is-indicator-ready': this._indicatorReady\n })}\n role=\"listbox\"\n aria-orientation=\"horizontal\"\n @pointerdown=${this.handlePointerDown}\n @pointerup=${this.handlePointerUp}\n @pointercancel=${this.handlePointerUp}\n @pointerleave=${this.handlePointerLeave}\n >\n <span class=\"wui-glass wui-segmented-indicator\"></span>\n <slot></slot>\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-segmented': WebUiSegmented\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/components/segmented/style.css?inline
|
|
2
|
-
var e = "*,:before,:after{box-sizing:border-box}:host{touch-action:none;-webkit-user-select:none;user-select:none;display:inline-block}.wui-segmented{touch-action:none;cursor:default;border-radius:var(--wui-radius-control,calc(infinity * 1px));background-color:var(--wui-color-surface
|
|
2
|
+
var e = "*,:before,:after{box-sizing:border-box}:host{touch-action:none;-webkit-user-select:none;user-select:none;display:inline-block}.wui-segmented{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);touch-action:none;cursor:default;border-radius:var(--wui-radius-control,calc(infinity * 1px));background-color:var(--wui-color-surface,#fff);-webkit-backdrop-filter:none;backdrop-filter:none;align-items:stretch;padding:4px;display:inline-flex;position:relative}.wui-segmented.is-disabled{cursor:not-allowed;opacity:.4}.wui-segmented.is-disabled .wui-segmented-trigger.is-disabled{opacity:1}:host([variant=raised]) .wui-segmented{background-color:var(--wui-color-surface-segmented,#e5e5ea);box-shadow:none}:host([variant=raised]) .wui-segmented:before{opacity:0}.wui-segmented-indicator{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);z-index:0;top:4px;bottom:4px;left:var(--indicator-left,0);transform-origin:50%;width:var(--indicator-width,0);border-radius:var(--wui-radius-control,calc(infinity * 1px));background-color:var(--wui-color-surface-segmented,#e5e5ea);-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;transition:transform var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), background-color var(--wui-duration-press,80ms) ease, box-shadow var(--wui-duration-press,80ms) ease;display:block;position:absolute;transform:scale(1)}.is-indicator-ready:not(.is-dragging) .wui-segmented-indicator{transition:left var(--wui-duration-trigger,.16s) var(--wui-ease-slide,cubic-bezier(.77, 0, .175, 1)), width var(--wui-duration-trigger,.16s) var(--wui-ease-slide,cubic-bezier(.77, 0, .175, 1)), transform var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), background-color var(--wui-duration-press,80ms) ease, box-shadow var(--wui-duration-press,80ms) ease}:host([variant=raised]) .wui-segmented-indicator{background-color:var(--wui-color-surface-selected,#fff);box-shadow:0 1px 3px #0000001f,0 1px 2px #00000014}.wui-segmented-indicator:before{opacity:0;transition:opacity var(--wui-duration-press,80ms) ease}.wui-segmented.is-pressed .wui-segmented-indicator,.wui-segmented.is-dragging .wui-segmented-indicator{-webkit-backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));box-shadow:inset 0 0 0 .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 38%, transparent), inset 0 1px .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 52%, transparent), inset 0 -.5px 1px #00000008, 0 2px 20px #0003;transition:transform var(--wui-duration-press,80ms) cubic-bezier(.4, 0, .2, 1), box-shadow var(--wui-duration-press,80ms) ease;background-color:#0000;transform:scale(1.5)}.wui-segmented.is-pressed .wui-segmented-indicator:before,.wui-segmented.is-dragging .wui-segmented-indicator:before{opacity:1}.wui-segmented.is-dragging:not(.is-disabled){--wui-internal-segmented-trigger-cursor:grabbing;cursor:grabbing}";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { e as default };
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/segmented/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n touch-action: none;\n user-select: none;\n display: inline-block;\n}\n\n.wui-segmented {\n touch-action: none;\n cursor: default;\n\n position: relative;\n\n display: inline-flex;\n align-items: stretch;\n\n padding: 4px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n background-color: var(--wui-color-surface
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/segmented/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n touch-action: none;\n user-select: none;\n display: inline-block;\n}\n\n.wui-segmented {\n /* 玻璃描边的角点半径与控件圆角同源:胶囊取短边一半(button-group 同法)。 */\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n\n touch-action: none;\n cursor: default;\n\n position: relative;\n\n display: inline-flex;\n align-items: stretch;\n\n padding: 4px;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n /* inset 变体(默认,「凹」):轨道是不透明实体面——底色取 --wui-color-surface、\n backdrop-filter 移除,描边环(::before)与投影由 .wui-glass 提供且静止/按压/拖拽\n 全状态同值。\n 为什么不是 surface-raised:#169 追加验收要求浅色下轨道与页面同色——surface-raised\n 的 #f2f2f7 在纯白页面上像一颗浅灰药丸凸出来,凹感不足。浅色 surface 与 page 同为\n #fff,轨道因此与页面同色,深度只由常驻的 1px 描边环与投影承担;深色 surface 与\n surface-raised 同为 #2c2c2e,「比页面高一档」的 elevation 原样保留(theme 里这两个\n token 在深色下同值,选 surface 不改变深色观感)。\n 实体化的取证依据:thumb 的 backdrop 采样面整个落在轨道之内(slider thumb 探出\n track 外、能采到页面背景,segmented 没有这个条件),玻璃轨道会把背后的条纹/色斑\n 连同自身边缘一起模糊进采样图——均匀深底上全透明 thumb 与相邻 track 仅差 +0.5 阶\n (42.8 vs 42.3)、本体不可感知,条纹底实测 thumb 内部灰度 std 1.89(背景渗透)。\n 轨道改实色后同一采样 std 归零,弧线与两条横线随磨砂边界一同消失,look3/4/5 为\n 压制这些采样痕迹引入的按压态特判(inset 高光淡出、环半隐、6% tint)全部移除。 */\n background-color: var(--wui-color-surface, #fff);\n backdrop-filter: none;\n\n &.is-disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n\n &.is-disabled .wui-segmented-trigger.is-disabled {\n opacity: 1;\n }\n}\n\n/* raised 变体(「凸」):经典形态的 flat 灰轨道——surface-segmented 实色,无描边环、无投影\n (.wui-glass 的 box-shadow 与 ::before 环整体关掉),三种状态下保持同值。 */\n:host([variant='raised']) .wui-segmented {\n background-color: var(--wui-color-surface-segmented, #e5e5ea);\n box-shadow: none;\n}\n\n:host([variant='raised']) .wui-segmented::before {\n opacity: 0;\n}\n\n.wui-segmented-indicator {\n /* 玻璃描边的角点半径与控件圆角同源:胶囊取短边一半(switch thumb 同法)。 */\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n\n position: absolute;\n\n /* 栈序契约:thumb 恒在 track 之上、文字之下。track 的 ::before 描边环按树序先画,\n trigger 的 z-index: 1 又压在 thumb 之上,所以 thumb 既不盖字也不被轨道盖住。 */\n z-index: 0;\n top: 4px;\n bottom: 4px;\n left: var(--indicator-left, 0);\n transform-origin: center center;\n transform: scale(1);\n\n display: block;\n\n width: var(--indicator-width, 0);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n /* inset 变体(默认)静止态是纯灰底:.wui-glass 恒挂只为复用按压态配方,这里把它的\n glass-only 输出逐条关掉——backdrop blur、::before 描边环、inset 高光与投影,\n 只留 surface-segmented 实色。 */\n background-color: var(--wui-color-surface-segmented, #e5e5ea);\n backdrop-filter: none;\n box-shadow: none;\n\n transition:\n transform var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n background-color var(--wui-duration-press, 80ms) ease,\n box-shadow var(--wui-duration-press, 80ms) ease;\n\n /* transition 只在首帧定位后且非拖拽状态启用,避免组件进入视口时触发初始化动画或拖拽跟手产生延迟;\n 其中的 background-color 只服务松开方向——按下态自己不含该属性,见下方按压/拖拽规则。\n backdrop-filter 不进任何过渡列表:静止态必须是 none(验收要求),而 none ↔ blur() 不可插值\n (dialog 的生硬跳变根因),离散过渡只会在 50% 处翻转,按下后前 40ms 会留下「已变色但无 blur」\n 的空洞帧;改为瞬时切换后,按下第一帧就是完整的按压态玻璃。 */\n .is-indicator-ready:not(.is-dragging) & {\n transition:\n left var(--wui-duration-trigger, 160ms) var(--wui-ease-slide, cubic-bezier(0.77, 0, 0.175, 1)),\n width var(--wui-duration-trigger, 160ms) var(--wui-ease-slide, cubic-bezier(0.77, 0, 0.175, 1)),\n transform var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n background-color var(--wui-duration-press, 80ms) ease,\n box-shadow var(--wui-duration-press, 80ms) ease;\n }\n}\n\n/* raised 变体静止态:实体白指示器 + 柔投影(经典形态;dark 主题 surface-selected 取\n #5c5c5e 凸起灰,同为实体档)。仅换底与投影,几何与过渡和 inset 变体同源。\n 注意源顺序:本规则与下方按压/拖拽规则特异性相同((0,3,0)),按压态必须排在更后面,\n 才能把实体底/柔投影覆盖成透明玻璃配方。 */\n:host([variant='raised']) .wui-segmented-indicator {\n background-color: var(--wui-color-surface-selected, #fff);\n box-shadow:\n 0 1px 3px rgb(0 0 0 / 0.12),\n 0 1px 2px rgb(0 0 0 / 0.08);\n}\n\n/* 静止态不绘制玻璃描边环:.wui-glass::before 是角点环 + 对角光泽层,纯灰底不需要它。\n 用 opacity 而不是 display:none,按压态才能让环随过渡淡入,而不是整层跳出。 */\n.wui-segmented-indicator::before {\n opacity: 0;\n transition: opacity var(--wui-duration-press, 80ms) ease;\n}\n\n/* 按压/拖拽时 thumb 转为玻璃态:静止态关掉的玻璃输出在这一态全部打开——backdrop blur、\n ::before 描边环、inset 高光,投影叠加更实一档并放大 1.5x。\n 底色全透明:轨道实体化后 thumb 的采样面拿到的是均匀实色(条纹底实测内部 std 归零),\n 本体可感知性由实色轨道与 1.5x 放大/环/投影共同承担,不再需要 tint 打底,也不需要\n 为采样痕迹去压制轨道的边缘装饰——那些按压态特判已全部移除,轨道装饰全状态恒定。\n transition 不含 background-color:按下即落到全透明,不产生灰→透明的插值中间帧;\n 松开回到静止态规则,由那里的 background-color 过渡把透明平滑淡回实体底。\n backdrop-filter 直接写死值(与 drawer/dialog/toast 的玻璃态同法):静止态是 none,\n glass 配方由这一态自己声明,不随 .wui-glass 类是否挂载而变;该属性同样不进 transition,\n 理由见静止态规则上方的说明。\n box-shadow 直接写死值(不经 --wui-internal-glass-shadow 中转):iOS Safari 对 var\n 离散切换驱动的 box-shadow 不触发过渡且可能整体不生效(slider thumb 同法),直接写值\n 后是普通属性变化,transition 正常插值;三条 inset 高光复制自 .wui-glass,避免整段\n 覆盖后按压态丢失玻璃描边。 */\n.wui-segmented.is-pressed .wui-segmented-indicator,\n.wui-segmented.is-dragging .wui-segmented-indicator {\n transform: scale(1.5);\n\n background-color: transparent;\n backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n box-shadow:\n inset 0 0 0 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 38%, transparent),\n inset 0 1px 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 52%, transparent),\n inset 0 -0.5px 1px rgb(0 0 0 / 0.03),\n 0 2px 20px rgb(0 0 0 / 0.2);\n\n transition:\n transform var(--wui-duration-press, 80ms) cubic-bezier(0.4, 0, 0.2, 1),\n box-shadow var(--wui-duration-press, 80ms) ease;\n}\n\n/* 按压/拖拽才绘制玻璃描边环,环随 opacity 过渡淡入。 */\n.wui-segmented.is-pressed .wui-segmented-indicator::before,\n.wui-segmented.is-dragging .wui-segmented-indicator::before {\n opacity: 1;\n}\n\n.wui-segmented.is-dragging:not(.is-disabled) {\n --wui-internal-segmented-trigger-cursor: grabbing;\n cursor: grabbing;\n}\n"],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/components/segmented-trigger/style.css?inline
|
|
2
|
-
var e = "*,:before,:after{box-sizing:border-box}:host{--wui-segmented-trigger-bg-hover:var(--wui-color-state-layer-hover,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent));--wui-segmented-trigger-bg-active:var(--wui-color-state-layer-active,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent));touch-action:none;display:inline-block}:host([disabled]){cursor:not-allowed}.wui-segmented-trigger{cursor:var(--wui-internal-segmented-trigger-cursor,default);-webkit-user-select:none;user-select:none;z-index:1;height:calc(var(--wui-control-size,36px) - 8px);padding:0 var(--wui-segmented-trigger-px,12px);border-radius:var(--wui-radius-control,calc(infinity * 1px));font-size:var(--wui-font-size,14px);color:var(--wui-color-text-secondary,#6a6a6a);white-space:nowrap;transition:color var(--wui-duration-focus,.2s) ease;background-color:#0000;justify-content:center;align-items:center;line-height:1;display:inline-flex;position:relative}.wui-segmented-trigger:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}
|
|
2
|
+
var e = "*,:before,:after{box-sizing:border-box}:host{--wui-segmented-trigger-bg-hover:var(--wui-color-state-layer-hover,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, transparent));--wui-segmented-trigger-bg-active:var(--wui-color-state-layer-active,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, transparent));touch-action:none;display:inline-block}:host([disabled]){cursor:not-allowed}.wui-segmented-trigger{cursor:var(--wui-internal-segmented-trigger-cursor,default);-webkit-user-select:none;user-select:none;z-index:1;height:calc(var(--wui-control-size,36px) - 8px);padding:0 var(--wui-segmented-trigger-px,12px);border-radius:var(--wui-radius-control,calc(infinity * 1px));font-size:var(--wui-font-size,14px);color:var(--wui-color-text-secondary,#6a6a6a);white-space:nowrap;transition:color var(--wui-duration-focus,.2s) ease;background-color:#0000;justify-content:center;align-items:center;line-height:1;display:inline-flex;position:relative}.wui-segmented-trigger:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}@media (hover:hover) and (pointer:fine){.wui-segmented-trigger:hover:not(.is-checked,.is-disabled){background-color:var(--wui-segmented-trigger-bg-hover)}}.wui-segmented-trigger:active:not(.is-checked,.is-disabled){background-color:var(--wui-segmented-trigger-bg-active)}.wui-segmented-trigger.is-disabled{cursor:not-allowed;opacity:.4}:host([data-wui-pointer-focus]) .wui-segmented-trigger:focus-visible{outline-color:#0000}";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { e as default };
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/segmented-trigger/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-segmented-trigger-bg-hover: var(\n --wui-color-state-layer-hover,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent)\n );\n --wui-segmented-trigger-bg-active: var(\n --wui-color-state-layer-active,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent)\n );\n touch-action: none;\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\n.wui-segmented-trigger {\n cursor: var(--wui-internal-segmented-trigger-cursor, default);\n user-select: none;\n\n position: relative;\n z-index: 1;\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n height: calc(var(--wui-control-size, 36px) - 8px);\n padding: 0 var(--wui-segmented-trigger-px, 12px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1;\n color: var(--wui-color-text-secondary, #6a6a6a);\n white-space: nowrap;\n\n background-color: transparent;\n\n transition: color var(--wui-duration-focus, 200ms) ease;\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/segmented-trigger/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-segmented-trigger-bg-hover: var(\n --wui-color-state-layer-hover,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, transparent)\n );\n --wui-segmented-trigger-bg-active: var(\n --wui-color-state-layer-active,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, transparent)\n );\n touch-action: none;\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n}\n\n.wui-segmented-trigger {\n cursor: var(--wui-internal-segmented-trigger-cursor, default);\n user-select: none;\n\n position: relative;\n z-index: 1;\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n height: calc(var(--wui-control-size, 36px) - 8px);\n padding: 0 var(--wui-segmented-trigger-px, 12px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size, 14px);\n line-height: 1;\n\n /* 选中与未选中同档灰:区分度只由玻璃指示器承担,未选中项无底色。 */\n color: var(--wui-color-text-secondary, #6a6a6a);\n white-space: nowrap;\n\n background-color: transparent;\n\n transition: color var(--wui-duration-focus, 200ms) ease;\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n }\n}\n\n@media (hover: hover) and (pointer: fine) {\n /* state layer 只服务未选中项:选中项的按压/悬停反馈由玻璃指示器(thumb)承载,\n 已选中项再叠一层 6%/15% 灰底会盖在透明玻璃 thumb 之上(trigger z-index: 1 >\n thumb z-index: 0),按住已选项到拖拽结束前 :active 一直不撤,整段手势都是\n 「灰底蒙在玻璃上」——即 #150「灰底在 thumb 层」要消除的残留。 */\n .wui-segmented-trigger:hover:not(.is-checked, .is-disabled) {\n background-color: var(--wui-segmented-trigger-bg-hover);\n }\n}\n\n.wui-segmented-trigger:active:not(.is-checked, .is-disabled) {\n background-color: var(--wui-segmented-trigger-bg-active);\n}\n\n.wui-segmented-trigger.is-disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n:host([data-wui-pointer-focus]) .wui-segmented-trigger:focus-visible {\n outline-color: transparent;\n}\n"],"mappings":""}
|
|
@@ -389,6 +389,7 @@ export declare class WebUiSelect extends WebUiSelect_base {
|
|
|
389
389
|
private readonly _scrollLock;
|
|
390
390
|
private static _nextInstanceId;
|
|
391
391
|
private readonly _optionPortal;
|
|
392
|
+
private readonly _overlay;
|
|
392
393
|
private readonly _panel;
|
|
393
394
|
get isOpen(): boolean;
|
|
394
395
|
get open(): boolean;
|
|
@@ -401,6 +402,7 @@ export declare class WebUiSelect extends WebUiSelect_base {
|
|
|
401
402
|
updated(changed: PropertyValues): void;
|
|
402
403
|
private _syncValidity;
|
|
403
404
|
private _syncOpenAttribute;
|
|
405
|
+
private _syncOverlayInert;
|
|
404
406
|
private _onTriggerSlotChange;
|
|
405
407
|
private _syncSelected;
|
|
406
408
|
private readonly _optionListeners;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
2
2
|
import "../icon/index.js";
|
|
3
|
-
import t from "../../
|
|
4
|
-
import "
|
|
5
|
-
import
|
|
6
|
-
import r from "../../assets/overlay-motion.js";
|
|
3
|
+
import t from "../../assets/glass.js";
|
|
4
|
+
import n from "../../icons/generated/lucide-chevron-down.js";
|
|
5
|
+
import { installPointerFocusSuppression as r } from "../../shared/focus/pointer-focus.js";
|
|
7
6
|
import { FormAssociated as i, FormAssociationController as a, defineFormAssociation as o } from "../../shared/form-association/index.js";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
7
|
+
import "../option/index.js";
|
|
8
|
+
import s from "../../assets/overlay-motion.js";
|
|
9
|
+
import { dispatchOpenChangeEvent as c } from "../../shared/open-state/index.js";
|
|
10
10
|
import { createComboboxOpenController as l, createOptionListenerBinding as u, handleComboboxFocusOut as d, nextWrappingIndex as f } from "../../shared/option-portal/combobox-shell.js";
|
|
11
11
|
import { defineOptionPortal as p } from "../../shared/option-portal/index.js";
|
|
12
12
|
import { defineAnchoredPanel as m } from "../../shared/overlay/anchored-panel.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
13
|
+
import { defineOpenOverlay as h } from "../../shared/overlay/open-overlay.js";
|
|
14
|
+
import { applyOverlayVariables as g, defineOverlayPortal as _ } from "../../shared/overlay/portal.js";
|
|
15
|
+
import { defineScrollLockLease as v } from "../../shared/scroll-lock/scroll-lock.js";
|
|
16
16
|
import y from "./style.js";
|
|
17
17
|
import { LitElement as b, html as x, nothing as S, unsafeCSS as C } from "lit";
|
|
18
18
|
import { customElement as w, property as T, state as E } from "lit/decorators.js";
|
|
19
19
|
//#region src/components/select/index.ts
|
|
20
20
|
var D;
|
|
21
|
-
|
|
21
|
+
r();
|
|
22
22
|
var O = class extends i(b) {
|
|
23
23
|
static {
|
|
24
24
|
D = this;
|
|
@@ -40,7 +40,7 @@ var O = class extends i(b) {
|
|
|
40
40
|
typeof e == "string" && (this.value = e);
|
|
41
41
|
},
|
|
42
42
|
syncValidity: () => this._syncValidity()
|
|
43
|
-
}).make(), this._formAssociationController = new a(this, this._formAssociation), this._isOpen = !1, this._activeIndex = -1, this._selectedLabel = "", this._hasTriggerSlot = !1, this._options = [], this._scrollLock =
|
|
43
|
+
}).make(), this._formAssociationController = new a(this, this._formAssociation), this._isOpen = !1, this._activeIndex = -1, this._selectedLabel = "", this._hasTriggerSlot = !1, this._options = [], this._scrollLock = v().make(), this._optionPortal = p().make({
|
|
44
44
|
element: this,
|
|
45
45
|
idPrefix: `web-ui-select-${++D._nextInstanceId}`,
|
|
46
46
|
getPortal: () => this._portal,
|
|
@@ -54,6 +54,9 @@ var O = class extends i(b) {
|
|
|
54
54
|
onImmediateSync: () => {
|
|
55
55
|
this._refreshOptions(), this._syncSelected(), this._syncActiveOption();
|
|
56
56
|
}
|
|
57
|
+
}), this._overlay = h().make({
|
|
58
|
+
requestClose: () => this._close(),
|
|
59
|
+
isConnected: () => this.isConnected
|
|
57
60
|
}), this._panel = m().make({
|
|
58
61
|
getAnchor: () => this.shadowRoot?.querySelector(".select-trigger") ?? null,
|
|
59
62
|
getLocalPanel: () => this.shadowRoot?.querySelector(".select-overlay") ?? null,
|
|
@@ -64,12 +67,13 @@ var O = class extends i(b) {
|
|
|
64
67
|
strategy: this.portal ? "fixed" : "absolute"
|
|
65
68
|
}),
|
|
66
69
|
isPortal: () => this.portal,
|
|
67
|
-
createPortal: () => this._createPortal()
|
|
70
|
+
createPortal: () => this._createPortal(),
|
|
71
|
+
openOverlay: this._overlay
|
|
68
72
|
}), this._onClickOutside = (e) => {
|
|
69
|
-
let t =
|
|
70
|
-
this._isOpen && !
|
|
73
|
+
let t = e.composedPath().includes(this) || !!this._panel.getHandle()?.containsEvent(e);
|
|
74
|
+
this._isOpen && !t && this._close();
|
|
71
75
|
}, this._onFocusOut = () => {
|
|
72
|
-
d(this, () => this._panel.
|
|
76
|
+
d(this, () => this._panel.getHandle(), () => this._isOpen, () => this._close());
|
|
73
77
|
}, this._onTriggerSlotChange = (e) => {
|
|
74
78
|
let t = e.target.assignedElements().length > 0;
|
|
75
79
|
this._hasTriggerSlot !== t && (this._hasTriggerSlot = t, this._reconfigureOverlay());
|
|
@@ -92,9 +96,6 @@ var O = class extends i(b) {
|
|
|
92
96
|
this._optionPortal.scheduleRefresh();
|
|
93
97
|
}, this._onKeydown = (e) => {
|
|
94
98
|
if (!this._isDisabled) switch (e.key) {
|
|
95
|
-
case "Escape":
|
|
96
|
-
this._isOpen && (this._close(), e.preventDefault());
|
|
97
|
-
break;
|
|
98
99
|
case "ArrowDown":
|
|
99
100
|
e.preventDefault(), this._isOpen ? this._navigateActive(1) : this._open(!0);
|
|
100
101
|
break;
|
|
@@ -127,8 +128,8 @@ var O = class extends i(b) {
|
|
|
127
128
|
}
|
|
128
129
|
static {
|
|
129
130
|
this.styles = [
|
|
130
|
-
C(
|
|
131
|
-
C(
|
|
131
|
+
C(t),
|
|
132
|
+
C(s),
|
|
132
133
|
C(y)
|
|
133
134
|
];
|
|
134
135
|
}
|
|
@@ -166,7 +167,7 @@ var O = class extends i(b) {
|
|
|
166
167
|
this._refreshOptions(), this._syncSelected();
|
|
167
168
|
}
|
|
168
169
|
updated(e) {
|
|
169
|
-
(e.has("portal") || e.has("overlayContainer")) && requestAnimationFrame(() => this._reconfigureOverlay()), e.has("noScrollLock") && this._syncScrollLock(), this._syncOpenAttribute(), this._syncValidity();
|
|
170
|
+
(e.has("portal") || e.has("overlayContainer")) && requestAnimationFrame(() => this._reconfigureOverlay()), e.has("noScrollLock") && this._syncScrollLock(), this._syncOpenAttribute(), this._syncOverlayInert(), this._syncValidity();
|
|
170
171
|
}
|
|
171
172
|
_syncValidity() {
|
|
172
173
|
let e = this._formAssociation.getInternals();
|
|
@@ -175,6 +176,9 @@ var O = class extends i(b) {
|
|
|
175
176
|
_syncOpenAttribute() {
|
|
176
177
|
this.toggleAttribute("open", this._isOpen);
|
|
177
178
|
}
|
|
179
|
+
_syncOverlayInert() {
|
|
180
|
+
this._panel.getHandle()?.setInert(this._isDisabled);
|
|
181
|
+
}
|
|
178
182
|
_syncSelected() {
|
|
179
183
|
if (this._options.forEach((e) => {
|
|
180
184
|
e.selected = e.value === this.value;
|
|
@@ -206,7 +210,7 @@ var O = class extends i(b) {
|
|
|
206
210
|
this._openController.close();
|
|
207
211
|
}
|
|
208
212
|
_dispatchOpenChange() {
|
|
209
|
-
|
|
213
|
+
c(this, this._isOpen);
|
|
210
214
|
}
|
|
211
215
|
_setInitialActiveOption() {
|
|
212
216
|
let e = this._options.findIndex((e) => e.value === this.value && !e.disabled && this._isLive(e)), t = this._options.findIndex((e) => !e.disabled && this._isLive(e));
|
|
@@ -231,34 +235,34 @@ var O = class extends i(b) {
|
|
|
231
235
|
this._isDisabled || (this._isOpen ? this._close() : this._open());
|
|
232
236
|
}
|
|
233
237
|
_openOverlay(e = !1) {
|
|
234
|
-
this._panel.open(e);
|
|
238
|
+
this._panel.open(e), this._syncOverlayInert();
|
|
235
239
|
}
|
|
236
240
|
_createPortal() {
|
|
237
|
-
let e =
|
|
241
|
+
let e = _().make({
|
|
238
242
|
container: this.overlayContainer,
|
|
239
243
|
target: this,
|
|
240
|
-
style: `${
|
|
244
|
+
style: `${t}\n${s}\n${y}`,
|
|
241
245
|
className: "wui-glass select-overlay portal wui-floating-panel",
|
|
242
246
|
onContentChange: () => this._optionPortal.scheduleRefresh()
|
|
243
247
|
});
|
|
244
|
-
this._portal = e,
|
|
248
|
+
this._portal = e, g(e.panel, this, [
|
|
245
249
|
"--wui-overlay-min-width",
|
|
246
250
|
"--wui-select-max-width",
|
|
247
251
|
"--wui-select-max-height"
|
|
248
252
|
]), e.panel.setAttribute("role", "listbox");
|
|
249
|
-
let
|
|
250
|
-
|
|
251
|
-
let
|
|
252
|
-
return
|
|
253
|
+
let n = document.createElement("div");
|
|
254
|
+
n.className = "select-scroll";
|
|
255
|
+
let r = document.createElement("div");
|
|
256
|
+
return r.className = "select-content", this._portalContent = r, n.append(r), e.panel.append(n), e.moveContent(Array.from(this.children).filter((e) => e.slot !== "trigger"), r), e;
|
|
253
257
|
}
|
|
254
258
|
_reconfigureOverlay() {
|
|
255
|
-
this._portal = void 0, this._portalContent = void 0, this._panel.reconfigure(this._isOpen);
|
|
259
|
+
this._portal = void 0, this._portalContent = void 0, this._panel.reconfigure(this._isOpen), this._syncOverlayInert();
|
|
256
260
|
}
|
|
257
261
|
async _closeOverlay() {
|
|
258
262
|
await this._panel.close(() => this._isOpen) && (this._portal = void 0, this._portalContent = void 0);
|
|
259
263
|
}
|
|
260
264
|
render() {
|
|
261
|
-
let e = `${this.localName}-listbox`,
|
|
265
|
+
let e = `${this.localName}-listbox`, t = !this.portal && this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex]?.id ?? S : S;
|
|
262
266
|
return x`
|
|
263
267
|
<div class="wui-select-inner">
|
|
264
268
|
<div
|
|
@@ -271,11 +275,11 @@ var O = class extends i(b) {
|
|
|
271
275
|
aria-haspopup="listbox"
|
|
272
276
|
aria-controls=${this.portal ? S : e}
|
|
273
277
|
aria-disabled=${String(this._isDisabled)}
|
|
274
|
-
aria-activedescendant=${
|
|
278
|
+
aria-activedescendant=${t}
|
|
275
279
|
>
|
|
276
280
|
<slot name="trigger" @slotchange=${this._onTriggerSlotChange}></slot>
|
|
277
281
|
${this._hasTriggerSlot ? S : x`<span class="label">${this._selectedLabel}</span>`}
|
|
278
|
-
<web-ui-icon class="arrow" .icon=${
|
|
282
|
+
<web-ui-icon class="arrow" .icon=${n}></web-ui-icon>
|
|
279
283
|
</div>
|
|
280
284
|
<div class="select-overlay wui-floating-panel wui-glass" hidden role="listbox" id=${e}>
|
|
281
285
|
<div class="select-scroll">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/select/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/icon'\nimport '@/components/option'\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport type { WebUiOption } from '@/components/option'\nimport { lucideChevronDown } from '@/icons'\nimport { installPointerFocusSuppression } from '@/shared/focus/pointer-focus'\nimport { FormAssociated, defineFormAssociation, FormAssociationController } from '@/shared/form-association'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport {\n createComboboxOpenController,\n createOptionListenerBinding,\n handleComboboxFocusOut,\n nextWrappingIndex\n} from '@/shared/option-portal'\nimport { defineOptionPortal } from '@/shared/option-portal'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { overlayComposition } from '@/shared/overlay/composition'\nimport { applyOverlayVariables, defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\ninstallPointerFocusSuppression()\n\n@customElement('web-ui-select')\nexport class WebUiSelect extends FormAssociated(LitElement) {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n @property({ type: String, reflect: true }) name = ''\n\n // value 使用内部状态 + 访问器模式,在变更时同步 ElementInternals;\n // @property + reflect 让它与 input/textarea/slider/input-number 的 value 反射语义保持一致。\n @state() private _value = ''\n @property({ type: String, reflect: true })\n get value(): string {\n return this._value\n }\n set value(v: string) {\n const old = this._value\n this._value = v\n this._formAssociation.sync()\n this.toggleAttribute('data-has-value', !!v)\n this.requestUpdate('value', old)\n }\n\n private readonly _formAssociation = defineFormAssociation<string>({\n host: this,\n initialize: () => {\n // 同步 HTML 属性中预设的 value,补全访问器模式不处理 attribute 反射。\n const attrValue = this.getAttribute('value')\n if (attrValue !== null) {\n this._value = attrValue\n this.toggleAttribute('data-has-value', !!attrValue)\n }\n },\n getState: () => this._value,\n setState: value => {\n this.value = value\n },\n getFormValue: () => this._value,\n getFormState: () => this._value,\n restoreState: state => {\n if (typeof state === 'string') this.value = state\n },\n syncValidity: () => this._syncValidity()\n }).make()\n\n private readonly _formAssociationController = new FormAssociationController(this, this._formAssociation)\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formAssociation.isFormDisabled()\n }\n\n @state() private _isOpen = false\n @state() private _activeIndex = -1\n @state() private _selectedLabel = ''\n @state() private _hasTriggerSlot = false\n\n private _options: WebUiOption[] = []\n private _portal?: OverlayPortal\n private _portalContent?: HTMLElement\n private readonly _scrollLock = defineScrollLockLease().make()\n\n private static _nextInstanceId = 0\n\n // option 注册表 / portal 同步 / 微任务调度收敛到 shared 模块(autocomplete 同款)\n private readonly _optionPortal = defineOptionPortal().make({\n element: this,\n // 实例级前缀保证多实例同时展开时 option id 不冲突(aria 引用按 id 定位)\n idPrefix: `web-ui-select-${++WebUiSelect._nextInstanceId}`,\n getPortal: () => this._portal,\n getPortalContent: () => this._portalContent,\n isOpen: () => this.portal && this._isOpen,\n getMigratableNodes: () => [...this.querySelectorAll<WebUiOption>('web-ui-option')],\n hasUpdated: () => this.hasUpdated,\n requestUpdate: () => this.requestUpdate(),\n bindOption: option => this._bindOption(option),\n unbindOption: option => this._unbindOption(option),\n onImmediateSync: () => {\n this._refreshOptions()\n this._syncSelected()\n this._syncActiveOption()\n }\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.select-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.select-overlay') ?? null,\n getPositioning: () => ({\n placement: 'bottom-start',\n offset: 4,\n // 面板宽度统一为 max(内容, trigger, --wui-overlay-min-width),内容自适应展开\n minAnchorWidth: true,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal()\n })\n\n get isOpen(): boolean {\n return this._isOpen\n }\n\n get open(): boolean {\n return this._isOpen\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n const panel = this._panel.getPanel()\n const isInside = e.composedPath().includes(this) || (panel && overlayComposition.containsEvent(panel, e))\n if (this._isOpen && !isInside) {\n this._close()\n }\n }\n\n private _onFocusOut = () => {\n handleComboboxFocusOut(\n this,\n () => this._panel.getPanel(),\n () => this._isOpen,\n () => this._close()\n )\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._optionPortal.bindHost()\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n document.addEventListener('click', this._onClickOutside)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._optionPortal.dispose()\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('focusout', this._onFocusOut)\n document.removeEventListener('click', this._onClickOutside)\n this._options.forEach(this._unbindOption)\n this._options = []\n this._portal = undefined\n this._portalContent = undefined\n this._close()\n this._panel.dispose()\n this._scrollLock.release()\n }\n\n override firstUpdated() {\n requestAnimationFrame(() => {\n if (this.isConnected) this._optionPortal.scheduleRefresh()\n })\n }\n\n override willUpdate() {\n this._refreshOptions()\n this._syncSelected()\n }\n\n override updated(changed: PropertyValues) {\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n if (changed.has('noScrollLock')) this._syncScrollLock()\n this._syncOpenAttribute()\n this._syncValidity()\n }\n\n private _syncValidity() {\n const internals = this._formAssociation.getInternals()\n if (!internals || typeof internals.setValidity !== 'function') return\n if (this._isDisabled || !this.required || this.value) internals.setValidity({})\n else internals.setValidity({ valueMissing: true }, '请选择一项')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n private _onTriggerSlotChange = (e: Event) => {\n const slot = e.target as HTMLSlotElement\n const hasContent = slot.assignedElements().length > 0\n if (this._hasTriggerSlot === hasContent) return\n this._hasTriggerSlot = hasContent\n this._reconfigureOverlay()\n }\n\n private _syncSelected() {\n this._options.forEach(o => {\n o.selected = o.value === this.value\n })\n if (!this.value) {\n this._selectedLabel = this.placeholder\n return\n }\n const option = this._options.find(o => o.value === this.value)\n this._selectedLabel = option?.label || this.placeholder\n }\n\n private readonly _optionListeners = createOptionListenerBinding({\n // 惰性解引用:handler 字段声明在后者仍可在调用期取到\n onClick: event => this._handleOptionClick(event),\n onPointerOver: event => this._handleOptionPointerOver(event),\n onPointerDown: event => this._handleOptionPointerDown(event),\n onUpdate: () => this._onOptionUpdate()\n })\n private _bindOption = (option: WebUiOption) => this._optionListeners.bind(option)\n private _unbindOption = (option: WebUiOption) => this._optionListeners.unbind(option)\n\n private _refreshOptions() {\n const activeOption = this._options[this._activeIndex]\n // diff 绑定/解绑与激活索引按 option 身份保持在 shared 内完成,\n // 避免移除中间项后激活静默偏移到相邻项\n const next = this._optionPortal.refresh(this._options, activeOption)\n this._options = next.options\n this._activeIndex = next.activeIndex\n // 非 portal 模式 aria-activedescendant 引用真实 option id,需保证已分配\n this._optionPortal.ensureOptionIds(this._options)\n }\n\n private _handleOptionClick = (e: Event) => {\n if (!(e.currentTarget instanceof HTMLElement)) return\n const option = e.currentTarget as WebUiOption\n if (option.disabled || !this._isLive(option)) return\n this.value = option.value\n this._close()\n this._notifyValueChange()\n }\n\n private _onOptionUpdate = () => {\n this._syncSelected()\n this._syncActiveOption()\n }\n\n private _handleOptionPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (!this._isOpen || this._activeIndex < 0 || !(e.currentTarget instanceof HTMLElement)) return\n\n // 指针接管后只保留 :hover,避免键盘激活项与悬停项同时高亮。\n this._activeIndex = -1\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持 trigger 焦点,避免 focusout 在 click 前关闭浮层。\n e.preventDefault()\n }\n\n // slotchange 不冒泡,只能由模板内 slot 自行监听;稳定引用避免 Lit 重挂载\n private _onSlotChange = () => {\n this._optionPortal.scheduleRefresh()\n }\n\n // slotchange/unregister 的刷新依赖 Lit 渲染调度;键盘或 click 事件可能先于其触发,\n // 已从 DOM 移除或被移出 Select/portal 面板的选项不得再被激活或选中。\n private _isLive(option: WebUiOption): boolean {\n const panel = this.portal ? this._panel.getPanel() : null\n return option.isConnected && (this.contains(option) || (!!panel && panel.contains(option)))\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this._isDisabled) return\n\n switch (e.key) {\n case 'Escape':\n if (this._isOpen) {\n this._close()\n e.preventDefault()\n }\n break\n case 'ArrowDown':\n e.preventDefault()\n if (!this._isOpen) {\n this._open(true)\n } else {\n this._navigateActive(1)\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n if (!this._isOpen) this._open(true)\n else this._navigateActive(-1)\n break\n case 'Enter': {\n if (this._isOpen && this._activeIndex >= 0) {\n const option = this._options[this._activeIndex]\n if (option && this._isLive(option) && !option.disabled) {\n this.value = option.value\n this._notifyValueChange()\n }\n this._close()\n e.preventDefault()\n }\n break\n }\n }\n }\n\n private _navigateActive(delta: number) {\n const enabled = this._options.filter(o => !o.disabled && this._isLive(o))\n if (!enabled.length) return\n\n const selectedOption = this._options.find(\n option => option.value === this.value && !option.disabled && this._isLive(option)\n )\n const currentIdx =\n this._activeIndex >= 0 && this._isLive(this._options[this._activeIndex])\n ? enabled.indexOf(this._options[this._activeIndex])\n : selectedOption\n ? enabled.indexOf(selectedOption)\n : delta > 0\n ? -1\n : 0\n const nextOption = enabled[nextWrappingIndex(enabled.length, currentIdx, delta)]\n this._activeIndex = this._options.indexOf(nextOption)\n\n this._syncActiveOption()\n }\n\n // 开合生命周期不变量(guard / 派发顺序 / scroll-lock 配对 / portal rAF dance)\n // 收敛在 shared combobox-shell;select 只注入差异点\n private readonly _openController = createComboboxOpenController({\n canOpen: () => !this._isDisabled,\n getIsOpen: () => this._isOpen,\n setIsOpen: open => {\n this._isOpen = open\n },\n dispatchOpenChange: () => this._dispatchOpenChange(),\n syncScrollLock: open => this._syncScrollLock(open),\n isPortal: () => this.portal,\n openOverlay: isKeyboardNavigation => this._openOverlay(isKeyboardNavigation),\n closeOverlay: () => void this._closeOverlay(),\n onOpen: isKeyboardNavigation => {\n this._syncSelected()\n if (isKeyboardNavigation) this._setInitialActiveOption()\n else this._syncActiveOption()\n },\n onAfterClose: () => {\n this._activeIndex = -1\n this._options.forEach(o => o.removeAttribute('active'))\n }\n })\n\n private _open(isKeyboardNavigation = false) {\n this._openController.open(isKeyboardNavigation)\n }\n\n private _close() {\n this._openController.close()\n }\n\n private _dispatchOpenChange() {\n dispatchOpenChangeEvent(this, this._isOpen)\n }\n\n private _setInitialActiveOption() {\n const selectedIndex = this._options.findIndex(\n option => option.value === this.value && !option.disabled && this._isLive(option)\n )\n const firstEnabledIndex = this._options.findIndex(option => !option.disabled && this._isLive(option))\n this._activeIndex = selectedIndex >= 0 ? selectedIndex : firstEnabledIndex\n this._syncActiveOption()\n }\n\n private _syncActiveOption() {\n this._options.forEach((option, index) =>\n option.toggleAttribute('active', index === this._activeIndex && this._isLive(option))\n )\n }\n\n private _notifyValueChange() {\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _togglePopup() {\n if (this._isDisabled) return\n if (this._isOpen) this._close()\n else this._open()\n }\n\n private _openOverlay(isKeyboardNavigation = false) {\n this._panel.open(isKeyboardNavigation)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'wui-glass select-overlay portal wui-floating-panel',\n onContentChange: () => this._optionPortal.scheduleRefresh()\n })\n this._portal = portal\n applyOverlayVariables(portal.panel, this, [\n '--wui-overlay-min-width',\n '--wui-select-max-width',\n '--wui-select-max-height'\n ])\n portal.panel.setAttribute('role', 'listbox')\n const scroll = document.createElement('div')\n scroll.className = 'select-scroll'\n const content = document.createElement('div')\n content.className = 'select-content'\n this._portalContent = content\n scroll.append(content)\n portal.panel.append(scroll)\n // 自定义 trigger 必须留在宿主内,不能随 options 迁入 portal 面板\n portal.moveContent(\n Array.from(this.children).filter(child => child.slot !== 'trigger'),\n content\n )\n return portal\n }\n\n private _reconfigureOverlay() {\n // reconfigure 会 dispose 并按需重建 portal,旧引用必须同步失效\n this._portal = undefined\n this._portalContent = undefined\n this._panel.reconfigure(this._isOpen)\n }\n\n private async _closeOverlay() {\n const closed = await this._panel.close(() => this._isOpen)\n // portal 已随关闭 dispose,与 autocomplete 对齐同步失效引用\n if (closed) {\n this._portal = undefined\n this._portalContent = undefined\n }\n }\n\n override render() {\n // portal 模式下 options 被 moveContent 移入浮层 shadow root,id 引用无法跨树作用域\n // 解析,因此 activedescendant 仅在非 portal 模式输出;aria-controls 同理指向同根内 listbox\n const listboxId = `${this.localName}-listbox`\n const activeDescendant =\n !this.portal && this._isOpen && this._activeIndex >= 0\n ? (this._options[this._activeIndex]?.id ?? nothing)\n : nothing\n\n return html`\n <div class=\"wui-select-inner\">\n <div\n class=\"wui-glass select-trigger\"\n ?data-custom-trigger=${this._hasTriggerSlot}\n @click=${this._togglePopup}\n tabindex=${this._isDisabled ? '-1' : '0'}\n role=\"combobox\"\n aria-expanded=${this._isOpen}\n aria-haspopup=\"listbox\"\n aria-controls=${this.portal ? nothing : listboxId}\n aria-disabled=${String(this._isDisabled)}\n aria-activedescendant=${activeDescendant}\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n ${!this._hasTriggerSlot ? html`<span class=\"label\">${this._selectedLabel}</span>` : nothing}\n <web-ui-icon class=\"arrow\" .icon=${lucideChevronDown}></web-ui-icon>\n </div>\n <div class=\"select-overlay wui-floating-panel wui-glass\" hidden role=\"listbox\" id=${listboxId}>\n <div class=\"select-scroll\">\n <div class=\"select-content\">\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n </div>\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-select': WebUiSelect\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/select/index.ts"],"sourcesContent":["import { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/icon'\nimport '@/components/option'\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport type { WebUiOption } from '@/components/option'\nimport { lucideChevronDown } from '@/icons'\nimport { installPointerFocusSuppression } from '@/shared/focus/pointer-focus'\nimport { FormAssociated, defineFormAssociation, FormAssociationController } from '@/shared/form-association'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport {\n createComboboxOpenController,\n createOptionListenerBinding,\n handleComboboxFocusOut,\n nextWrappingIndex\n} from '@/shared/option-portal'\nimport { defineOptionPortal } from '@/shared/option-portal'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { applyOverlayVariables, defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\ninstallPointerFocusSuppression()\n\n@customElement('web-ui-select')\nexport class WebUiSelect extends FormAssociated(LitElement) {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n @property({ type: String, reflect: true }) name = ''\n\n // value 使用内部状态 + 访问器模式,在变更时同步 ElementInternals;\n // @property + reflect 让它与 input/textarea/slider/input-number 的 value 反射语义保持一致。\n @state() private _value = ''\n @property({ type: String, reflect: true })\n get value(): string {\n return this._value\n }\n set value(v: string) {\n const old = this._value\n this._value = v\n this._formAssociation.sync()\n this.toggleAttribute('data-has-value', !!v)\n this.requestUpdate('value', old)\n }\n\n private readonly _formAssociation = defineFormAssociation<string>({\n host: this,\n initialize: () => {\n // 同步 HTML 属性中预设的 value,补全访问器模式不处理 attribute 反射。\n const attrValue = this.getAttribute('value')\n if (attrValue !== null) {\n this._value = attrValue\n this.toggleAttribute('data-has-value', !!attrValue)\n }\n },\n getState: () => this._value,\n setState: value => {\n this.value = value\n },\n getFormValue: () => this._value,\n getFormState: () => this._value,\n restoreState: state => {\n if (typeof state === 'string') this.value = state\n },\n syncValidity: () => this._syncValidity()\n }).make()\n\n private readonly _formAssociationController = new FormAssociationController(this, this._formAssociation)\n\n private get _isDisabled(): boolean {\n return this.disabled || this._formAssociation.isFormDisabled()\n }\n\n @state() private _isOpen = false\n @state() private _activeIndex = -1\n @state() private _selectedLabel = ''\n @state() private _hasTriggerSlot = false\n\n private _options: WebUiOption[] = []\n private _portal?: OverlayPortal\n private _portalContent?: HTMLElement\n private readonly _scrollLock = defineScrollLockLease().make()\n\n private static _nextInstanceId = 0\n\n // option 注册表 / portal 同步 / 微任务调度收敛到 shared 模块(autocomplete 同款)\n private readonly _optionPortal = defineOptionPortal().make({\n element: this,\n // 实例级前缀保证多实例同时展开时 option id 不冲突(aria 引用按 id 定位)\n idPrefix: `web-ui-select-${++WebUiSelect._nextInstanceId}`,\n getPortal: () => this._portal,\n getPortalContent: () => this._portalContent,\n isOpen: () => this.portal && this._isOpen,\n getMigratableNodes: () => [...this.querySelectorAll<WebUiOption>('web-ui-option')],\n hasUpdated: () => this.hasUpdated,\n requestUpdate: () => this.requestUpdate(),\n bindOption: option => this._bindOption(option),\n unbindOption: option => this._unbindOption(option),\n onImmediateSync: () => {\n this._refreshOptions()\n this._syncSelected()\n this._syncActiveOption()\n }\n })\n /*\n * 开启态浮层承载「我开着吗」(issue #120 Block 1):本组件不再在 keydown 里自行关闭,\n * 只声明「我开着」。宿主级监听在 portal 模式下收不到面板内的 Escape,正是原实现的\n * 缺陷来源;改由唯一仲裁者在 document 捕获阶段判定最内层。\n *\n * 宿主接口除 requestClose 外只再提供一个 isConnected(仅供惰性回收读取):开启状态是\n * 声明而非询问,仲裁时不再回头问 isOpen()。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._close(),\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.select-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.select-overlay') ?? null,\n getPositioning: () => ({\n placement: 'bottom-start',\n offset: 4,\n // 面板宽度统一为 max(内容, trigger, --wui-overlay-min-width),内容自适应展开\n minAnchorWidth: true,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal(),\n openOverlay: this._overlay\n })\n\n get isOpen(): boolean {\n return this._isOpen\n }\n\n get open(): boolean {\n return this._isOpen\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n // 在监听器内部判定:composedPath() 在派发结束后会被清空。\n const isInside = e.composedPath().includes(this) || !!this._panel.getHandle()?.containsEvent(e)\n if (this._isOpen && !isInside) {\n this._close()\n }\n }\n\n private _onFocusOut = () => {\n handleComboboxFocusOut(\n this,\n () => this._panel.getHandle(),\n () => this._isOpen,\n () => this._close()\n )\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._optionPortal.bindHost()\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n document.addEventListener('click', this._onClickOutside)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._optionPortal.dispose()\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('focusout', this._onFocusOut)\n document.removeEventListener('click', this._onClickOutside)\n this._options.forEach(this._unbindOption)\n this._options = []\n this._portal = undefined\n this._portalContent = undefined\n this._close()\n // 撤销登记由 _panel.dispose() 完成(句柄归它持有),不再需要单独 dispose 仲裁者。\n this._panel.dispose()\n this._scrollLock.release()\n }\n\n override firstUpdated() {\n requestAnimationFrame(() => {\n if (this.isConnected) this._optionPortal.scheduleRefresh()\n })\n }\n\n override willUpdate() {\n this._refreshOptions()\n this._syncSelected()\n }\n\n override updated(changed: PropertyValues) {\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n if (changed.has('noScrollLock')) this._syncScrollLock()\n this._syncOpenAttribute()\n this._syncOverlayInert()\n this._syncValidity()\n }\n\n private _syncValidity() {\n const internals = this._formAssociation.getInternals()\n if (!internals || typeof internals.setValidity !== 'function') return\n if (this._isDisabled || !this.required || this.value) internals.setValidity({})\n else internals.setValidity({ valueMissing: true }, '请选择一项')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n /*\n * 禁用态不响应 Escape。仲裁者仍在(吞掉按键并压掉原生 cancel),只是不走关闭入口\n * —— 与旧的「跳过候选」语义不同:旧语义放任事件落到下层浮层,把外层一起关掉。\n * 每次渲染后同步即可覆盖 disabled 属性与表单禁用两条来源。\n */\n private _syncOverlayInert() {\n this._panel.getHandle()?.setInert(this._isDisabled)\n }\n\n private _onTriggerSlotChange = (e: Event) => {\n const slot = e.target as HTMLSlotElement\n const hasContent = slot.assignedElements().length > 0\n if (this._hasTriggerSlot === hasContent) return\n this._hasTriggerSlot = hasContent\n this._reconfigureOverlay()\n }\n\n private _syncSelected() {\n this._options.forEach(o => {\n o.selected = o.value === this.value\n })\n if (!this.value) {\n this._selectedLabel = this.placeholder\n return\n }\n const option = this._options.find(o => o.value === this.value)\n this._selectedLabel = option?.label || this.placeholder\n }\n\n private readonly _optionListeners = createOptionListenerBinding({\n // 惰性解引用:handler 字段声明在后者仍可在调用期取到\n onClick: event => this._handleOptionClick(event),\n onPointerOver: event => this._handleOptionPointerOver(event),\n onPointerDown: event => this._handleOptionPointerDown(event),\n onUpdate: () => this._onOptionUpdate()\n })\n private _bindOption = (option: WebUiOption) => this._optionListeners.bind(option)\n private _unbindOption = (option: WebUiOption) => this._optionListeners.unbind(option)\n\n private _refreshOptions() {\n const activeOption = this._options[this._activeIndex]\n // diff 绑定/解绑与激活索引按 option 身份保持在 shared 内完成,\n // 避免移除中间项后激活静默偏移到相邻项\n const next = this._optionPortal.refresh(this._options, activeOption)\n this._options = next.options\n this._activeIndex = next.activeIndex\n // 非 portal 模式 aria-activedescendant 引用真实 option id,需保证已分配\n this._optionPortal.ensureOptionIds(this._options)\n }\n\n private _handleOptionClick = (e: Event) => {\n if (!(e.currentTarget instanceof HTMLElement)) return\n const option = e.currentTarget as WebUiOption\n if (option.disabled || !this._isLive(option)) return\n this.value = option.value\n this._close()\n this._notifyValueChange()\n }\n\n private _onOptionUpdate = () => {\n this._syncSelected()\n this._syncActiveOption()\n }\n\n private _handleOptionPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (!this._isOpen || this._activeIndex < 0 || !(e.currentTarget instanceof HTMLElement)) return\n\n // 指针接管后只保留 :hover,避免键盘激活项与悬停项同时高亮。\n this._activeIndex = -1\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持 trigger 焦点,避免 focusout 在 click 前关闭浮层。\n e.preventDefault()\n }\n\n // slotchange 不冒泡,只能由模板内 slot 自行监听;稳定引用避免 Lit 重挂载\n private _onSlotChange = () => {\n this._optionPortal.scheduleRefresh()\n }\n\n // slotchange/unregister 的刷新依赖 Lit 渲染调度;键盘或 click 事件可能先于其触发,\n // 已从 DOM 移除或被移出 Select/portal 面板的选项不得再被激活或选中。\n private _isLive(option: WebUiOption): boolean {\n const panel = this.portal ? this._panel.getPanel() : null\n return option.isConnected && (this.contains(option) || (!!panel && panel.contains(option)))\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this._isDisabled) return\n\n // Escape 不在本组件处理:由共享仲裁者在 document 捕获阶段归属(issue #120 Block 1)。\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!this._isOpen) {\n this._open(true)\n } else {\n this._navigateActive(1)\n }\n break\n case 'ArrowUp':\n e.preventDefault()\n if (!this._isOpen) this._open(true)\n else this._navigateActive(-1)\n break\n case 'Enter': {\n if (this._isOpen && this._activeIndex >= 0) {\n const option = this._options[this._activeIndex]\n if (option && this._isLive(option) && !option.disabled) {\n this.value = option.value\n this._notifyValueChange()\n }\n this._close()\n e.preventDefault()\n }\n break\n }\n }\n }\n\n private _navigateActive(delta: number) {\n const enabled = this._options.filter(o => !o.disabled && this._isLive(o))\n if (!enabled.length) return\n\n const selectedOption = this._options.find(\n option => option.value === this.value && !option.disabled && this._isLive(option)\n )\n const currentIdx =\n this._activeIndex >= 0 && this._isLive(this._options[this._activeIndex])\n ? enabled.indexOf(this._options[this._activeIndex])\n : selectedOption\n ? enabled.indexOf(selectedOption)\n : delta > 0\n ? -1\n : 0\n const nextOption = enabled[nextWrappingIndex(enabled.length, currentIdx, delta)]\n this._activeIndex = this._options.indexOf(nextOption)\n\n this._syncActiveOption()\n }\n\n // 开合生命周期不变量(guard / 派发顺序 / scroll-lock 配对 / portal rAF dance)\n // 收敛在 shared combobox-shell;select 只注入差异点\n private readonly _openController = createComboboxOpenController({\n canOpen: () => !this._isDisabled,\n getIsOpen: () => this._isOpen,\n setIsOpen: open => {\n this._isOpen = open\n },\n dispatchOpenChange: () => this._dispatchOpenChange(),\n syncScrollLock: open => this._syncScrollLock(open),\n isPortal: () => this.portal,\n openOverlay: isKeyboardNavigation => this._openOverlay(isKeyboardNavigation),\n closeOverlay: () => void this._closeOverlay(),\n onOpen: isKeyboardNavigation => {\n this._syncSelected()\n if (isKeyboardNavigation) this._setInitialActiveOption()\n else this._syncActiveOption()\n },\n onAfterClose: () => {\n this._activeIndex = -1\n this._options.forEach(o => o.removeAttribute('active'))\n }\n })\n\n private _open(isKeyboardNavigation = false) {\n this._openController.open(isKeyboardNavigation)\n }\n\n private _close() {\n this._openController.close()\n }\n\n private _dispatchOpenChange() {\n dispatchOpenChangeEvent(this, this._isOpen)\n }\n\n private _setInitialActiveOption() {\n const selectedIndex = this._options.findIndex(\n option => option.value === this.value && !option.disabled && this._isLive(option)\n )\n const firstEnabledIndex = this._options.findIndex(option => !option.disabled && this._isLive(option))\n this._activeIndex = selectedIndex >= 0 ? selectedIndex : firstEnabledIndex\n this._syncActiveOption()\n }\n\n private _syncActiveOption() {\n this._options.forEach((option, index) =>\n option.toggleAttribute('active', index === this._activeIndex && this._isLive(option))\n )\n }\n\n private _notifyValueChange() {\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _togglePopup() {\n if (this._isDisabled) return\n if (this._isOpen) this._close()\n else this._open()\n }\n\n private _openOverlay(isKeyboardNavigation = false) {\n this._panel.open(isKeyboardNavigation)\n // 新会话的句柄刚建立,惰性状态需按当前 disabled 重新同步。\n this._syncOverlayInert()\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'wui-glass select-overlay portal wui-floating-panel',\n onContentChange: () => this._optionPortal.scheduleRefresh()\n })\n this._portal = portal\n applyOverlayVariables(portal.panel, this, [\n '--wui-overlay-min-width',\n '--wui-select-max-width',\n '--wui-select-max-height'\n ])\n portal.panel.setAttribute('role', 'listbox')\n const scroll = document.createElement('div')\n scroll.className = 'select-scroll'\n const content = document.createElement('div')\n content.className = 'select-content'\n this._portalContent = content\n scroll.append(content)\n portal.panel.append(scroll)\n // 自定义 trigger 必须留在宿主内,不能随 options 迁入 portal 面板\n portal.moveContent(\n Array.from(this.children).filter(child => child.slot !== 'trigger'),\n content\n )\n return portal\n }\n\n private _reconfigureOverlay() {\n // reconfigure 会 dispose 并按需重建 portal,旧引用必须同步失效\n this._portal = undefined\n this._portalContent = undefined\n this._panel.reconfigure(this._isOpen)\n /*\n * reconfigure 重新 claim = 新会话,inert 回到 false。实测这条重推是**冗余**的(摘掉本行\n * 全部用例仍绿):这条路径后面跟着一轮渲染,而 `updated()` 每次渲染都会调\n * `_syncOverlayInert()`。留在这里是不想依赖「这条路径必然跟着一次渲染」这个隐含前提。\n */\n this._syncOverlayInert()\n }\n\n private async _closeOverlay() {\n const closed = await this._panel.close(() => this._isOpen)\n // portal 已随关闭 dispose,与 autocomplete 对齐同步失效引用\n if (closed) {\n this._portal = undefined\n this._portalContent = undefined\n }\n }\n\n override render() {\n // portal 模式下 options 被 moveContent 移入浮层 shadow root,id 引用无法跨树作用域\n // 解析,因此 activedescendant 仅在非 portal 模式输出;aria-controls 同理指向同根内 listbox\n const listboxId = `${this.localName}-listbox`\n const activeDescendant =\n !this.portal && this._isOpen && this._activeIndex >= 0\n ? (this._options[this._activeIndex]?.id ?? nothing)\n : nothing\n\n return html`\n <div class=\"wui-select-inner\">\n <div\n class=\"wui-glass select-trigger\"\n ?data-custom-trigger=${this._hasTriggerSlot}\n @click=${this._togglePopup}\n tabindex=${this._isDisabled ? '-1' : '0'}\n role=\"combobox\"\n aria-expanded=${this._isOpen}\n aria-haspopup=\"listbox\"\n aria-controls=${this.portal ? nothing : listboxId}\n aria-disabled=${String(this._isDisabled)}\n aria-activedescendant=${activeDescendant}\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n ${!this._hasTriggerSlot ? html`<span class=\"label\">${this._selectedLabel}</span>` : nothing}\n <web-ui-icon class=\"arrow\" .icon=${lucideChevronDown}></web-ui-icon>\n </div>\n <div class=\"select-overlay wui-floating-panel wui-glass\" hidden role=\"listbox\" id=${listboxId}>\n <div class=\"select-scroll\">\n <div class=\"select-content\">\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n </div>\n </div>\n </div>\n `\n }\n\n declare readonly $events: {\n input: Event\n change: Event\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-select': WebUiSelect\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import e from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
2
2
|
import t from "../../assets/glass.js";
|
|
3
|
-
import {
|
|
4
|
-
import { normalizeNumber as
|
|
5
|
-
import {
|
|
3
|
+
import { installPointerFocusSuppression as n } from "../../shared/focus/pointer-focus.js";
|
|
4
|
+
import { normalizeNumber as r } from "../../shared/normalize/index.js";
|
|
5
|
+
import { FormAssociated as i, FormAssociationController as a, defineFormAssociation as o } from "../../shared/form-association/index.js";
|
|
6
6
|
import { attachDragGesture as s } from "../../shared/gesture/drag-gesture.js";
|
|
7
7
|
import { clamp as c } from "../../shared/gesture/physics.js";
|
|
8
8
|
import l from "./style.js";
|
|
@@ -11,10 +11,10 @@ import { customElement as p, property as m, state as h } from "lit/decorators.js
|
|
|
11
11
|
import { classMap as g } from "lit/directives/class-map.js";
|
|
12
12
|
import { styleMap as _ } from "lit/directives/style-map.js";
|
|
13
13
|
//#region src/components/slider/index.ts
|
|
14
|
-
|
|
15
|
-
var v = class extends
|
|
14
|
+
n();
|
|
15
|
+
var v = class extends i(u) {
|
|
16
16
|
constructor(...e) {
|
|
17
|
-
super(...e), this.disabled = !1, this.marks = !1, this.vertical = !1, this.name = "", this.required = !1, this._value = 0, this._min = 0, this._max = 100, this._step = 1, this._dragging = !1, this._pressed = !1, this._dragGestureHandle = null, this._formAssociation =
|
|
17
|
+
super(...e), this.disabled = !1, this.marks = !1, this.vertical = !1, this.name = "", this.required = !1, this._value = 0, this._min = 0, this._max = 100, this._step = 1, this._dragging = !1, this._pressed = !1, this._dragGestureHandle = null, this._formAssociation = o({
|
|
18
18
|
host: this,
|
|
19
19
|
initialize: () => {
|
|
20
20
|
this._value = this._normalizeValue(this._value);
|
|
@@ -33,7 +33,7 @@ var v = class extends n(u) {
|
|
|
33
33
|
syncValidity: (e) => {
|
|
34
34
|
typeof e.setValidity == "function" && e.setValidity({});
|
|
35
35
|
}
|
|
36
|
-
}).make(), this._formAssociationController = new
|
|
36
|
+
}).make(), this._formAssociationController = new a(this, this._formAssociation);
|
|
37
37
|
}
|
|
38
38
|
static {
|
|
39
39
|
this.styles = [f(t), f(l)];
|
|
@@ -42,26 +42,26 @@ var v = class extends n(u) {
|
|
|
42
42
|
return this._value;
|
|
43
43
|
}
|
|
44
44
|
set value(e) {
|
|
45
|
-
let t =
|
|
45
|
+
let t = r(e, -Infinity, Infinity, 0), n = this._value;
|
|
46
46
|
this._value = t, this._formAssociation.sync(), this.requestUpdate("value", n);
|
|
47
47
|
}
|
|
48
48
|
get min() {
|
|
49
49
|
return this._min;
|
|
50
50
|
}
|
|
51
51
|
set min(e) {
|
|
52
|
-
this._min =
|
|
52
|
+
this._min = r(e, -Infinity, Infinity, 0);
|
|
53
53
|
}
|
|
54
54
|
get max() {
|
|
55
55
|
return this._max;
|
|
56
56
|
}
|
|
57
57
|
set max(e) {
|
|
58
|
-
this._max =
|
|
58
|
+
this._max = r(e, -Infinity, Infinity, 100);
|
|
59
59
|
}
|
|
60
60
|
get step() {
|
|
61
61
|
return this._step;
|
|
62
62
|
}
|
|
63
63
|
set step(e) {
|
|
64
|
-
this._step =
|
|
64
|
+
this._step = r(e, -Infinity, Infinity, 1);
|
|
65
65
|
}
|
|
66
66
|
disconnectedCallback() {
|
|
67
67
|
super.disconnectedCallback(), this._dragGestureHandle?.destroy(), this._dragGestureHandle = null;
|