@greypan/web-ui 12.0.1 → 12.2.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 +4 -0
- package/README.md +4 -0
- package/dist/assets/menu-portal.js +1 -1
- package/dist/assets/menu-portal.js.map +1 -1
- package/dist/assets/toast-containers.js +1 -1
- package/dist/assets/toast-containers.js.map +1 -1
- package/dist/components/autocomplete/index.d.ts +5 -0
- package/dist/components/autocomplete/index.d.ts.map +1 -1
- package/dist/components/autocomplete/index.js +18 -2
- 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/back-top/style.js +1 -1
- package/dist/components/back-top/style.js.map +1 -1
- package/dist/components/button-group/style.js +1 -1
- package/dist/components/button-group/style.js.map +1 -1
- package/dist/components/dialog/index.d.ts +5 -1
- package/dist/components/dialog/index.d.ts.map +1 -1
- package/dist/components/dialog/index.js +16 -4
- 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 +11 -0
- package/dist/components/drawer/index.d.ts.map +1 -1
- package/dist/components/drawer/index.js +23 -1
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/page-shift.js +113 -0
- package/dist/components/drawer/page-shift.js.map +1 -0
- package/dist/components/dropdown/index.js +1 -1
- package/dist/components/grouped-text/grouping.d.ts +25 -0
- package/dist/components/grouped-text/grouping.d.ts.map +1 -0
- package/dist/components/grouped-text/grouping.js +147 -0
- package/dist/components/grouped-text/grouping.js.map +1 -0
- package/dist/components/grouped-text/index.d.ts +36 -0
- package/dist/components/grouped-text/index.d.ts.map +1 -0
- package/dist/components/grouped-text/index.js +28 -0
- package/dist/components/grouped-text/index.js.map +1 -0
- package/dist/components/grouped-text/style.js +5 -0
- package/dist/components/grouped-text/style.js.map +1 -0
- package/dist/components/icon/index.d.ts +1 -1
- package/dist/components/icon/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +6 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -1
- package/dist/components/layout/index.d.ts +8 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +24 -13
- 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/middle-ellipsis/index.js +1 -1
- package/dist/components/popover/index.d.ts +5 -2
- package/dist/components/popover/index.d.ts.map +1 -1
- package/dist/components/popover/index.js +32 -21
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/popover/style.js +1 -1
- package/dist/components/popover/style.js.map +1 -1
- package/dist/components/progress/index.d.ts +30 -0
- package/dist/components/progress/index.d.ts.map +1 -0
- package/dist/components/progress/index.js +103 -0
- package/dist/components/progress/index.js.map +1 -0
- package/dist/components/progress/style.js +5 -0
- package/dist/components/progress/style.js.map +1 -0
- package/dist/components/segmented-trigger/index.d.ts +2 -0
- package/dist/components/segmented-trigger/index.d.ts.map +1 -1
- package/dist/components/segmented-trigger/index.js +7 -0
- package/dist/components/segmented-trigger/index.js.map +1 -1
- package/dist/components/select/index.d.ts +13 -0
- package/dist/components/select/index.d.ts.map +1 -1
- package/dist/components/select/index.js +41 -3
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/select/style.js +1 -1
- package/dist/components/select/style.js.map +1 -1
- package/dist/components/shake/index.d.ts +43 -0
- package/dist/components/shake/index.d.ts.map +1 -0
- package/dist/components/shake/index.js +103 -0
- package/dist/components/shake/index.js.map +1 -0
- package/dist/components/spinner/index.d.ts +0 -3
- package/dist/components/spinner/index.d.ts.map +1 -1
- package/dist/components/spinner/index.js +5 -20
- package/dist/components/spinner/index.js.map +1 -1
- package/dist/components/spinner/style.js +1 -1
- package/dist/components/spinner/style.js.map +1 -1
- package/dist/components/theme/style.js +1 -1
- package/dist/components/theme/style.js.map +1 -1
- package/dist/components/tooltip/index.d.ts +8 -0
- package/dist/components/tooltip/index.d.ts.map +1 -1
- package/dist/components/tooltip/index.js +60 -10
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/components/tooltip/style.js +1 -1
- package/dist/components/tooltip/style.js.map +1 -1
- package/dist/icons/generated/ant-design-sync-outlined.d.ts +7 -0
- package/dist/icons/generated/ant-design-sync-outlined.d.ts.map +1 -0
- package/dist/icons/generated/ant-design-sync-outlined.js +9 -0
- package/dist/icons/generated/ant-design-sync-outlined.js.map +1 -0
- package/dist/icons/generated/ic-baseline-phonelink.d.ts +7 -0
- package/dist/icons/generated/ic-baseline-phonelink.d.ts.map +1 -0
- package/dist/icons/generated/ic-baseline-phonelink.js +9 -0
- package/dist/icons/generated/ic-baseline-phonelink.js.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.d.ts +7 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.d.ts.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.js +9 -0
- package/dist/icons/generated/ic-outline-motion-photos-off.js.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.d.ts +7 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.d.ts.map +1 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.js +9 -0
- package/dist/icons/generated/ic-outline-motion-photos-on.js.map +1 -0
- package/dist/icons/generated/ic-round-menu-open.d.ts +7 -0
- package/dist/icons/generated/ic-round-menu-open.d.ts.map +1 -0
- package/dist/icons/generated/ic-round-menu-open.js +9 -0
- package/dist/icons/generated/ic-round-menu-open.js.map +1 -0
- package/dist/icons/generated/lucide-accessibility.d.ts +7 -0
- package/dist/icons/generated/lucide-accessibility.d.ts.map +1 -0
- package/dist/icons/generated/lucide-accessibility.js +9 -0
- package/dist/icons/generated/lucide-accessibility.js.map +1 -0
- package/dist/icons/generated/lucide-boxes.d.ts +7 -0
- package/dist/icons/generated/lucide-boxes.d.ts.map +1 -0
- package/dist/icons/generated/lucide-boxes.js +9 -0
- package/dist/icons/generated/lucide-boxes.js.map +1 -0
- package/dist/icons/generated/lucide-contrast.d.ts +7 -0
- package/dist/icons/generated/lucide-contrast.d.ts.map +1 -0
- package/dist/icons/generated/lucide-contrast.js +9 -0
- package/dist/icons/generated/lucide-contrast.js.map +1 -0
- package/dist/icons/generated/lucide-keyboard.d.ts +7 -0
- package/dist/icons/generated/lucide-keyboard.d.ts.map +1 -0
- package/dist/icons/generated/lucide-keyboard.js +9 -0
- package/dist/icons/generated/lucide-keyboard.js.map +1 -0
- package/dist/icons/generated/lucide-languages.d.ts +7 -0
- package/dist/icons/generated/lucide-languages.d.ts.map +1 -0
- package/dist/icons/generated/lucide-languages.js +9 -0
- package/dist/icons/generated/lucide-languages.js.map +1 -0
- package/dist/icons/generated/lucide-list.d.ts +7 -0
- package/dist/icons/generated/lucide-list.d.ts.map +1 -0
- package/dist/icons/generated/lucide-list.js +9 -0
- package/dist/icons/generated/lucide-list.js.map +1 -0
- package/dist/icons/generated/lucide-moon.d.ts +7 -0
- package/dist/icons/generated/lucide-moon.d.ts.map +1 -0
- package/dist/icons/generated/lucide-moon.js +9 -0
- package/dist/icons/generated/lucide-moon.js.map +1 -0
- package/dist/icons/generated/lucide-sparkles.d.ts +7 -0
- package/dist/icons/generated/lucide-sparkles.d.ts.map +1 -0
- package/dist/icons/generated/lucide-sparkles.js +9 -0
- package/dist/icons/generated/lucide-sparkles.js.map +1 -0
- package/dist/icons/generated/lucide-sun.d.ts +7 -0
- package/dist/icons/generated/lucide-sun.d.ts.map +1 -0
- package/dist/icons/generated/lucide-sun.js +9 -0
- package/dist/icons/generated/lucide-sun.js.map +1 -0
- package/dist/icons/generated/tabler-brand-typescript.d.ts +7 -0
- package/dist/icons/generated/tabler-brand-typescript.d.ts.map +1 -0
- package/dist/icons/generated/tabler-brand-typescript.js +9 -0
- package/dist/icons/generated/tabler-brand-typescript.js.map +1 -0
- package/dist/icons/index.d.ts +87 -72
- package/dist/icons/index.js +16 -1
- package/dist/shared/locale/builtin-labels.js +2 -1
- package/dist/shared/locale/builtin-labels.js.map +1 -1
- package/dist/shared/overlay/anchored-panel.js +2 -2
- package/dist/shared/overlay/anchored-panel.js.map +1 -1
- package/dist/shared/overlay/presence.js +2 -2
- package/dist/shared/overlay/presence.js.map +1 -1
- package/dist/shared/overlay/trigger-props.d.ts +10 -0
- package/dist/shared/overlay/trigger-props.d.ts.map +1 -0
- package/dist/shared/overlay/trigger-props.js +42 -0
- package/dist/shared/overlay/trigger-props.js.map +1 -0
- package/package.json +4 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["style"],"sources":["../../../src/components/segmented-trigger/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\n\nimport { installPointerFocusSuppression } from '@/shared/focus/pointer-focus'\nimport { defineGroupManaged, selectionGroupContextKey, type SelectionGroupContext } from '@/shared/group-management'\n\nimport style from './style.css?inline'\n\ninstallPointerFocusSuppression()\n\n@customElement('web-ui-segmented-trigger')\nexport class WebUiSegmentedTrigger extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: String }) value = ''\n @property({ type: Boolean, reflect: true }) checked = false\n @property({ type: Boolean, reflect: true }) disabled = false\n\n private readonly _groupManagement = defineGroupManaged<SelectionGroupContext>(this, {\n context: selectionGroupContextKey,\n requestUpdate: () => this.requestUpdate(),\n equals: (a, b) => a?.disabled === b?.disabled && a?.tabStop === b?.tabStop\n }).make()\n\n private get _isDisabled(): boolean {\n return this.disabled || this._groupManagement.getContext()?.disabled === true\n }\n\n private get _isManagedByGroup(): boolean {\n return this._groupManagement.getContext() !== undefined\n }\n\n private handleClick() {\n if (this._isDisabled || this.checked) return\n this.checked = true\n // group-managed 时事件不冒泡/不组合,由 segmented 统一派发一次 host 事件\n const opts: EventInit = this._isManagedByGroup\n ? { bubbles: false, composed: false }\n : { bubbles: true, composed: true }\n this.dispatchEvent(new Event('change', opts))\n }\n\n private handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.handleClick()\n }\n }\n\n override render() {\n const cls = {\n 'wui-segmented-trigger': true,\n 'is-checked': this.checked,\n 'is-disabled': this._isDisabled\n }\n\n return html`\n <div\n class=${classMap(cls)}\n tabindex=${this._isDisabled || this._groupManagement.getContext()?.tabStop === false ? '-1' : '0'}\n role=\"option\"\n aria-selected=${String(this.checked)}\n aria-disabled=${String(this._isDisabled)}\n @click=${this.handleClick}\n @keydown=${this.handleKeyDown}\n >\n <slot></slot>\n </div>\n `\n }\n\n declare readonly $events: {\n change: Event\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-segmented-trigger': WebUiSegmentedTrigger\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":["style"],"sources":["../../../src/components/segmented-trigger/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { installPointerFocusSuppression } from '@/shared/focus/pointer-focus'\nimport { defineGroupManaged, selectionGroupContextKey, type SelectionGroupContext } from '@/shared/group-management'\n\nimport style from './style.css?inline'\n\ninstallPointerFocusSuppression()\n\n@customElement('web-ui-segmented-trigger')\nexport class WebUiSegmentedTrigger extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: String }) value = ''\n @property({ type: Boolean, reflect: true }) checked = false\n @property({ type: Boolean, reflect: true }) disabled = false\n /** 纯图标 trigger 的可访问名;会转发到内部 `role=\"option\"`。 */\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n\n private readonly _groupManagement = defineGroupManaged<SelectionGroupContext>(this, {\n context: selectionGroupContextKey,\n requestUpdate: () => this.requestUpdate(),\n equals: (a, b) => a?.disabled === b?.disabled && a?.tabStop === b?.tabStop\n }).make()\n\n private get _isDisabled(): boolean {\n return this.disabled || this._groupManagement.getContext()?.disabled === true\n }\n\n private get _isManagedByGroup(): boolean {\n return this._groupManagement.getContext() !== undefined\n }\n\n private handleClick() {\n if (this._isDisabled || this.checked) return\n this.checked = true\n // group-managed 时事件不冒泡/不组合,由 segmented 统一派发一次 host 事件\n const opts: EventInit = this._isManagedByGroup\n ? { bubbles: false, composed: false }\n : { bubbles: true, composed: true }\n this.dispatchEvent(new Event('change', opts))\n }\n\n private handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.handleClick()\n }\n }\n\n override render() {\n const cls = {\n 'wui-segmented-trigger': true,\n 'is-checked': this.checked,\n 'is-disabled': this._isDisabled\n }\n\n return html`\n <div\n class=${classMap(cls)}\n tabindex=${this._isDisabled || this._groupManagement.getContext()?.tabStop === false ? '-1' : '0'}\n role=\"option\"\n aria-label=${ifDefined(this.ariaLabel ?? undefined)}\n aria-selected=${String(this.checked)}\n aria-disabled=${String(this._isDisabled)}\n @click=${this.handleClick}\n @keydown=${this.handleKeyDown}\n >\n <slot></slot>\n </div>\n `\n }\n\n declare readonly $events: {\n change: Event\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-segmented-trigger': WebUiSegmentedTrigger\n }\n}\n"],"mappings":";;;;;;;;;AAUA,+BAA+B;AAGxB,IAAM,wBAAN,MAAM,8BAA8B,WAAW;;;EAGhB,KAAA,QAAA;EACkB,KAAA,UAAA;EACC,KAAA,WAAA;EAEkC,KAAA,YAAA;EAErD,KAAA,mBAAA,mBAA0C,MAAM;GAClF,SAAS;GACT,qBAAqB,KAAK,cAAc;GACxC,SAAS,GAAG,MAAM,GAAG,aAAa,GAAG,YAAY,GAAG,YAAY,GAAG;EACrE,CAAC,CAAC,CAAC,KAAK;;;EAZiB,KAAA,SAAA,UAAUA,aAAK;;CAcxC,IAAY,cAAuB;EACjC,OAAO,KAAK,YAAY,KAAK,iBAAiB,WAAW,CAAC,EAAE,aAAa;CAC3E;CAEA,IAAY,oBAA6B;EACvC,OAAO,KAAK,iBAAiB,WAAW,MAAM,KAAA;CAChD;CAEA,cAAsB;EACpB,IAAI,KAAK,eAAe,KAAK,SAAS;EACtC,KAAK,UAAU;EAEf,MAAM,OAAkB,KAAK,oBACzB;GAAE,SAAS;GAAO,UAAU;EAAM,IAClC;GAAE,SAAS;GAAM,UAAU;EAAK;EACpC,KAAK,cAAc,IAAI,MAAM,UAAU,IAAI,CAAC;CAC9C;CAEA,cAAsB,GAAkB;EACtC,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;GACtC,EAAE,eAAe;GACjB,KAAK,YAAY;EACnB;CACF;CAEA,SAAkB;EAChB,MAAM,MAAM;GACV,yBAAyB;GACzB,cAAc,KAAK;GACnB,eAAe,KAAK;EACtB;EAEA,OAAO,IAAI;;gBAEC,SAAS,GAAG,EAAE;mBACX,KAAK,eAAe,KAAK,iBAAiB,WAAW,CAAC,EAAE,YAAY,QAAQ,OAAO,IAAI;;qBAErF,UAAU,KAAK,aAAa,KAAA,CAAS,EAAE;wBACpC,OAAO,KAAK,OAAO,EAAE;wBACrB,OAAO,KAAK,WAAW,EAAE;iBAChC,KAAK,YAAY;mBACf,KAAK,cAAc;;;;;CAKpC;AAKF;AA/DG,WAAA,CAAA,SAAS,EAAE,MAAM,OAAO,CAAC,CAAA,GAAA,sBAAA,WAAA,SAAA,KAAA,CAAA;AACzB,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,sBAAA,WAAA,WAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,sBAAA,WAAA,YAAA,KAAA,CAAA;AAEzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,sBAAA,WAAA,aAAA,KAAA,CAAA;AARpD,wBAAA,WAAA,CAAA,cAAc,0BAA0B,CAAA,GAAA,qBAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../icon/index.js";
|
|
2
2
|
import { OverlayContainer } from "../../shared/overlay/portal.js";
|
|
3
3
|
import { LitElement, PropertyValues } from "lit";
|
|
4
|
+
import { Placement } from "@floating-ui/dom";
|
|
4
5
|
declare const WebUiSelect_base: {
|
|
5
6
|
new (...args: any[]): {
|
|
6
7
|
formResetCallback(): void;
|
|
@@ -369,8 +370,20 @@ export declare class WebUiSelect extends WebUiSelect_base {
|
|
|
369
370
|
static styles: import("lit").CSSResult[];
|
|
370
371
|
placeholder: string;
|
|
371
372
|
disabled: boolean;
|
|
373
|
+
/**
|
|
374
|
+
* 触发器外观:`label` 为默认的带选中文本与箭头;`icon` 保留右侧箭头,只把 `trigger` slot
|
|
375
|
+
* 的内容换成左侧图标区——带 trigger slot 时触发器贴合内容宽度,高度不变。
|
|
376
|
+
* 图标模式需要消费方提供 `trigger` slot 与 `aria-label`。
|
|
377
|
+
*/
|
|
378
|
+
get trigger(): 'label' | 'icon';
|
|
379
|
+
set trigger(v: string);
|
|
380
|
+
private _trigger;
|
|
372
381
|
required: boolean;
|
|
373
382
|
portal: boolean;
|
|
383
|
+
/** 下拉 panel 相对触发器的方向;默认贴着触发器左下角向下展开。 */
|
|
384
|
+
get placement(): Placement;
|
|
385
|
+
set placement(v: string);
|
|
386
|
+
private _placement;
|
|
374
387
|
noScrollLock: boolean;
|
|
375
388
|
overlayContainer?: OverlayContainer;
|
|
376
389
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/select/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/select/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuCa,oBAAoB;SACf,sBAAM;EAEqB;EACC;;;;;;MAQxC;MAGA,QAAQ;UAKJ;EACoC;EACA;;MAGxC,aAAa;MAGb,UAAU;UAKN;EACiE;EACzC,mBAAmB;EACR;EAGmB;UAI7C;MAEb;MAGA,MAAM;mBAQO;mBAsBA;cAEL;UAIK;UACA;UACA;UACA;UAET;UACA;UAEA;UACA;UACA;mBACS;iBAEF;mBAGE;mBA0BA;mBAIA;MAeb;MAIA;UAII;UAQA;EASC;EAQA;EAgBA;EAMA;EAKA,QAAQ,SAAS;UAUlB;UAOA;UASA;UAIA;UAQA;mBAgBS;UAOT;UACA;UAEA;UAWA;UASA;UAKA;UAUA;UAMA;UAMA;UAKA;UAqDA;UASA;UAUA;UAyCA;UAIA;mBAwBS;UAsBT;UAKA;UAKA;UAKA;UAIA;UASA;UAMA;UAKA;UAIA;UAMA;UAMA;UA8BA;UAaM;EASL,wBAAM;WA0CE;IACf,OAAO;IACP,QAAQ;IACR,eAAe;MAAc;;;;QAIzB;YACI;IACR,iBAAiB"}
|
|
@@ -4,6 +4,7 @@ import glass_default from "../../classes/glass.js";
|
|
|
4
4
|
import lucide_chevron_down_default from "../../icons/generated/lucide-chevron-down.js";
|
|
5
5
|
import { installPointerFocusSuppression } from "../../shared/focus/pointer-focus.js";
|
|
6
6
|
import { FormAssociated, FormAssociationController, defineFormAssociation } from "../../shared/form-association/index.js";
|
|
7
|
+
import { normalizeLiteral } from "../../shared/normalize/index.js";
|
|
7
8
|
import overlay_motion_default from "../../assets/overlay-motion.js";
|
|
8
9
|
import scrollbar_default from "../../assets/scrollbar.js";
|
|
9
10
|
import { dispatchOpenChangeEvent } from "../../shared/open-state/index.js";
|
|
@@ -11,6 +12,7 @@ import { createComboboxOpenController, createOptionListenerBinding, handleCombob
|
|
|
11
12
|
import { defineOptionPortal } from "../../shared/option-portal/index.js";
|
|
12
13
|
import { defineAnchoredPanel } from "../../shared/overlay/anchored-panel.js";
|
|
13
14
|
import { defineOpenOverlay } from "../../shared/overlay/open-overlay.js";
|
|
15
|
+
import { FLOATING_PLACEMENTS } from "../../shared/overlay/placement-props.js";
|
|
14
16
|
import { applyOverlayVariables, defineOverlayPortal } from "../../shared/overlay/portal.js";
|
|
15
17
|
import { defineScrollLockLease } from "../../shared/scroll-lock/scroll-lock.js";
|
|
16
18
|
import style_default from "./style.js";
|
|
@@ -28,8 +30,10 @@ let WebUiSelect = class WebUiSelect extends FormAssociated(LitElement) {
|
|
|
28
30
|
super(..._args);
|
|
29
31
|
this.placeholder = "";
|
|
30
32
|
this.disabled = false;
|
|
33
|
+
this._trigger = "label";
|
|
31
34
|
this.required = false;
|
|
32
35
|
this.portal = false;
|
|
36
|
+
this._placement = "bottom-start";
|
|
33
37
|
this.noScrollLock = false;
|
|
34
38
|
this.name = "";
|
|
35
39
|
this.ariaLabel = null;
|
|
@@ -88,7 +92,7 @@ let WebUiSelect = class WebUiSelect extends FormAssociated(LitElement) {
|
|
|
88
92
|
getAnchor: () => this.shadowRoot?.querySelector(".select-trigger") ?? null,
|
|
89
93
|
getLocalPanel: () => this.shadowRoot?.querySelector(".select-overlay") ?? null,
|
|
90
94
|
getPositioning: () => ({
|
|
91
|
-
placement:
|
|
95
|
+
placement: this.placement,
|
|
92
96
|
offset: 4,
|
|
93
97
|
minAnchorWidth: true,
|
|
94
98
|
strategy: this.portal ? "fixed" : "absolute"
|
|
@@ -216,6 +220,28 @@ let WebUiSelect = class WebUiSelect extends FormAssociated(LitElement) {
|
|
|
216
220
|
unsafeCSS(style_default)
|
|
217
221
|
];
|
|
218
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* 触发器外观:`label` 为默认的带选中文本与箭头;`icon` 保留右侧箭头,只把 `trigger` slot
|
|
225
|
+
* 的内容换成左侧图标区——带 trigger slot 时触发器贴合内容宽度,高度不变。
|
|
226
|
+
* 图标模式需要消费方提供 `trigger` slot 与 `aria-label`。
|
|
227
|
+
*/
|
|
228
|
+
get trigger() {
|
|
229
|
+
return this._trigger;
|
|
230
|
+
}
|
|
231
|
+
set trigger(v) {
|
|
232
|
+
const old = this._trigger;
|
|
233
|
+
this._trigger = normalizeLiteral(v, ["label", "icon"], "label");
|
|
234
|
+
this.requestUpdate("trigger", old);
|
|
235
|
+
}
|
|
236
|
+
/** 下拉 panel 相对触发器的方向;默认贴着触发器左下角向下展开。 */
|
|
237
|
+
get placement() {
|
|
238
|
+
return this._placement;
|
|
239
|
+
}
|
|
240
|
+
set placement(v) {
|
|
241
|
+
const old = this._placement;
|
|
242
|
+
this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, "bottom-start");
|
|
243
|
+
this.requestUpdate("placement", old);
|
|
244
|
+
}
|
|
219
245
|
get value() {
|
|
220
246
|
return this._value;
|
|
221
247
|
}
|
|
@@ -271,6 +297,7 @@ let WebUiSelect = class WebUiSelect extends FormAssociated(LitElement) {
|
|
|
271
297
|
updated(changed) {
|
|
272
298
|
if (changed.has("portal") || changed.has("overlayContainer")) requestAnimationFrame(() => this._reconfigureOverlay());
|
|
273
299
|
if (changed.has("noScrollLock")) this._syncScrollLock();
|
|
300
|
+
if (changed.has("placement")) this._panel.updatePosition();
|
|
274
301
|
this._syncOpenAttribute();
|
|
275
302
|
this._syncOverlayInert();
|
|
276
303
|
this._syncValidity();
|
|
@@ -467,8 +494,11 @@ let WebUiSelect = class WebUiSelect extends FormAssociated(LitElement) {
|
|
|
467
494
|
aria-activedescendant=${activeDescendant}
|
|
468
495
|
aria-label=${ifDefined(this.ariaLabel)}
|
|
469
496
|
>
|
|
470
|
-
<
|
|
471
|
-
|
|
497
|
+
<span class="label">
|
|
498
|
+
<slot name="trigger" @slotchange=${this._onTriggerSlotChange}>
|
|
499
|
+
${this._hasTriggerSlot ? nothing : this._selectedLabel}
|
|
500
|
+
</slot>
|
|
501
|
+
</span>
|
|
472
502
|
<web-ui-icon class="arrow" .icon=${lucide_chevron_down_default}></web-ui-icon>
|
|
473
503
|
</div>
|
|
474
504
|
<div class="select-overlay wui-floating-panel wui-glass" hidden role="listbox" id=${listboxId}>
|
|
@@ -490,6 +520,10 @@ __decorate([property({
|
|
|
490
520
|
type: Boolean,
|
|
491
521
|
reflect: true
|
|
492
522
|
})], WebUiSelect.prototype, "disabled", void 0);
|
|
523
|
+
__decorate([property({
|
|
524
|
+
type: String,
|
|
525
|
+
reflect: true
|
|
526
|
+
})], WebUiSelect.prototype, "trigger", null);
|
|
493
527
|
__decorate([property({
|
|
494
528
|
type: Boolean,
|
|
495
529
|
reflect: true
|
|
@@ -498,6 +532,10 @@ __decorate([property({
|
|
|
498
532
|
type: Boolean,
|
|
499
533
|
reflect: true
|
|
500
534
|
})], WebUiSelect.prototype, "portal", void 0);
|
|
535
|
+
__decorate([property({
|
|
536
|
+
type: String,
|
|
537
|
+
reflect: true
|
|
538
|
+
})], WebUiSelect.prototype, "placement", null);
|
|
501
539
|
__decorate([property({
|
|
502
540
|
type: Boolean,
|
|
503
541
|
reflect: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["glass","overlayMotion","scrollbarStyle","style","lucideChevronDown"],"sources":["../../../src/components/select/index.ts"],"sourcesContent":["import '@/components/icon'\n\nimport { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport scrollbarStyle from '@/assets/scrollbar.css?inline'\nimport glass from '@/classes/glass.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 defineOptionPortal,\n handleComboboxFocusOut,\n nextWrappingIndex\n} from '@/shared/option-portal'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport {\n applyOverlayVariables,\n defineOverlayPortal,\n type OverlayContainer,\n type OverlayPortal\n} 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(scrollbarStyle), 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 // Explicitly delegated accessible naming attributes.\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\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 _typeaheadBuffer = ''\n private _typeaheadLastInputAt = 0\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 * 开启态 overlay 承载「我开着吗」(issue #120 Block 1):本组件不在 keydown 里自行关闭,\n * 只声明「我开着」。宿主级监听在 portal 模式下收不到 panel 内的 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 // panel 宽度统一为 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() 完成(handle 归它持有)。\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 }, 'Select an option')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n /*\n * 禁用态不响应 Escape。仲裁者仍在(吞掉按键并压掉原生 cancel),只是不走关闭入口:\n * 事件不落到下层 overlay,不会把外层一起关掉。\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 const selected = this.value !== '' && o.value === this.value\n o.selected = selected\n o.setAttribute('role', 'option')\n o.setAttribute('aria-selected', String(selected))\n o.setAttribute('aria-disabled', String(o.disabled))\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._resetTypeahead()\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持 trigger 焦点,避免 focusout 在 click 前关闭 overlay。\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 panel 的 option 不得再被激活或选中。\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 || e.isComposing) 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 'Home':\n if (!this._isOpen) break\n e.preventDefault()\n this._moveActiveToBoundary(true)\n break\n case 'End':\n if (!this._isOpen) break\n e.preventDefault()\n this._moveActiveToBoundary(false)\n break\n case 'Enter': {\n e.preventDefault()\n if (e.repeat) break\n if (!this._isOpen) this._open(true)\n else if (this._activeIndex >= 0) this._selectActiveOption()\n break\n }\n case ' ':\n case 'Space':\n case 'Spacebar': {\n e.preventDefault()\n if (e.repeat) break\n if (!this._isOpen) this._open(true)\n else if (this._activeIndex >= 0) this._selectActiveOption()\n break\n }\n default:\n if (this._isOpen && !e.isComposing && !e.ctrlKey && !e.metaKey && !e.altKey && Array.from(e.key).length === 1) {\n e.preventDefault()\n this._typeahead(e.key)\n }\n break\n }\n }\n\n private _selectActiveOption() {\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 }\n\n private _moveActiveToBoundary(toStart: boolean) {\n this._resetTypeahead()\n const enabled = this._options.filter(option => !option.disabled && this._isLive(option))\n const option = toStart ? enabled[0] : enabled.at(-1)\n if (!option) return\n\n this._activeIndex = this._options.indexOf(option)\n this._syncActiveOption()\n }\n\n private _typeahead(key: string) {\n const enabled = this._options.filter(option => !option.disabled && this._isLive(option))\n if (!enabled.length) return\n\n const now = Date.now()\n const withinSequence = now - this._typeaheadLastInputAt <= 500\n const isRepeatedKey =\n withinSequence &&\n Array.from(this._typeaheadBuffer).length === 1 &&\n this._normalizeTypeaheadText(this._typeaheadBuffer) === this._normalizeTypeaheadText(key)\n const query = isRepeatedKey ? key : withinSequence ? `${this._typeaheadBuffer}${key}` : key\n this._typeaheadBuffer = query\n this._typeaheadLastInputAt = now\n\n const activeOption = this._options[this._activeIndex]\n const activeIndex = activeOption ? enabled.indexOf(activeOption) : -1\n const findMatch = (prefix: string) => {\n const normalizedPrefix = this._normalizeTypeaheadText(prefix)\n for (let offset = 1; offset <= enabled.length; offset++) {\n const option = enabled[(activeIndex + offset + enabled.length) % enabled.length]\n if (this._normalizeTypeaheadText(option.label.trimStart()).startsWith(normalizedPrefix)) return option\n }\n return undefined\n }\n\n const currentMatch =\n query !== key &&\n activeIndex >= 0 &&\n activeOption &&\n this._normalizeTypeaheadText(activeOption.label.trimStart()).startsWith(this._normalizeTypeaheadText(query))\n ? activeOption\n : undefined\n const queryMatch = currentMatch ?? findMatch(query)\n const option = queryMatch ?? (query === key ? undefined : findMatch(key))\n if (!queryMatch && query !== key) this._typeaheadBuffer = key\n if (!option) return\n\n this._activeIndex = this._options.indexOf(option)\n this._syncActiveOption()\n }\n\n private _normalizeTypeaheadText(value: string) {\n return value.toLocaleLowerCase().normalize('NFD').replace(/\\p{M}/gu, '')\n }\n\n private _navigateActive(delta: number) {\n this._resetTypeahead()\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._resetTypeahead()\n this._openController.open(isKeyboardNavigation)\n }\n\n private _close() {\n this._resetTypeahead()\n this._openController.close()\n }\n\n private _resetTypeahead() {\n this._typeaheadBuffer = ''\n this._typeaheadLastInputAt = 0\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 // 新会话的 handle 刚建立,惰性状态需按当前 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${scrollbarStyle}\\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 wui-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 panel\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 移入 overlay 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 aria-label=${ifDefined(this.ariaLabel)}\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 wui-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":";;;;;;;;;;;;;;;;;;;;;AAiCA,+BAA+B;AAGxB,IAAM,cAAN,MAAM,oBAAoB,eAAe,UAAU,CAAC,CAAC;;;;;;EAGD,KAAA,cAAA;EACF,KAAA,WAAA;EACA,KAAA,WAAA;EACF,KAAA,SAAA;EACmC,KAAA,eAAA;EAEtC,KAAA,OAAA;EAGuC,KAAA,YAAA;EAI/D,KAAA,SAAA;EAaU,KAAA,mBAAA,sBAA8B;GAChE,MAAM;GACN,kBAAkB;IAEhB,MAAM,YAAY,KAAK,aAAa,OAAO;IAC3C,IAAI,cAAc,MAAM;KACtB,KAAK,SAAS;KACd,KAAK,gBAAgB,kBAAkB,CAAC,CAAC,SAAS;IACpD;GACF;GACA,gBAAgB,KAAK;GACrB,WAAU,UAAS;IACjB,KAAK,QAAQ;GACf;GACA,oBAAoB,KAAK;GACzB,oBAAoB,KAAK;GACzB,eAAc,UAAS;IACrB,IAAI,OAAO,UAAU,UAAU,KAAK,QAAQ;GAC9C;GACA,oBAAoB,KAAK,cAAc;EACzC,CAAC,CAAC,CAAC,KAAK;EAEsC,KAAA,6BAAA,IAAI,0BAA0B,MAAM,KAAK,gBAAgB;EAM5E,KAAA,UAAA;EACK,KAAA,eAAA;EACE,KAAA,iBAAA;EACC,KAAA,kBAAA;EAER,KAAA,mBAAA;EACK,KAAA,wBAAA;EAEE,KAAA,WAAA,CAAC;EAGJ,KAAA,cAAA,sBAAsB,CAAC,CAAC,KAAK;EAK3B,KAAA,gBAAA,mBAAmB,CAAC,CAAC,KAAK;GACzD,SAAS;GAET,UAAU,iBAAiB,EAAA,aAAc;GACzC,iBAAiB,KAAK;GACtB,wBAAwB,KAAK;GAC7B,cAAc,KAAK,UAAU,KAAK;GAClC,0BAA0B,CAAC,GAAG,KAAK,iBAA8B,eAAe,CAAC;GACjF,kBAAkB,KAAK;GACvB,qBAAqB,KAAK,cAAc;GACxC,aAAY,WAAU,KAAK,YAAY,MAAM;GAC7C,eAAc,WAAU,KAAK,cAAc,MAAM;GACjD,uBAAuB;IACrB,KAAK,gBAAgB;IACrB,KAAK,cAAc;IACnB,KAAK,kBAAkB;GACzB;EACF,CAAC;EAS2B,KAAA,WAAA,kBAAkB,CAAC,CAAC,KAAK;GACnD,oBAAoB,KAAK,OAAO;GAChC,mBAAmB,KAAK;EAC1B,CAAC;EACyB,KAAA,SAAA,oBAAoB,CAAC,CAAC,KAAK;GACnD,iBAAiB,KAAK,YAAY,cAA2B,iBAAiB,KAAK;GACnF,qBAAqB,KAAK,YAAY,cAA2B,iBAAiB,KAAK;GACvF,uBAAuB;IACrB,WAAW;IACX,QAAQ;IAER,gBAAgB;IAChB,UAAU,KAAK,SAAS,UAAU;GACpC;GACA,gBAAgB,KAAK;GACrB,oBAAoB,KAAK,cAAc;GACvC,aAAa,KAAK;EACpB,CAAC;EAU0B,KAAA,mBAAA,MAAkB;GAE3C,MAAM,WAAW,EAAE,aAAa,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,KAAK,OAAO,UAAU,CAAC,EAAE,cAAc,CAAC;GAC9F,IAAI,KAAK,WAAW,CAAC,UACnB,KAAK,OAAO;EAEhB;EAE4B,KAAA,oBAAA;GAC1B,uBACE,YACM,KAAK,OAAO,UAAU,SACtB,KAAK,eACL,KAAK,OAAO,CACpB;EACF;EAkEgC,KAAA,wBAAA,MAAa;GAE3C,MAAM,aADO,EAAE,OACS,iBAAiB,CAAC,CAAC,SAAS;GACpD,IAAI,KAAK,oBAAoB,YAAY;GACzC,KAAK,kBAAkB;GACvB,KAAK,oBAAoB;EAC3B;EAkBoC,KAAA,mBAAA,4BAA4B;GAE9D,UAAS,UAAS,KAAK,mBAAmB,KAAK;GAC/C,gBAAe,UAAS,KAAK,yBAAyB,KAAK;GAC3D,gBAAe,UAAS,KAAK,yBAAyB,KAAK;GAC3D,gBAAgB,KAAK,gBAAgB;EACvC,CAAC;EACsB,KAAA,eAAA,WAAwB,KAAK,iBAAiB,KAAK,MAAM;EACvD,KAAA,iBAAA,WAAwB,KAAK,iBAAiB,OAAO,MAAM;EAatD,KAAA,sBAAA,MAAa;GACzC,IAAI,EAAE,EAAE,yBAAyB,cAAc;GAC/C,MAAM,SAAS,EAAE;GACjB,IAAI,OAAO,YAAY,CAAC,KAAK,QAAQ,MAAM,GAAG;GAC9C,KAAK,QAAQ,OAAO;GACpB,KAAK,OAAO;GACZ,KAAK,mBAAmB;EAC1B;EAEgC,KAAA,wBAAA;GAC9B,KAAK,cAAc;GACnB,KAAK,kBAAkB;EACzB;EAEoC,KAAA,4BAAA,MAAoB;GACtD,IAAI,EAAE,gBAAgB,SAAS;GAC/B,IAAI,CAAC,KAAK,WAAW,KAAK,eAAe,KAAK,EAAE,EAAE,yBAAyB,cAAc;GAGzF,KAAK,eAAe;GACpB,KAAK,gBAAgB;GACrB,KAAK,kBAAkB;EACzB;EAEoC,KAAA,4BAAA,MAAoB;GAEtD,EAAE,eAAe;EACnB;EAG8B,KAAA,sBAAA;GAC5B,KAAK,cAAc,gBAAgB;EACrC;EASsB,KAAA,cAAA,MAAqB;GACzC,IAAI,KAAK,eAAe,EAAE,aAAa;GAGvC,QAAQ,EAAE,KAAV;IACE,KAAK;KACH,EAAE,eAAe;KACjB,IAAI,CAAC,KAAK,SACR,KAAK,MAAM,IAAI;UAEf,KAAK,gBAAgB,CAAC;KAExB;IACF,KAAK;KACH,EAAE,eAAe;KACjB,IAAI,CAAC,KAAK,SAAS,KAAK,MAAM,IAAI;UAC7B,KAAK,gBAAgB,EAAE;KAC5B;IACF,KAAK;KACH,IAAI,CAAC,KAAK,SAAS;KACnB,EAAE,eAAe;KACjB,KAAK,sBAAsB,IAAI;KAC/B;IACF,KAAK;KACH,IAAI,CAAC,KAAK,SAAS;KACnB,EAAE,eAAe;KACjB,KAAK,sBAAsB,KAAK;KAChC;IACF,KAAK;KACH,EAAE,eAAe;KACjB,IAAI,EAAE,QAAQ;KACd,IAAI,CAAC,KAAK,SAAS,KAAK,MAAM,IAAI;UAC7B,IAAI,KAAK,gBAAgB,GAAG,KAAK,oBAAoB;KAC1D;IAEF,KAAK;IACL,KAAK;IACL,KAAK;KACH,EAAE,eAAe;KACjB,IAAI,EAAE,QAAQ;KACd,IAAI,CAAC,KAAK,SAAS,KAAK,MAAM,IAAI;UAC7B,IAAI,KAAK,gBAAgB,GAAG,KAAK,oBAAoB;KAC1D;IAEF,SACE,IAAI,KAAK,WAAW,CAAC,EAAE,eAAe,CAAC,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,EAAE,UAAU,MAAM,KAAK,EAAE,GAAG,CAAC,CAAC,WAAW,GAAG;KAC7G,EAAE,eAAe;KACjB,KAAK,WAAW,EAAE,GAAG;IACvB;GAEJ;EACF;EA0FmC,KAAA,kBAAA,6BAA6B;GAC9D,eAAe,CAAC,KAAK;GACrB,iBAAiB,KAAK;GACtB,YAAW,SAAQ;IACjB,KAAK,UAAU;GACjB;GACA,0BAA0B,KAAK,oBAAoB;GACnD,iBAAgB,SAAQ,KAAK,gBAAgB,IAAI;GACjD,gBAAgB,KAAK;GACrB,cAAa,yBAAwB,KAAK,aAAa,oBAAoB;GAC3E,oBAAoB,KAAK,KAAK,cAAc;GAC5C,SAAQ,yBAAwB;IAC9B,KAAK,cAAc;IACnB,IAAI,sBAAsB,KAAK,wBAAwB;SAClD,KAAK,kBAAkB;GAC9B;GACA,oBAAoB;IAClB,KAAK,eAAe;IACpB,KAAK,SAAS,SAAQ,MAAK,EAAE,gBAAgB,QAAQ,CAAC;GACxD;EACF,CAAC;;;EArcwB,KAAA,SAAA;GAAC,UAAUA,aAAK;GAAG,UAAUC,sBAAa;GAAG,UAAUC,iBAAc;GAAG,UAAUC,aAAK;EAAC;;CAgBjH,IACI,QAAgB;EAClB,OAAO,KAAK;CACd;CACA,IAAI,MAAM,GAAW;EACnB,MAAM,MAAM,KAAK;EACjB,KAAK,SAAS;EACd,KAAK,iBAAiB,KAAK;EAC3B,KAAK,gBAAgB,kBAAkB,CAAC,CAAC,CAAC;EAC1C,KAAK,cAAc,SAAS,GAAG;CACjC;CA0BA,IAAY,cAAuB;EACjC,OAAO,KAAK,YAAY,KAAK,iBAAiB,eAAe;CAC/D;;EAeiC,KAAA,kBAAA;;CAgDjC,IAAI,SAAkB;EACpB,OAAO,KAAK;CACd;CAEA,IAAI,OAAgB;EAClB,OAAO,KAAK;CACd;CAmBA,oBAA6B;EAC3B,MAAM,kBAAkB;EACxB,KAAK,cAAc,SAAS;EAC5B,KAAK,iBAAiB,WAAW,KAAK,UAAU;EAChD,KAAK,iBAAiB,YAAY,KAAK,WAAW;EAClD,SAAS,iBAAiB,SAAS,KAAK,eAAe;CACzD;CAEA,uBAAgC;EAC9B,MAAM,qBAAqB;EAC3B,KAAK,cAAc,QAAQ;EAC3B,KAAK,oBAAoB,WAAW,KAAK,UAAU;EACnD,KAAK,oBAAoB,YAAY,KAAK,WAAW;EACrD,SAAS,oBAAoB,SAAS,KAAK,eAAe;EAC1D,KAAK,SAAS,QAAQ,KAAK,aAAa;EACxC,KAAK,WAAW,CAAC;EACjB,KAAK,UAAU,KAAA;EACf,KAAK,iBAAiB,KAAA;EACtB,KAAK,OAAO;EAEZ,KAAK,OAAO,QAAQ;EACpB,KAAK,YAAY,QAAQ;CAC3B;CAEA,eAAwB;EACtB,4BAA4B;GAC1B,IAAI,KAAK,aAAa,KAAK,cAAc,gBAAgB;EAC3D,CAAC;CACH;CAEA,aAAsB;EACpB,KAAK,gBAAgB;EACrB,KAAK,cAAc;CACrB;CAEA,QAAiB,SAAyB;EACxC,IAAI,QAAQ,IAAI,QAAQ,KAAK,QAAQ,IAAI,kBAAkB,GACzD,4BAA4B,KAAK,oBAAoB,CAAC;EACxD,IAAI,QAAQ,IAAI,cAAc,GAAG,KAAK,gBAAgB;EACtD,KAAK,mBAAmB;EACxB,KAAK,kBAAkB;EACvB,KAAK,cAAc;CACrB;CAEA,gBAAwB;EACtB,MAAM,YAAY,KAAK,iBAAiB,aAAa;EACrD,IAAI,CAAC,aAAa,OAAO,UAAU,gBAAgB,YAAY;EAC/D,IAAI,KAAK,eAAe,CAAC,KAAK,YAAY,KAAK,OAAO,UAAU,YAAY,CAAC,CAAC;OACzE,UAAU,YAAY,EAAE,cAAc,KAAK,GAAG,kBAAkB;CACvE;CAEA,qBAA6B;EAC3B,KAAK,gBAAgB,QAAQ,KAAK,OAAO;CAC3C;CAOA,oBAA4B;EAC1B,KAAK,OAAO,UAAU,CAAC,EAAE,SAAS,KAAK,WAAW;CACpD;CAUA,gBAAwB;EACtB,KAAK,SAAS,SAAQ,MAAK;GACzB,MAAM,WAAW,KAAK,UAAU,MAAM,EAAE,UAAU,KAAK;GACvD,EAAE,WAAW;GACb,EAAE,aAAa,QAAQ,QAAQ;GAC/B,EAAE,aAAa,iBAAiB,OAAO,QAAQ,CAAC;GAChD,EAAE,aAAa,iBAAiB,OAAO,EAAE,QAAQ,CAAC;EACpD,CAAC;EACD,IAAI,CAAC,KAAK,OAAO;GACf,KAAK,iBAAiB,KAAK;GAC3B;EACF;EACA,MAAM,SAAS,KAAK,SAAS,MAAK,MAAK,EAAE,UAAU,KAAK,KAAK;EAC7D,KAAK,iBAAiB,QAAQ,SAAS,KAAK;CAC9C;CAYA,kBAA0B;EACxB,MAAM,eAAe,KAAK,SAAS,KAAK;EAGxC,MAAM,OAAO,KAAK,cAAc,QAAQ,KAAK,UAAU,YAAY;EACnE,KAAK,WAAW,KAAK;EACrB,KAAK,eAAe,KAAK;EAEzB,KAAK,cAAc,gBAAgB,KAAK,QAAQ;CAClD;CAsCA,QAAgB,QAA8B;EAC5C,MAAM,QAAQ,KAAK,SAAS,KAAK,OAAO,SAAS,IAAI;EACrD,OAAO,OAAO,gBAAgB,KAAK,SAAS,MAAM,KAAM,CAAC,CAAC,SAAS,MAAM,SAAS,MAAM;CAC1F;CAuDA,sBAA8B;EAC5B,MAAM,SAAS,KAAK,SAAS,KAAK;EAClC,IAAI,UAAU,KAAK,QAAQ,MAAM,KAAK,CAAC,OAAO,UAAU;GACtD,KAAK,QAAQ,OAAO;GACpB,KAAK,mBAAmB;EAC1B;EACA,KAAK,OAAO;CACd;CAEA,sBAA8B,SAAkB;EAC9C,KAAK,gBAAgB;EACrB,MAAM,UAAU,KAAK,SAAS,QAAO,WAAU,CAAC,OAAO,YAAY,KAAK,QAAQ,MAAM,CAAC;EACvF,MAAM,SAAS,UAAU,QAAQ,KAAK,QAAQ,GAAG,EAAE;EACnD,IAAI,CAAC,QAAQ;EAEb,KAAK,eAAe,KAAK,SAAS,QAAQ,MAAM;EAChD,KAAK,kBAAkB;CACzB;CAEA,WAAmB,KAAa;EAC9B,MAAM,UAAU,KAAK,SAAS,QAAO,WAAU,CAAC,OAAO,YAAY,KAAK,QAAQ,MAAM,CAAC;EACvF,IAAI,CAAC,QAAQ,QAAQ;EAErB,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,iBAAiB,MAAM,KAAK,yBAAyB;EAK3D,MAAM,QAHJ,kBACA,MAAM,KAAK,KAAK,gBAAgB,CAAC,CAAC,WAAW,KAC7C,KAAK,wBAAwB,KAAK,gBAAgB,MAAM,KAAK,wBAAwB,GAAG,IAC5D,MAAM,iBAAiB,GAAG,KAAK,mBAAmB,QAAQ;EACxF,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;EAE7B,MAAM,eAAe,KAAK,SAAS,KAAK;EACxC,MAAM,cAAc,eAAe,QAAQ,QAAQ,YAAY,IAAI;EACnE,MAAM,aAAa,WAAmB;GACpC,MAAM,mBAAmB,KAAK,wBAAwB,MAAM;GAC5D,KAAK,IAAI,SAAS,GAAG,UAAU,QAAQ,QAAQ,UAAU;IACvD,MAAM,SAAS,SAAS,cAAc,SAAS,QAAQ,UAAU,QAAQ;IACzE,IAAI,KAAK,wBAAwB,OAAO,MAAM,UAAU,CAAC,CAAC,CAAC,WAAW,gBAAgB,GAAG,OAAO;GAClG;EAEF;EASA,MAAM,cANJ,UAAU,OACV,eAAe,KACf,gBACA,KAAK,wBAAwB,aAAa,MAAM,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,wBAAwB,KAAK,CAAC,IACvG,eACA,KAAA,MAC6B,UAAU,KAAK;EAClD,MAAM,SAAS,eAAe,UAAU,MAAM,KAAA,IAAY,UAAU,GAAG;EACvE,IAAI,CAAC,cAAc,UAAU,KAAK,KAAK,mBAAmB;EAC1D,IAAI,CAAC,QAAQ;EAEb,KAAK,eAAe,KAAK,SAAS,QAAQ,MAAM;EAChD,KAAK,kBAAkB;CACzB;CAEA,wBAAgC,OAAe;EAC7C,OAAO,MAAM,kBAAkB,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,QAAQ,WAAW,EAAE;CACzE;CAEA,gBAAwB,OAAe;EACrC,KAAK,gBAAgB;EACrB,MAAM,UAAU,KAAK,SAAS,QAAO,MAAK,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC,CAAC;EACxE,IAAI,CAAC,QAAQ,QAAQ;EAErB,MAAM,iBAAiB,KAAK,SAAS,MACnC,WAAU,OAAO,UAAU,KAAK,SAAS,CAAC,OAAO,YAAY,KAAK,QAAQ,MAAM,CAClF;EACA,MAAM,aACJ,KAAK,gBAAgB,KAAK,KAAK,QAAQ,KAAK,SAAS,KAAK,aAAa,IACnE,QAAQ,QAAQ,KAAK,SAAS,KAAK,aAAa,IAChD,iBACE,QAAQ,QAAQ,cAAc,IAC9B,QAAQ,IACN,KACA;EACV,MAAM,aAAa,QAAQ,kBAAkB,QAAQ,QAAQ,YAAY,KAAK;EAC9E,KAAK,eAAe,KAAK,SAAS,QAAQ,UAAU;EAEpD,KAAK,kBAAkB;CACzB;CA0BA,MAAc,uBAAuB,OAAO;EAC1C,KAAK,gBAAgB;EACrB,KAAK,gBAAgB,KAAK,oBAAoB;CAChD;CAEA,SAAiB;EACf,KAAK,gBAAgB;EACrB,KAAK,gBAAgB,MAAM;CAC7B;CAEA,kBAA0B;EACxB,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;CAC/B;CAEA,sBAA8B;EAC5B,wBAAwB,MAAM,KAAK,OAAO;CAC5C;CAEA,0BAAkC;EAChC,MAAM,gBAAgB,KAAK,SAAS,WAClC,WAAU,OAAO,UAAU,KAAK,SAAS,CAAC,OAAO,YAAY,KAAK,QAAQ,MAAM,CAClF;EACA,MAAM,oBAAoB,KAAK,SAAS,WAAU,WAAU,CAAC,OAAO,YAAY,KAAK,QAAQ,MAAM,CAAC;EACpG,KAAK,eAAe,iBAAiB,IAAI,gBAAgB;EACzD,KAAK,kBAAkB;CACzB;CAEA,oBAA4B;EAC1B,KAAK,SAAS,SAAS,QAAQ,UAC7B,OAAO,gBAAgB,UAAU,UAAU,KAAK,gBAAgB,KAAK,QAAQ,MAAM,CAAC,CACtF;CACF;CAEA,qBAA6B;EAC3B,KAAK,cAAc,IAAI,MAAM,SAAS;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;EACxE,KAAK,cAAc,IAAI,MAAM,UAAU;GAAE,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;CAC3E;CAEA,gBAAwB,SAAS,KAAK,SAAS;EAC7C,KAAK,YAAY,KAAK,UAAU,CAAC,KAAK,YAAY;CACpD;CAEA,eAAuB;EACrB,IAAI,KAAK,aAAa;EACtB,IAAI,KAAK,SAAS,KAAK,OAAO;OACzB,KAAK,MAAM;CAClB;CAEA,aAAqB,uBAAuB,OAAO;EACjD,KAAK,OAAO,KAAK,oBAAoB;EAErC,KAAK,kBAAkB;CACzB;CAEA,gBAAuC;EACrC,MAAM,SAAS,oBAAoB,CAAC,CAAC,KAAK;GACxC,WAAW,KAAK;GAChB,QAAQ;GACR,OAAO,GAAGH,cAAM,IAAIC,uBAAc,IAAIC,kBAAe,IAAIC;GACzD,WAAW;GACX,uBAAuB,KAAK,cAAc,gBAAgB;EAC5D,CAAC;EACD,KAAK,UAAU;EACf,sBAAsB,OAAO,OAAO,MAAM;GACxC;GACA;GACA;EACF,CAAC;EACD,OAAO,MAAM,aAAa,QAAQ,SAAS;EAC3C,MAAM,SAAS,SAAS,cAAc,KAAK;EAC3C,OAAO,YAAY;EACnB,MAAM,UAAU,SAAS,cAAc,KAAK;EAC5C,QAAQ,YAAY;EACpB,KAAK,iBAAiB;EACtB,OAAO,OAAO,OAAO;EACrB,OAAO,MAAM,OAAO,MAAM;EAE1B,OAAO,YACL,MAAM,KAAK,KAAK,QAAQ,CAAC,CAAC,QAAO,UAAS,MAAM,SAAS,SAAS,GAClE,OACF;EACA,OAAO;CACT;CAEA,sBAA8B;EAE5B,KAAK,UAAU,KAAA;EACf,KAAK,iBAAiB,KAAA;EACtB,KAAK,OAAO,YAAY,KAAK,OAAO;EAMpC,KAAK,kBAAkB;CACzB;CAEA,MAAc,gBAAgB;EAG5B,IAAI,MAFiB,KAAK,OAAO,YAAY,KAAK,OAAO,GAE7C;GACV,KAAK,UAAU,KAAA;GACf,KAAK,iBAAiB,KAAA;EACxB;CACF;CAEA,SAAkB;EAGhB,MAAM,YAAY,GAAG,KAAK,UAAU;EACpC,MAAM,mBACJ,CAAC,KAAK,UAAU,KAAK,WAAW,KAAK,gBAAgB,IAChD,KAAK,SAAS,KAAK,aAAa,EAAE,MAAM,UACzC;EAEN,OAAO,IAAI;;;;iCAIkB,KAAK,gBAAgB;mBACnC,KAAK,aAAa;qBAChB,KAAK,cAAc,OAAO,IAAI;;0BAEzB,KAAK,QAAQ;;0BAEb,KAAK,SAAS,UAAU,UAAU;0BAClC,OAAO,KAAK,WAAW,EAAE;kCACjB,iBAAiB;uBAC5B,UAAU,KAAK,SAAS,EAAE;;6CAEJ,KAAK,qBAAqB;YAC3D,CAAC,KAAK,kBAAkB,IAAI,uBAAuB,KAAK,eAAe,WAAW,QAAQ;6CACzDC,4BAAkB;;4FAE6B,UAAU;;;kCAGpE,KAAK,cAAc;;;;;;CAMnD;AAOF;AA5lBG,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,YAAA,WAAA,eAAA,KAAA,CAAA;AACxC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,YAAA,WAAA,YAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,YAAA,WAAA,YAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,YAAA,WAAA,UAAA,KAAA,CAAA;AACzC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAiB,CAAC,CAAA,GAAA,YAAA,WAAA,gBAAA,KAAA,CAAA;AACtE,WAAA,CAAA,SAAS,EAAE,WAAW,MAAM,CAAC,CAAA,GAAA,YAAA,WAAA,oBAAA,KAAA,CAAA;AAC7B,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,YAAA,WAAA,QAAA,KAAA,CAAA;AAGxC,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,WAAW;AAAa,CAAC,CAAA,GAAA,YAAA,WAAA,aAAA,KAAA,CAAA;AAIlD,WAAA,CAAA,MAAM,CAAA,GAAA,YAAA,WAAA,UAAA,KAAA,CAAA;AACN,WAAA,CAAA,SAAS;CAAE,MAAM;CAAQ,SAAS;AAAK,CAAC,CAAA,GAAA,YAAA,WAAA,SAAA,IAAA;AAwCxC,WAAA,CAAA,MAAM,CAAA,GAAA,YAAA,WAAA,WAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,YAAA,WAAA,gBAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,YAAA,WAAA,kBAAA,KAAA,CAAA;AACN,WAAA,CAAA,MAAM,CAAA,GAAA,YAAA,WAAA,mBAAA,KAAA,CAAA;AA7DR,cAAA,eAAA,WAAA,CAAA,cAAc,eAAe,CAAA,GAAA,WAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["glass","overlayMotion","scrollbarStyle","style","lucideChevronDown"],"sources":["../../../src/components/select/index.ts"],"sourcesContent":["import '@/components/icon'\n\nimport type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, nothing, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport scrollbarStyle from '@/assets/scrollbar.css?inline'\nimport glass from '@/classes/glass.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 { normalizeLiteral } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport {\n createComboboxOpenController,\n createOptionListenerBinding,\n defineOptionPortal,\n handleComboboxFocusOut,\n nextWrappingIndex\n} from '@/shared/option-portal'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOpenOverlay } from '@/shared/overlay/open-overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport {\n applyOverlayVariables,\n defineOverlayPortal,\n type OverlayContainer,\n type OverlayPortal\n} 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(scrollbarStyle), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: Boolean, reflect: true }) disabled = false\n\n /**\n * 触发器外观:`label` 为默认的带选中文本与箭头;`icon` 保留右侧箭头,只把 `trigger` slot\n * 的内容换成左侧图标区——带 trigger slot 时触发器贴合内容宽度,高度不变。\n * 图标模式需要消费方提供 `trigger` slot 与 `aria-label`。\n */\n @property({ type: String, reflect: true })\n get trigger(): 'label' | 'icon' {\n return this._trigger\n }\n set trigger(v: string) {\n const old = this._trigger\n this._trigger = normalizeLiteral(v, ['label', 'icon'] as const, 'label')\n this.requestUpdate('trigger', old)\n }\n private _trigger: 'label' | 'icon' = 'label'\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) portal = false\n /** 下拉 panel 相对触发器的方向;默认贴着触发器左下角向下展开。 */\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'bottom-start')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'bottom-start'\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 // Explicitly delegated accessible naming attributes.\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\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 _typeaheadBuffer = ''\n private _typeaheadLastInputAt = 0\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 * 开启态 overlay 承载「我开着吗」(issue #120 Block 1):本组件不在 keydown 里自行关闭,\n * 只声明「我开着」。宿主级监听在 portal 模式下收不到 panel 内的 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: this.placement,\n offset: 4,\n // panel 宽度统一为 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() 完成(handle 归它持有)。\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 if (changed.has('placement')) this._panel.updatePosition()\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 }, 'Select an option')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n /*\n * 禁用态不响应 Escape。仲裁者仍在(吞掉按键并压掉原生 cancel),只是不走关闭入口:\n * 事件不落到下层 overlay,不会把外层一起关掉。\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 const selected = this.value !== '' && o.value === this.value\n o.selected = selected\n o.setAttribute('role', 'option')\n o.setAttribute('aria-selected', String(selected))\n o.setAttribute('aria-disabled', String(o.disabled))\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._resetTypeahead()\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持 trigger 焦点,避免 focusout 在 click 前关闭 overlay。\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 panel 的 option 不得再被激活或选中。\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 || e.isComposing) 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 'Home':\n if (!this._isOpen) break\n e.preventDefault()\n this._moveActiveToBoundary(true)\n break\n case 'End':\n if (!this._isOpen) break\n e.preventDefault()\n this._moveActiveToBoundary(false)\n break\n case 'Enter': {\n e.preventDefault()\n if (e.repeat) break\n if (!this._isOpen) this._open(true)\n else if (this._activeIndex >= 0) this._selectActiveOption()\n break\n }\n case ' ':\n case 'Space':\n case 'Spacebar': {\n e.preventDefault()\n if (e.repeat) break\n if (!this._isOpen) this._open(true)\n else if (this._activeIndex >= 0) this._selectActiveOption()\n break\n }\n default:\n if (this._isOpen && !e.isComposing && !e.ctrlKey && !e.metaKey && !e.altKey && Array.from(e.key).length === 1) {\n e.preventDefault()\n this._typeahead(e.key)\n }\n break\n }\n }\n\n private _selectActiveOption() {\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 }\n\n private _moveActiveToBoundary(toStart: boolean) {\n this._resetTypeahead()\n const enabled = this._options.filter(option => !option.disabled && this._isLive(option))\n const option = toStart ? enabled[0] : enabled.at(-1)\n if (!option) return\n\n this._activeIndex = this._options.indexOf(option)\n this._syncActiveOption()\n }\n\n private _typeahead(key: string) {\n const enabled = this._options.filter(option => !option.disabled && this._isLive(option))\n if (!enabled.length) return\n\n const now = Date.now()\n const withinSequence = now - this._typeaheadLastInputAt <= 500\n const isRepeatedKey =\n withinSequence &&\n Array.from(this._typeaheadBuffer).length === 1 &&\n this._normalizeTypeaheadText(this._typeaheadBuffer) === this._normalizeTypeaheadText(key)\n const query = isRepeatedKey ? key : withinSequence ? `${this._typeaheadBuffer}${key}` : key\n this._typeaheadBuffer = query\n this._typeaheadLastInputAt = now\n\n const activeOption = this._options[this._activeIndex]\n const activeIndex = activeOption ? enabled.indexOf(activeOption) : -1\n const findMatch = (prefix: string) => {\n const normalizedPrefix = this._normalizeTypeaheadText(prefix)\n for (let offset = 1; offset <= enabled.length; offset++) {\n const option = enabled[(activeIndex + offset + enabled.length) % enabled.length]\n if (this._normalizeTypeaheadText(option.label.trimStart()).startsWith(normalizedPrefix)) return option\n }\n return undefined\n }\n\n const currentMatch =\n query !== key &&\n activeIndex >= 0 &&\n activeOption &&\n this._normalizeTypeaheadText(activeOption.label.trimStart()).startsWith(this._normalizeTypeaheadText(query))\n ? activeOption\n : undefined\n const queryMatch = currentMatch ?? findMatch(query)\n const option = queryMatch ?? (query === key ? undefined : findMatch(key))\n if (!queryMatch && query !== key) this._typeaheadBuffer = key\n if (!option) return\n\n this._activeIndex = this._options.indexOf(option)\n this._syncActiveOption()\n }\n\n private _normalizeTypeaheadText(value: string) {\n return value.toLocaleLowerCase().normalize('NFD').replace(/\\p{M}/gu, '')\n }\n\n private _navigateActive(delta: number) {\n this._resetTypeahead()\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._resetTypeahead()\n this._openController.open(isKeyboardNavigation)\n }\n\n private _close() {\n this._resetTypeahead()\n this._openController.close()\n }\n\n private _resetTypeahead() {\n this._typeaheadBuffer = ''\n this._typeaheadLastInputAt = 0\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 // 新会话的 handle 刚建立,惰性状态需按当前 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${scrollbarStyle}\\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 wui-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 panel\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 移入 overlay 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 aria-label=${ifDefined(this.ariaLabel)}\n >\n <span class=\"label\">\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}>\n ${this._hasTriggerSlot ? nothing : this._selectedLabel}\n </slot>\n </span>\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 wui-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,5 +1,5 @@
|
|
|
1
1
|
// src/components/select/style.css?inline
|
|
2
|
-
var style_default = "*,:before,:after{box-sizing:border-box}:host{--wui-select-bg-hover:var(--wui-color-surface-glass-hover,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, var(--wui-color-surface-glass,#fafafa57)));--wui-select-bg-active:var(--wui-color-surface-glass-active,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, var(--wui-color-surface-glass,#fafafa57)));-webkit-user-select:none;user-select:none;display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-select-inner{flex-direction:column;display:flex;position:relative}.select-trigger{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);cursor:default;gap:var(--wui-space-2,8px);box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-control-size,36px);height:var(--wui-control-size,36px);padding:0 var(--wui-space-3,12px);border-radius:var(--wui-radius-control,calc(infinity * 1px));border:none;align-items:center;display:flex;overflow:clip}.select-trigger:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#0071e3) 40%, transparent));outline-offset:2px}:host([disabled]) .select-trigger{cursor:not-allowed}@media (hover:hover) and (pointer:fine){:host(:not([disabled])) .select-trigger:hover{background-color:var(--wui-select-bg-hover)}}:host(:not([disabled])) .select-trigger:active,:host([open]:not([disabled])) .select-trigger{background-color:var(--wui-select-bg-active)}.select-trigger[data-custom-trigger]{width:auto}.label{font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}:host(:not([data-has-value])) .label{color:var(--wui-color-text-secondary,#6a6a6a)}
|
|
2
|
+
var style_default = "*,:before,:after{box-sizing:border-box}:host{--wui-select-bg-hover:var(--wui-color-surface-glass-hover,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 6%, var(--wui-color-surface-glass,#fafafa57)));--wui-select-bg-active:var(--wui-color-surface-glass-active,color-mix(in srgb, var(--wui-color-text,#1b1b1b) 15%, var(--wui-color-surface-glass,#fafafa57)));-webkit-user-select:none;user-select:none;display:inline-block}:host([disabled]){cursor:not-allowed;opacity:.4}.wui-select-inner{flex-direction:column;display:flex;position:relative}.select-trigger{--wui-glass-corner-radius:calc(var(--wui-control-size,36px) / 2);cursor:default;gap:var(--wui-space-2,8px);box-sizing:border-box;width:var(--wui-input-width,200px);min-width:var(--wui-control-size,36px);height:var(--wui-control-size,36px);padding:0 var(--wui-space-3,12px);border-radius:var(--wui-radius-control,calc(infinity * 1px));border:none;align-items:center;display:flex;overflow:clip}.select-trigger:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,color-mix(in srgb, var(--wui-color-accent,#0071e3) 40%, transparent));outline-offset:2px}:host([disabled]) .select-trigger{cursor:not-allowed}@media (hover:hover) and (pointer:fine){:host(:not([disabled])) .select-trigger:hover{background-color:var(--wui-select-bg-hover)}}:host(:not([disabled])) .select-trigger:active,:host([open]:not([disabled])) .select-trigger{background-color:var(--wui-select-bg-active)}.select-trigger[data-custom-trigger]{width:auto}.label{font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}:host(:not([data-has-value])) .label{color:var(--wui-color-text-secondary,#6a6a6a)}:host([trigger=icon]) .label{flex:none;justify-content:center;align-items:center;display:flex;overflow:visible}.arrow{color:var(--wui-color-text-secondary,#6a6a6a);flex-shrink:0}:host([open]) .arrow{transform:rotate(180deg)}.select-overlay{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-internal-duration-float-enter:var(--wui-duration-float-enter,.24s);--wui-internal-duration-float-exit:var(--wui-duration-float-exit,.16s);--wui-glass-corner-radius:var(--wui-radius-menu,18px);--wui-color-glass-ring:transparent;z-index:var(--wui-layer-inline-overlay,10);box-sizing:border-box;min-width:var(--wui-overlay-min-width,200px);max-width:var(--wui-select-max-width,500px);border-radius:var(--wui-radius-menu,18px);background-color:var(--wui-color-surface-menu,#fafafac2);position:absolute;overflow:hidden}.select-overlay.portal{z-index:var(--wui-layer-menu,1000);position:fixed}.select-overlay.hidden{display:none}.select-scroll{max-height:var(--wui-select-max-height,200px);overflow-y:auto}.select-content{padding:var(--wui-space-1,4px)}:host([portal]) .select-overlay{display:none}:host([data-wui-pointer-focus]) .select-trigger:focus-visible{outline-color:#0000}\n";
|
|
3
3
|
export { style_default as default };
|
|
4
4
|
|
|
5
5
|
//# sourceMappingURL=style.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/select/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-select-bg-hover: var(\n --wui-color-surface-glass-hover,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, var(--wui-color-surface-glass, rgb(250 250 250 / 0.34)))\n );\n --wui-select-bg-active: var(\n --wui-color-surface-glass-active,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, var(--wui-color-surface-glass, rgb(250 250 250 / 0.34)))\n );\n user-select: none;\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wui-select-inner {\n position: relative;\n display: flex;\n flex-direction: column;\n}\n\n.select-trigger {\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n\n cursor: default;\n\n overflow: clip;\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-control-size, 36px);\n height: var(--wui-control-size, 36px);\n padding: 0 var(--wui-space-3, 12px);\n border: none;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #0071e3) 40%, transparent));\n outline-offset: 2px;\n }\n}\n\n:host([disabled]) .select-trigger {\n cursor: not-allowed;\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host(:not([disabled])) .select-trigger:hover {\n background-color: var(--wui-select-bg-hover);\n }\n}\n\n:host(:not([disabled])) .select-trigger:active,\n:host([open]:not([disabled])) .select-trigger {\n background-color: var(--wui-select-bg-active);\n}\n\n.select-trigger[data-custom-trigger] {\n width: auto;\n}\n\n.label {\n overflow: hidden;\n flex: 1;\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n:host(:not([data-has-value])) .label {\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\n
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../../../src/components/select/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-select-bg-hover: var(\n --wui-color-surface-glass-hover,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 6%, var(--wui-color-surface-glass, rgb(250 250 250 / 0.34)))\n );\n --wui-select-bg-active: var(\n --wui-color-surface-glass-active,\n color-mix(in srgb, var(--wui-color-text, #1b1b1b) 15%, var(--wui-color-surface-glass, rgb(250 250 250 / 0.34)))\n );\n user-select: none;\n display: inline-block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.wui-select-inner {\n position: relative;\n display: flex;\n flex-direction: column;\n}\n\n.select-trigger {\n --wui-glass-corner-radius: calc(var(--wui-control-size, 36px) / 2);\n\n cursor: default;\n\n overflow: clip;\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n\n box-sizing: border-box;\n width: var(--wui-input-width, 200px);\n min-width: var(--wui-control-size, 36px);\n height: var(--wui-control-size, 36px);\n padding: 0 var(--wui-space-3, 12px);\n border: none;\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n &:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid\n var(--wui-color-focus-ring, color-mix(in srgb, var(--wui-color-accent, #0071e3) 40%, transparent));\n outline-offset: 2px;\n }\n}\n\n:host([disabled]) .select-trigger {\n cursor: not-allowed;\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host(:not([disabled])) .select-trigger:hover {\n background-color: var(--wui-select-bg-hover);\n }\n}\n\n:host(:not([disabled])) .select-trigger:active,\n:host([open]:not([disabled])) .select-trigger {\n background-color: var(--wui-select-bg-active);\n}\n\n.select-trigger[data-custom-trigger] {\n width: auto;\n}\n\n.label {\n overflow: hidden;\n flex: 1;\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n:host(:not([data-has-value])) .label {\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\n:host([trigger='icon']) .label {\n overflow: visible;\n display: flex;\n flex: none;\n align-items: center;\n justify-content: center;\n}\n\n.arrow {\n flex-shrink: 0;\n color: var(--wui-color-text-secondary, #6a6a6a);\n}\n\n:host([open]) .arrow {\n transform: rotate(180deg);\n}\n\n.select-overlay {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-internal-duration-float-enter: var(--wui-duration-float-enter, 240ms);\n --wui-internal-duration-float-exit: var(--wui-duration-float-exit, 160ms);\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\n\n /* 环底色转 transparent,宽 panel 的长边中段不留铺底,见 menu-portal.css 同处注释。 */\n --wui-color-glass-ring: transparent;\n position: absolute;\n z-index: var(--wui-layer-inline-overlay, 10);\n\n overflow: hidden;\n\n box-sizing: border-box;\n min-width: var(--wui-overlay-min-width, 200px);\n max-width: var(--wui-select-max-width, 500px);\n border-radius: var(--wui-radius-menu, 18px);\n\n /* 玻璃背景:wui-glass 在 panel 自身,这里覆盖其默认玻璃底为 menu surface 色 */\n background-color: var(--wui-color-surface-menu, rgb(250 250 250 / 0.76));\n\n &.portal {\n position: fixed;\n z-index: var(--wui-layer-menu, 1000);\n }\n\n &.hidden {\n display: none;\n }\n}\n\n.select-scroll {\n overflow-y: auto;\n max-height: var(--wui-select-max-height, 200px);\n}\n\n.select-content {\n padding: var(--wui-space-1, 4px);\n}\n\n:host([portal]) .select-overlay {\n display: none;\n}\n\n:host([data-wui-pointer-focus]) .select-trigger:focus-visible {\n outline-color: transparent;\n}\n"],"mappings":";AAAA,IAAA,gBAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** `shake()` 的可选项。除 `target` 外都有默认值,`shake()` 不带参数即可用。 */
|
|
2
|
+
export interface ShakeOptions {
|
|
3
|
+
/**
|
|
4
|
+
* 位移目标。省略时震整页(`document.documentElement`):页面里 in-flow 与 `position: fixed`
|
|
5
|
+
* 的内容一起跟着走,而 top layer 的 `<dialog>` 与它的 `::backdrop` 不受影响(Chromium 实测),
|
|
6
|
+
* 因此正在打开的 drawer / dialog 不会跟着晃。
|
|
7
|
+
*/
|
|
8
|
+
target?: HTMLElement;
|
|
9
|
+
/**
|
|
10
|
+
* 横向首摆幅度(px)。省略时读目标计算样式上的 `--wui-shake-x-distance`。
|
|
11
|
+
* 震整页时该 token 要写在 `html` / `:root` 上:主题元素在 body 之下,它的声明继承
|
|
12
|
+
* 不到 `documentElement`(继承只往下走)。
|
|
13
|
+
*/
|
|
14
|
+
xDistance?: number;
|
|
15
|
+
/**
|
|
16
|
+
* 纵向幅度(px),默认与横向同值。省略时读目标计算样式上的 `--wui-shake-y-distance`。
|
|
17
|
+
* 与横向同相位,所以合成位移沿一条直线、倾角由两个幅度决定;把横向置 `0` 就是纯上下摆,
|
|
18
|
+
* 把纵向置 `0` 就是纯横摆。
|
|
19
|
+
*/
|
|
20
|
+
yDistance?: number;
|
|
21
|
+
/** 整段时长(ms)。省略时读目标计算样式上的 `--wui-shake-duration`。 */
|
|
22
|
+
duration?: number;
|
|
23
|
+
}
|
|
24
|
+
/** 横向幅度 token 的名字;注册项与 JS 读取共用这一个字符串。 */
|
|
25
|
+
export declare const SHAKE_X_DISTANCE_VARIABLE = "--wui-shake-x-distance";
|
|
26
|
+
/** 纵向幅度 token 的名字。 */
|
|
27
|
+
export declare const SHAKE_Y_DISTANCE_VARIABLE = "--wui-shake-y-distance";
|
|
28
|
+
export declare const SHAKE_X_DISTANCE_FALLBACK = 12;
|
|
29
|
+
export declare const SHAKE_Y_DISTANCE_FALLBACK = 12;
|
|
30
|
+
/**
|
|
31
|
+
* 让一次「不行 / 请先处理」的信号可见:目标摆几下后回到原位。
|
|
32
|
+
*
|
|
33
|
+
* 用于打断一次被拦下的操作(例如表单还有未保存内容却要退出),或把注意力拉回某个元素。
|
|
34
|
+
* 传 `target` 就只震那一块,不传就震整页。播放期间目标上已有的 `transform` 会被逐帧带上,
|
|
35
|
+
* 因此居中定位不会被震动吃掉。
|
|
36
|
+
*
|
|
37
|
+
* 两个幅度默认同值,所以不带参数是斜向摆;把某一轴设为 0 就只剩另一条轴,
|
|
38
|
+
* 两轴同相位所以合成轨迹始终是一条直线。
|
|
39
|
+
* 同一目标上重复调用会**重新开始**摆(撤掉上一条),而不是叠加成更大的位移;
|
|
40
|
+
* `prefers-reduced-motion`(系统或 `web-ui-theme` 的 motion 档位)下不产生任何位移。
|
|
41
|
+
*/
|
|
42
|
+
export declare function shake(input?: HTMLElement | ShakeOptions): void;
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/shake/index.ts"],"mappings":";iBAIiB;;;;;;EAMf,SAAS;;;;;;EAMT;;;;;;EAMA;;EAEA;;;qBAIW;;qBAEA;qBASA;qBACA;;;;;;;;;;;;;wBAmHG,MAAM,QAAQ,cAAc"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { findRootTheme } from "../../shared/overlay/theme-overlay-scope.js";
|
|
2
|
+
import { prefersReducedMotion } from "../../shared/theme/reduced-motion.js";
|
|
3
|
+
// src/components/shake/index.ts
|
|
4
|
+
/** 横向幅度 token 的名字;注册项与 JS 读取共用这一个字符串。 */
|
|
5
|
+
const SHAKE_X_DISTANCE_VARIABLE = "--wui-shake-x-distance";
|
|
6
|
+
/** 纵向幅度 token 的名字。 */
|
|
7
|
+
const SHAKE_Y_DISTANCE_VARIABLE = "--wui-shake-y-distance";
|
|
8
|
+
const DURATION_PROPERTY = "--wui-shake-duration";
|
|
9
|
+
const SHAKE_X_DISTANCE_FALLBACK = 12;
|
|
10
|
+
const SHAKE_Y_DISTANCE_FALLBACK = 12;
|
|
11
|
+
const DURATION_FALLBACK = 420;
|
|
12
|
+
/** 挂在 Animation.id 上的标记,用于「同一次调用只保留一条震动」。 */
|
|
13
|
+
const SHAKE_ANIMATION_ID = "wui-shake";
|
|
14
|
+
const SHAKE_CYCLES = 3.5;
|
|
15
|
+
const SHAKE_SAMPLE_COUNT = 24;
|
|
16
|
+
if (typeof CSS !== "undefined" && "registerProperty" in CSS) for (const [name, initialValue] of [[SHAKE_X_DISTANCE_VARIABLE, "12px"], [SHAKE_Y_DISTANCE_VARIABLE, "12px"]]) try {
|
|
17
|
+
CSS.registerProperty({
|
|
18
|
+
name,
|
|
19
|
+
syntax: "<length>",
|
|
20
|
+
inherits: true,
|
|
21
|
+
initialValue
|
|
22
|
+
});
|
|
23
|
+
} catch {}
|
|
24
|
+
function readLength(target, property, fallback) {
|
|
25
|
+
const parsed = Number.parseFloat(getComputedStyle(target).getPropertyValue(property));
|
|
26
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
27
|
+
}
|
|
28
|
+
function readDuration(target, property, fallback) {
|
|
29
|
+
const raw = getComputedStyle(target).getPropertyValue(property).trim();
|
|
30
|
+
const value = Number.parseFloat(raw);
|
|
31
|
+
if (!Number.isFinite(value)) return fallback;
|
|
32
|
+
return raw.endsWith("ms") ? value : value * 1e3;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 目标所在范围是否要求减少动效。
|
|
36
|
+
*
|
|
37
|
+
* 指定 target 时按它自己的主题范围走。默认震整页时不能只看祖先:主题元素总在 body 之下,
|
|
38
|
+
* `documentElement` 往上走找不到它们,于是 `shake()` 会和页面里其它动效认的档位分叉。
|
|
39
|
+
* 这里改用**根主题**——与 toast / imagePreview 解析挂载根时同一个 `findRootTheme()`,
|
|
40
|
+
* 命令式入口的「页面级默认值」两条路径认的是同一个主题;没有主题范围时回退系统偏好。
|
|
41
|
+
*/
|
|
42
|
+
function isReducedFor(target) {
|
|
43
|
+
if (target !== document.documentElement) return prefersReducedMotion(target);
|
|
44
|
+
const theme = findRootTheme();
|
|
45
|
+
return theme ? theme.isReducedMotion() : prefersReducedMotion(target);
|
|
46
|
+
}
|
|
47
|
+
function resolveOptions(input) {
|
|
48
|
+
const options = input instanceof HTMLElement ? { target: input } : input ?? {};
|
|
49
|
+
const target = options.target ?? document.documentElement;
|
|
50
|
+
return {
|
|
51
|
+
target,
|
|
52
|
+
xDistance: options.xDistance ?? readLength(target, "--wui-shake-x-distance", 12),
|
|
53
|
+
yDistance: options.yDistance ?? readLength(target, "--wui-shake-y-distance", 12),
|
|
54
|
+
duration: options.duration ?? readDuration(target, DURATION_PROPERTY, DURATION_FALLBACK)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 关键帧里写的是 `<transform-list>`,而计算值在没有变换时是 `none`——`none translate(-6px, 0px)`
|
|
59
|
+
* 不是合法的变换列表,整条关键帧会被丢弃。
|
|
60
|
+
*/
|
|
61
|
+
function withBaseTransform(base, dx, dy) {
|
|
62
|
+
const translate = `translate(${dx.toFixed(3)}px, ${dy.toFixed(3)}px)`;
|
|
63
|
+
return base === "none" ? translate : `${base} ${translate}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 让一次「不行 / 请先处理」的信号可见:目标摆几下后回到原位。
|
|
67
|
+
*
|
|
68
|
+
* 用于打断一次被拦下的操作(例如表单还有未保存内容却要退出),或把注意力拉回某个元素。
|
|
69
|
+
* 传 `target` 就只震那一块,不传就震整页。播放期间目标上已有的 `transform` 会被逐帧带上,
|
|
70
|
+
* 因此居中定位不会被震动吃掉。
|
|
71
|
+
*
|
|
72
|
+
* 两个幅度默认同值,所以不带参数是斜向摆;把某一轴设为 0 就只剩另一条轴,
|
|
73
|
+
* 两轴同相位所以合成轨迹始终是一条直线。
|
|
74
|
+
* 同一目标上重复调用会**重新开始**摆(撤掉上一条),而不是叠加成更大的位移;
|
|
75
|
+
* `prefers-reduced-motion`(系统或 `web-ui-theme` 的 motion 档位)下不产生任何位移。
|
|
76
|
+
*/
|
|
77
|
+
function shake(input) {
|
|
78
|
+
const { target, xDistance, yDistance, duration } = resolveOptions(input);
|
|
79
|
+
if (duration <= 0 || xDistance === 0 && yDistance === 0) return;
|
|
80
|
+
if (isReducedFor(target)) return;
|
|
81
|
+
if (typeof target.animate !== "function") return;
|
|
82
|
+
for (const animation of target.getAnimations()) if (animation.id === SHAKE_ANIMATION_ID) animation.cancel();
|
|
83
|
+
const base = getComputedStyle(target).transform;
|
|
84
|
+
const samples = [];
|
|
85
|
+
for (let i = 0; i <= SHAKE_SAMPLE_COUNT; i++) {
|
|
86
|
+
const t = i / SHAKE_SAMPLE_COUNT;
|
|
87
|
+
samples.push(-Math.sin(2 * Math.PI * SHAKE_CYCLES * t) * Math.exp(-3.2 * t));
|
|
88
|
+
}
|
|
89
|
+
const peak = Math.max(...samples.map(Math.abs));
|
|
90
|
+
const xUnit = xDistance / peak;
|
|
91
|
+
const yUnit = yDistance / peak;
|
|
92
|
+
const animation = target.animate(samples.map((sample, index) => ({
|
|
93
|
+
offset: index / SHAKE_SAMPLE_COUNT,
|
|
94
|
+
transform: withBaseTransform(base, sample * xUnit, sample * yUnit)
|
|
95
|
+
})), {
|
|
96
|
+
duration,
|
|
97
|
+
easing: "linear"
|
|
98
|
+
});
|
|
99
|
+
animation.id = SHAKE_ANIMATION_ID;
|
|
100
|
+
}
|
|
101
|
+
export { SHAKE_X_DISTANCE_FALLBACK, SHAKE_X_DISTANCE_VARIABLE, SHAKE_Y_DISTANCE_FALLBACK, SHAKE_Y_DISTANCE_VARIABLE, shake };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/shake/index.ts"],"sourcesContent":["import { findRootTheme } from '@/shared/overlay/theme-overlay-scope'\nimport { prefersReducedMotion } from '@/shared/theme/reduced-motion'\n\n/** `shake()` 的可选项。除 `target` 外都有默认值,`shake()` 不带参数即可用。 */\nexport interface ShakeOptions {\n /**\n * 位移目标。省略时震整页(`document.documentElement`):页面里 in-flow 与 `position: fixed`\n * 的内容一起跟着走,而 top layer 的 `<dialog>` 与它的 `::backdrop` 不受影响(Chromium 实测),\n * 因此正在打开的 drawer / dialog 不会跟着晃。\n */\n target?: HTMLElement\n /**\n * 横向首摆幅度(px)。省略时读目标计算样式上的 `--wui-shake-x-distance`。\n * 震整页时该 token 要写在 `html` / `:root` 上:主题元素在 body 之下,它的声明继承\n * 不到 `documentElement`(继承只往下走)。\n */\n xDistance?: number\n /**\n * 纵向幅度(px),默认与横向同值。省略时读目标计算样式上的 `--wui-shake-y-distance`。\n * 与横向同相位,所以合成位移沿一条直线、倾角由两个幅度决定;把横向置 `0` 就是纯上下摆,\n * 把纵向置 `0` 就是纯横摆。\n */\n yDistance?: number\n /** 整段时长(ms)。省略时读目标计算样式上的 `--wui-shake-duration`。 */\n duration?: number\n}\n\n/** 横向幅度 token 的名字;注册项与 JS 读取共用这一个字符串。 */\nexport const SHAKE_X_DISTANCE_VARIABLE = '--wui-shake-x-distance'\n/** 纵向幅度 token 的名字。 */\nexport const SHAKE_Y_DISTANCE_VARIABLE = '--wui-shake-y-distance'\nconst DURATION_PROPERTY = '--wui-shake-duration'\n\n/*\n * 两个 FALLBACK 各是对应注册项 initialValue 的镜像,**不是**第二真相源:浏览器里\n * computed style 永远有值,走不到这个兜底;保留它们只为 jsdom——那里没有 registerProperty,\n * 读回来是空串。shake.browser.spec.ts 有断言把两者钉在一起,防止漂移。\n * 两轴默认同值:不带参数就是斜向摆,单轴归零才只摆另一条轴。\n */\nexport const SHAKE_X_DISTANCE_FALLBACK = 12\nexport const SHAKE_Y_DISTANCE_FALLBACK = 12\n// 时长不注册,没有对应的 initialValue 可镜像,兜底就是唯一真相源。\nconst DURATION_FALLBACK = 420\n\n/** 挂在 Animation.id 上的标记,用于「同一次调用只保留一条震动」。 */\nconst SHAKE_ANIMATION_ID = 'wui-shake'\n\n/*\n * 波形:阻尼正弦 f(t) = -sin(2π·CYCLES·t)·e^(-DECAY·t),t ∈ [0, 1],负号让首摆先朝**自己幅度的负方向**\n * (默认两轴同幅,首摆朝左上)。\n *\n * - CYCLES 取**半整数**,于是 sin(2π·CYCLES) = 0:t=0 与 t=1 天然落在原位,收尾不需要额外补一条\n * 归零关键帧,也不会因为「最后一个采样点还剩一点振幅」而在动画结束时跳一下。\n * - 采样后按最大绝对值归一,`xDistance` 与 `yDistance` 因此就是**各自轴上实际摆出的最大位移**,\n * 不随 DECAY 漂移:改衰减只改「摆几下来回」,不改「摆多大」。两轴共用同一条采样序列,\n * 即**同相位**——合成轨迹因此是一条直线而不是椭圆轨道,方向可预期,读起来仍是「摆几下」。\n * - 采样点取 25(含首尾):420ms / 24 段 ≈ 17.5ms,约一帧一段,折线对正弦的逼近误差在\n * 亚像素量级,人眼读不出台阶。\n * - 关键帧之间的插值用 `linear`:整段 `easing` 会重排**每段之间的时间分配**,\n * ease-out 会把尾段拉长、首摆压短,而首摆正是「被拦下了」这一下信号,不能被压。\n */\nconst SHAKE_CYCLES = 3.5\nconst SHAKE_DECAY = 3.2\nconst SHAKE_SAMPLE_COUNT = 24\n\nif (typeof CSS !== 'undefined' && 'registerProperty' in CSS) {\n /*\n * 幅度注册为 <length>:消费方写 unitless 的 0 会在计算值阶段归一成 0px,读回来永远是带单位的\n * 长度;inherits 为 true,让挂在 html 或 web-ui-theme 上的一次改写覆盖到页面里任何一处调用点。\n * `<length>` 同时吃视口单位与 calc()(`2vmax`、`calc(1vmax + 4px)` 在两个引擎里都在计算值阶段\n * 落成确定 px),但**不接受百分号**——写了会静默回落到 initialValue。\n * 时长不注册为 <time>:注册项的计算值会按规范单位序列化成 `s`,一个名为 duration 却只能写\n * 毫秒数的 token 反而更容易读错,所以走「带单位读、按后缀换算」的解析。\n * 注册表是全局的,模块重复执行(HMR)时捕获已注册错误并忽略。\n */\n for (const [name, initialValue] of [\n [SHAKE_X_DISTANCE_VARIABLE, '12px'],\n [SHAKE_Y_DISTANCE_VARIABLE, '12px']\n ] as const) {\n try {\n CSS.registerProperty({ name, syntax: '<length>', inherits: true, initialValue })\n } catch {\n // 已注册(如 HMR 重复执行)时忽略\n }\n }\n}\n\nfunction readLength(target: HTMLElement, property: string, fallback: number): number {\n const parsed = Number.parseFloat(getComputedStyle(target).getPropertyValue(property))\n return Number.isFinite(parsed) ? parsed : fallback\n}\n\n/*\n * 时长读的是带单位的 CSS 时间字面量。计算值可能序列化成 `420ms`(未注册的原样透传)或\n * `0.42s`(注册为 <time> 的规范单位),所以按后缀换算,不能直接 parseFloat——那会把 0.42 当成\n * 0.42ms,整段震动塌成一次瞬移。\n */\nfunction readDuration(target: HTMLElement, property: string, fallback: number): number {\n const raw = getComputedStyle(target).getPropertyValue(property).trim()\n const value = Number.parseFloat(raw)\n if (!Number.isFinite(value)) return fallback\n return raw.endsWith('ms') ? value : value * 1000\n}\n\n/**\n * 目标所在范围是否要求减少动效。\n *\n * 指定 target 时按它自己的主题范围走。默认震整页时不能只看祖先:主题元素总在 body 之下,\n * `documentElement` 往上走找不到它们,于是 `shake()` 会和页面里其它动效认的档位分叉。\n * 这里改用**根主题**——与 toast / imagePreview 解析挂载根时同一个 `findRootTheme()`,\n * 命令式入口的「页面级默认值」两条路径认的是同一个主题;没有主题范围时回退系统偏好。\n */\nfunction isReducedFor(target: HTMLElement): boolean {\n if (target !== document.documentElement) return prefersReducedMotion(target)\n const theme = findRootTheme()\n return theme ? theme.isReducedMotion() : prefersReducedMotion(target)\n}\n\nfunction resolveOptions(input: HTMLElement | ShakeOptions | undefined): {\n target: HTMLElement\n xDistance: number\n yDistance: number\n duration: number\n} {\n const options: ShakeOptions = input instanceof HTMLElement ? { target: input } : (input ?? {})\n const target = options.target ?? document.documentElement\n return {\n target,\n xDistance: options.xDistance ?? readLength(target, SHAKE_X_DISTANCE_VARIABLE, SHAKE_X_DISTANCE_FALLBACK),\n yDistance: options.yDistance ?? readLength(target, SHAKE_Y_DISTANCE_VARIABLE, SHAKE_Y_DISTANCE_FALLBACK),\n duration: options.duration ?? readDuration(target, DURATION_PROPERTY, DURATION_FALLBACK)\n }\n}\n\n/**\n * 关键帧里写的是 `<transform-list>`,而计算值在没有变换时是 `none`——`none translate(-6px, 0px)`\n * 不是合法的变换列表,整条关键帧会被丢弃。\n */\nfunction withBaseTransform(base: string, dx: number, dy: number): string {\n const translate = `translate(${dx.toFixed(3)}px, ${dy.toFixed(3)}px)`\n return base === 'none' ? translate : `${base} ${translate}`\n}\n\n/**\n * 让一次「不行 / 请先处理」的信号可见:目标摆几下后回到原位。\n *\n * 用于打断一次被拦下的操作(例如表单还有未保存内容却要退出),或把注意力拉回某个元素。\n * 传 `target` 就只震那一块,不传就震整页。播放期间目标上已有的 `transform` 会被逐帧带上,\n * 因此居中定位不会被震动吃掉。\n *\n * 两个幅度默认同值,所以不带参数是斜向摆;把某一轴设为 0 就只剩另一条轴,\n * 两轴同相位所以合成轨迹始终是一条直线。\n * 同一目标上重复调用会**重新开始**摆(撤掉上一条),而不是叠加成更大的位移;\n * `prefers-reduced-motion`(系统或 `web-ui-theme` 的 motion 档位)下不产生任何位移。\n */\nexport function shake(input?: HTMLElement | ShakeOptions): void {\n const { target, xDistance, yDistance, duration } = resolveOptions(input)\n // 两轴都为 0 才是「什么都不摆」:单轴归零只是把那条轴摘掉,另一轴照旧。\n if (duration <= 0 || (xDistance === 0 && yDistance === 0)) return\n // 前庭动效敏感用户的档位:不摆,也不留任何状态。\n if (isReducedFor(target)) return\n // jsdom 等没有 WAAPI 的环境:命令式入口不该因为「测试环境没有动画」而抛错。\n if (typeof target.animate !== 'function') return\n\n // 重触发时先撤掉自己上一条:同一属性上的两条动画会各自生效,读起来是「位移翻倍」而不是「重摆」。\n for (const animation of target.getAnimations()) {\n if (animation.id === SHAKE_ANIMATION_ID) animation.cancel()\n }\n\n const base = getComputedStyle(target).transform\n const samples: number[] = []\n for (let i = 0; i <= SHAKE_SAMPLE_COUNT; i++) {\n const t = i / SHAKE_SAMPLE_COUNT\n samples.push(-Math.sin(2 * Math.PI * SHAKE_CYCLES * t) * Math.exp(-SHAKE_DECAY * t))\n }\n const peak = Math.max(...samples.map(Math.abs))\n // 采样点里必有非零波峰(由 SHAKE_CYCLES 与 SHAKE_SAMPLE_COUNT 决定),按它把幅度归一到峰值。\n const xUnit = xDistance / peak\n const yUnit = yDistance / peak\n\n const animation = target.animate(\n samples.map((sample, index) => ({\n offset: index / SHAKE_SAMPLE_COUNT,\n transform: withBaseTransform(base, sample * xUnit, sample * yUnit)\n })),\n { duration, easing: 'linear' }\n )\n animation.id = SHAKE_ANIMATION_ID\n}\n"],"mappings":"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"}
|
|
@@ -6,9 +6,6 @@ export declare class WebUiSpinner extends LitElement {
|
|
|
6
6
|
/** 叶片颜色;空字符串时跟随主题次要文本色。 */
|
|
7
7
|
color: string;
|
|
8
8
|
private _ariaLabel?;
|
|
9
|
-
private readonly _overlay;
|
|
10
|
-
private _overlayHandle?;
|
|
11
|
-
private readonly _scrollLock;
|
|
12
9
|
/**
|
|
13
10
|
* 显示一个全屏加载实例并挂载到主题 overlay root(无主题时挂载到 fallback overlay root);新实例会替换之前由此方法创建的实例。
|
|
14
11
|
* @param options 尺寸、说明文字、颜色与可选自动关闭时长。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/spinner/index.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/spinner/index.ts"],"mappings":";qBA8Ba,qBAAqB;SAChB,sBAAM;EAEqB;EACf;;EAEA;UACiC;;;;;;SAOtD,KAAK;IAAY;IAAe;IAAmB;IAAsB;MAAmB;SA6B5F;;SAcA,WAAW;;EAGlB;;EAEA,SAAS,kBAAkB;EAElB;EAgBA;YAaU,QAAQ,OAAO;UAQ1B;UAeA;UAIA;EAOC,wBAAM;;QAsBT;YACI;IACR,kBAAkB"}
|