@greypan/web-ui 10.1.0 → 10.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.CN.md +10 -1
  2. package/README.md +12 -1
  3. package/dist/components/autocomplete/index.js +62 -60
  4. package/dist/components/autocomplete/index.js.map +1 -1
  5. package/dist/components/collapse/index.js +1 -1
  6. package/dist/components/collapse/index.js.map +1 -1
  7. package/dist/components/collapse/style.js +1 -1
  8. package/dist/components/collapse/style.js.map +1 -1
  9. package/dist/components/context-menu/index.d.ts +16 -0
  10. package/dist/components/context-menu/index.js +9 -4
  11. package/dist/components/context-menu/index.js.map +1 -1
  12. package/dist/components/dialog/index.js +39 -37
  13. package/dist/components/dialog/index.js.map +1 -1
  14. package/dist/components/drawer/index.js +64 -62
  15. package/dist/components/drawer/index.js.map +1 -1
  16. package/dist/components/empty/style.js +1 -1
  17. package/dist/components/empty/style.js.map +1 -1
  18. package/dist/components/segmented/index.js +17 -7
  19. package/dist/components/segmented/index.js.map +1 -1
  20. package/dist/components/select/index.js +45 -43
  21. package/dist/components/select/index.js.map +1 -1
  22. package/dist/components/toast/manager.js +1 -1
  23. package/dist/components/toast/manager.js.map +1 -1
  24. package/dist/scrollbars/internal.js +6 -0
  25. package/dist/scrollbars/internal.js.map +1 -0
  26. package/dist/scrollbars/style.css +1 -1
  27. package/dist/shared/menu-portal/menu-portal.js +16 -14
  28. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  29. package/dist/shared/overlay/overlay-root.js +13 -12
  30. package/dist/shared/overlay/overlay-root.js.map +1 -1
  31. package/package.json +1 -1
package/README.CN.md CHANGED
@@ -53,6 +53,12 @@ import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue' // 或 overla
53
53
  所以宿主自身的布局一旦承重(grid、居中盒子、`ul`/`ol`)就会坏。
54
54
  - OverlayScrollbars 只改变它被初始化到的那个元素,子元素保持原生滚动条。要覆盖文档滚动条就初始化
55
55
  `document.body`——在那里 `window.scrollY` / `window.scrollTo` 保持原生语义。
56
+ - 自带滚动容器的组件(`select`、`autocomplete`、dropdown / context-menu 面板、`dialog`、`drawer`、
57
+ `toast`)在各自的 shadow root 内给**组件内部**滚动条上主题。OverlayScrollbars 进不了 shadow
58
+ root——它的结构样式与主题类都是文档级选择器——所以组件改为在原生滚动条上读同一组继承的
59
+ `--wui-scrollbar-*` 颜色(`scrollbar-color` / `scrollbar-width`),并刻意不用 `::-webkit-scrollbar`:
60
+ 声明它会让引擎放弃平台的覆盖式滚动条、固定占一条布局宽度,而组件内部滚动条正是不能占宽度。
61
+ 导入本样式表,组件内部滚动条才会跟随外观,与整页滚动条同一机制。
56
62
 
57
63
  ## Vite
58
64
 
@@ -685,7 +691,7 @@ Portal 面板创建时会镜像 host 上解析后的这些变量;更新 host
685
691
 
686
692
  根据 `value` 同步子 trigger 的 `checked` 状态。`disabled` 提供继承的有效禁用状态,不改写 trigger 自身的 `disabled` 属性。直接设 `value` 不派发事件。
687
693
 
688
- 按住当前选中项横向拖拽可滑动指示器,松手吸附到最近选项(快速抛掷按速度切换)。触摸面声明 `touch-action: none`,拖拽激活期间阻止 `touchmove` 默认滚动,避免 iOS Safari 中断手势。
694
+ 按住当前选中项横向拖拽可滑动指示器,松手吸附到最近选项(快速抛掷按速度切换)。trigger 宽度不等时,拖拽中的指示器取「离自身中心最近的那一项」的宽度——即预览松手会落到的那一项,而不是保持按下那一项的宽度。触摸面声明 `touch-action: none`,拖拽激活期间阻止 `touchmove` 默认滚动,避免 iOS Safari 中断手势。
689
695
 
690
696
  **按压态:** 轨道在所有状态下都是不透明实体面(`--wui-color-surface`,浅色即 page 同色、无 backdrop filter),1px 描边环与投影全程不变;转为玻璃的是指示器这一层。静止态指示器是 `--wui-color-surface-segmented` 实色底、玻璃输出全部关闭;按压/拖拽态获得 backdrop blur、随 80ms 过渡淡入的玻璃描边环与 1.5x 放大,底色全透明:指示器的 blur 采样面整个落在轨道之内,此前的玻璃轨道上全透明指示器在均匀深底与相邻轨道仅差 +0.5 阶,条纹底实测指示器内部灰度 std 1.89(背景渗透);轨道实体化后同一采样 std 归零,按压态本体的可感知性由实色轨道与放大/环/投影共同承担,不再需要 tint 打底或压制轨道边缘装饰。底色不淡入——按下第一帧即落定;松开时指示器经 `--wui-duration-press` 淡回实色灰底。
691
697
 
@@ -1087,6 +1093,9 @@ await preview.closed
1087
1093
  | `--wui-collapse-peek-edge-max` | `112px` | 长度上限,避免大 `peek` 算出过长的虚化带 |
1088
1094
  | `--wui-collapse-peek-edge` | — | 显式指定长度,优先于推导值 |
1089
1095
  | `--wui-collapse-peek-edge-color` | `transparent` | 渐变末端颜色(需带 alpha,mask 按 alpha 解析) |
1096
+ | `--wui-collapse-peek-edge-blur` | `4px` | 同一条渐变带上背景模糊的半径 |
1097
+
1098
+ 渐变带由两层组成,配对方式与 layout header 的晕染一致:上面那条 alpha 渐隐之外,同一条带上再叠一层真实的 `backdrop-filter` 模糊,被裁掉的内容因此是被**糊掉**的,而不只是被调成半透明。模糊强度由本盒自己的 `mask-image` 调制——从带子起点为 0 升到后半段满强度、再在裁剪边缘前回到 0:起点不为 0 会在「突然开始模糊」处留一条接缝,末端不为 0 则会一路糊到裁剪边界。展开态活动长度为 0,各色标塌缩到 100% 而末位色标是全透明,于是这一层什么都不画。
1090
1099
 
1091
1100
  比例设为 `0` 即关闭渐隐。推导是纯 CSS 的 `calc(peek * ratio)`:`peek` 用 rem 时渐变长度自动跟随根字号缩放,JS 侧不需要做任何单位解析。已知限制:`peek` 取百分比时推导结果不是长度、无法被注册属性插值,会静默回落为「无渐隐」,此时请用 `--wui-collapse-peek-edge` 显式指定长度。
1092
1101
 
package/README.md CHANGED
@@ -55,6 +55,14 @@ import { OverlayScrollbarsComponent } from 'overlayscrollbars-react' // or overl
55
55
  - OverlayScrollbars only changes the element it is initialized on; children keep their native scrollbars. To cover
56
56
  the document scroller, initialize `document.body` — `window.scrollY` / `window.scrollTo` keep their native
57
57
  semantics there.
58
+ - Components that own a scroll container (`select`, `autocomplete`, the dropdown / context-menu panels,
59
+ `dialog`, `drawer`, `toast`) theme that container's **internal** scrollbar inside their own shadow root.
60
+ OverlayScrollbars cannot reach a shadow root — its structural styles and theme classes are document-level
61
+ selectors — so the components read the same inherited `--wui-scrollbar-*` colours through `scrollbar-color`
62
+ / `scrollbar-width` on the native scrollbar instead. `::-webkit-scrollbar` is deliberately not used: styling
63
+ it opts out of the platform's overlay scrollbar and reserves a layout gutter, which these scrollbars must
64
+ not do. Import this stylesheet for the internal scrollbars to follow the appearance, just like the
65
+ page-level ones.
58
66
 
59
67
  ## Vite
60
68
 
@@ -723,7 +731,7 @@ Form-associated: integrates with native `<form>` via `ElementInternals`.
723
731
 
724
732
  Manages child trigger `checked` state based on `value`. `disabled` supplies inherited effective disabled state without changing a trigger's own `disabled` property. Setting `value` directly does not dispatch `input`/`change`.
725
733
 
726
- Press the selected segment and drag horizontally to slide the indicator; on release it snaps to the nearest option (a fast flick switches by velocity). Touch surfaces declare `touch-action: none` and suppress `touchmove` defaulting during an active drag, so iOS Safari does not interrupt the gesture.
734
+ Press the selected segment and drag horizontally to slide the indicator; on release it snaps to the nearest option (a fast flick switches by velocity). While dragging with triggers of unequal width, the indicator takes the width of the option its center is nearest to, so it previews the option it will snap to instead of keeping the pressed segment's width. Touch surfaces declare `touch-action: none` and suppress `touchmove` defaulting during an active drag, so iOS Safari does not interrupt the gesture.
727
735
 
728
736
  **Pressed state:** the track is an opaque surface (`--wui-color-surface`, page-colored in light appearance) with no backdrop filter in every state. Its 1px ring and drop shadow never change. The indicator is the layer that turns to glass. At rest it is a solid `--wui-color-surface-segmented` surface with all glass output off. While pressed or dragging it gains backdrop blur, the glass ring fading in over 80ms, and a 1.5x scale over a fully transparent background: the indicator samples its blur entirely from inside the track, and against the previous glass track a fully transparent indicator measured only +0.5 gray levels on a uniform dark backdrop while striped backdrops showed through the sample (std 1.89 gray levels inside the indicator). The opaque track makes that sample uniform (std 0), which is what gives the pressed thumb a perceptible body. No tint and no edge-decoration suppression are needed. The background never fades in. It lands on the first pressed frame. And on release the indicator eases back to the solid gray rest surface over `--wui-duration-press`.
729
737
 
@@ -1128,6 +1136,9 @@ The initial `open` attribute settles instantly without playing the animation. Ne
1128
1136
  | `--wui-collapse-peek-edge-max` | `112px` | Upper bound, so a large `peek` cannot produce an oversized fade band |
1129
1137
  | `--wui-collapse-peek-edge` | — | Explicit fade length; wins over the derived value |
1130
1138
  | `--wui-collapse-peek-edge-color` | `transparent` | Fade-stop color (must carry alpha - `mask-image` reads alpha channel) |
1139
+ | `--wui-collapse-peek-edge-blur` | `4px` | Blur radius of the frost layer over the same band |
1140
+
1141
+ The band carries two layers, the same pairing the layout header's glow uses: the alpha fade above, plus a real `backdrop-filter` blur over the same band, so the clipped content is blurred out rather than merely made translucent. The blur is modulated by the band's own `mask-image`, ramping from 0 at the band's start to full in its second half and back to 0 at the cut edge - a non-zero start would draw a visible seam where the blur abruptly begins, and a non-zero end would blur right up to the clip boundary. When `open`, the band length is `0`, every mask stop collapses onto 100% and the last stop is fully transparent, so the layer paints nothing.
1131
1142
 
1132
1143
  Set the ratio to `0` to turn the fade off. The derivation is pure CSS `calc(peek * ratio)`, so a `rem`-based `peek` scales the fade with the root font size and nothing has to be measured in JS. Known limitation: a percentage `peek` does not derive to a length, so the fade silently falls back to "none". Set `--wui-collapse-peek-edge` explicitly in that case.
1133
1144
 
@@ -4,32 +4,33 @@ import { FormAssociated as n, FormAssociationController as r, defineFormAssociat
4
4
  import { normalizeLiteral as a } from "../../shared/normalize/index.js";
5
5
  import "../input/index.js";
6
6
  import o from "../../assets/overlay-motion.js";
7
- import { dispatchOpenChangeEvent as s } from "../../shared/open-state/index.js";
8
- import { createComboboxOpenController as c, createOptionListenerBinding as l, defineComboboxTrigger as u, handleComboboxFocusOut as d, nextWrappingIndex as f } from "../../shared/option-portal/combobox-shell.js";
9
- import { defineOptionPortal as p } from "../../shared/option-portal/index.js";
10
- import { defineAnchoredPanel as m } from "../../shared/overlay/anchored-panel.js";
11
- import { defineOpenOverlay as h } from "../../shared/overlay/open-overlay.js";
12
- import { applyOverlayVariables as g, defineOverlayPortal as _ } from "../../shared/overlay/portal.js";
13
- import { defineScrollLockLease as v } from "../../shared/scroll-lock/scroll-lock.js";
14
- import y from "./style.js";
15
- import { LitElement as b, html as x, nothing as S, unsafeCSS as C } from "lit";
16
- import { customElement as w, property as T, state as E } from "lit/decorators.js";
17
- import { ifDefined as D } from "lit/directives/if-defined.js";
7
+ import s from "../../scrollbars/internal.js";
8
+ import { dispatchOpenChangeEvent as c } from "../../shared/open-state/index.js";
9
+ import { createComboboxOpenController as l, createOptionListenerBinding as u, defineComboboxTrigger as d, handleComboboxFocusOut as f, nextWrappingIndex as p } from "../../shared/option-portal/combobox-shell.js";
10
+ import { defineOptionPortal as m } from "../../shared/option-portal/index.js";
11
+ import { defineAnchoredPanel as h } from "../../shared/overlay/anchored-panel.js";
12
+ import { defineOpenOverlay as g } from "../../shared/overlay/open-overlay.js";
13
+ import { applyOverlayVariables as _, defineOverlayPortal as v } from "../../shared/overlay/portal.js";
14
+ import { defineScrollLockLease as y } from "../../shared/scroll-lock/scroll-lock.js";
15
+ import b from "./style.js";
16
+ import { LitElement as x, html as S, nothing as C, unsafeCSS as w } from "lit";
17
+ import { customElement as T, property as E, state as D } from "lit/decorators.js";
18
+ import { ifDefined as O } from "lit/directives/if-defined.js";
18
19
  //#region src/components/autocomplete/index.ts
19
- var O, k = [
20
+ var k, A = [
20
21
  "none",
21
22
  "prefix",
22
23
  "contains"
23
24
  ];
24
- function A(e) {
25
+ function j(e) {
25
26
  return e instanceof Element && e.slot === "trigger";
26
27
  }
27
- function j(e) {
28
+ function M(e) {
28
29
  return e instanceof Element && e.slot === "empty";
29
30
  }
30
- var M = class extends n(b) {
31
+ var N = class extends n(x) {
31
32
  static {
32
- O = this;
33
+ k = this;
33
34
  }
34
35
  constructor(...e) {
35
36
  super(...e), this.placeholder = "", this.borderless = !1, this.disabled = !1, this.readonly = !1, this.required = !1, this.portal = !1, this.noScrollLock = !1, this.allowCustomValue = !1, this.name = "", this.ariaLabel = null, this._filter = "contains", this._value = "", this._selectedValue = "", this._formAssociation = i({
@@ -48,18 +49,18 @@ var M = class extends n(b) {
48
49
  typeof e == "string" && (this.value = e);
49
50
  },
50
51
  syncValidity: () => this._syncValidity()
51
- }).make(), this._formAssociationController = new r(this, this._formAssociation), this._isOpen = !1, this._activeIndex = -1, this._focused = !1, this._hasTriggerSlot = !1, this._idPrefix = `web-ui-autocomplete-${++O._nextInstanceId}`, this._a11yOptionIds = /* @__PURE__ */ new WeakMap(), this._nextA11yOptionId = 0, this._options = [], this._scrollLock = v().make(), this._optionPortal = p().make({
52
+ }).make(), this._formAssociationController = new r(this, this._formAssociation), this._isOpen = !1, this._activeIndex = -1, this._focused = !1, this._hasTriggerSlot = !1, this._idPrefix = `web-ui-autocomplete-${++k._nextInstanceId}`, this._a11yOptionIds = /* @__PURE__ */ new WeakMap(), this._nextA11yOptionId = 0, this._options = [], this._scrollLock = y().make(), this._optionPortal = m().make({
52
53
  element: this,
53
54
  idPrefix: `${this._idPrefix}-option`,
54
55
  getPortal: () => this._portal,
55
56
  getPortalContent: () => this._portalContent,
56
57
  isOpen: () => this.portal && this._isOpen,
57
- getMigratableNodes: () => Array.from(this.childNodes).filter((e) => !A(e) && !j(e)),
58
+ getMigratableNodes: () => Array.from(this.childNodes).filter((e) => !j(e) && !M(e)),
58
59
  hasUpdated: () => this.hasUpdated,
59
60
  requestUpdate: () => this.requestUpdate(),
60
61
  bindOption: (e) => this._bindOption(e),
61
62
  unbindOption: (e) => this._unbindOption(e)
62
- }), this._trigger = u().make({
63
+ }), this._trigger = d().make({
63
64
  getWrapper: () => this.shadowRoot?.querySelector(".autocomplete-trigger") ?? null,
64
65
  getCustomTrigger: () => {
65
66
  let e = this.shadowRoot?.querySelector("slot[name=\"trigger\"]")?.assignedElements()[0];
@@ -70,10 +71,10 @@ var M = class extends n(b) {
70
71
  onClick: () => this._onTriggerClick(),
71
72
  onFocusIn: (e) => this._onTriggerFocusIn(e),
72
73
  onFocusOut: (e) => this._onTriggerFocusOut(e)
73
- }), this._overlay = h().make({
74
+ }), this._overlay = g().make({
74
75
  requestClose: () => this._close(),
75
76
  isConnected: () => this.isConnected
76
- }), this._panel = m().make({
77
+ }), this._panel = h().make({
77
78
  getAnchor: () => this._trigger.getTrigger() ?? this.shadowRoot?.querySelector(".autocomplete-trigger") ?? null,
78
79
  getLocalPanel: () => this.shadowRoot?.querySelector(".autocomplete-overlay") ?? null,
79
80
  getPositioning: () => ({
@@ -88,12 +89,12 @@ var M = class extends n(b) {
88
89
  }), this._onClickOutside = (e) => {
89
90
  this._isOpen && (e.composedPath().includes(this) || this._panel.getHandle()?.containsEvent(e) || this._close());
90
91
  }, this._onFocusOut = () => {
91
- d(this, () => this._panel.getHandle(), () => this._isOpen, () => this._close());
92
+ f(this, () => this._panel.getHandle(), () => this._isOpen, () => this._close());
92
93
  }, this._handlePanelPointerDown = (e) => {
93
94
  e.preventDefault();
94
95
  }, this._onTriggerSlotChange = () => {
95
96
  this._syncTriggerSlot();
96
- }, this._optionListeners = l({
97
+ }, this._optionListeners = u({
97
98
  onClick: (e) => this._handleOptionClick(e),
98
99
  onPointerOver: (e) => this._handleOptionPointerOver(e),
99
100
  onPointerDown: (e) => this._handleOptionPointerDown(e),
@@ -151,7 +152,7 @@ var M = class extends n(b) {
151
152
  composed: !0,
152
153
  relatedTarget: e.relatedTarget
153
154
  }));
154
- }, this._openController = c({
155
+ }, this._openController = l({
155
156
  canOpen: () => !this._isDisabled && !this.readonly,
156
157
  getIsOpen: () => this._isOpen,
157
158
  setIsOpen: (e) => {
@@ -175,9 +176,10 @@ var M = class extends n(b) {
175
176
  }
176
177
  static {
177
178
  this.styles = [
178
- C(t),
179
- C(o),
180
- C(y)
179
+ w(t),
180
+ w(o),
181
+ w(s),
182
+ w(b)
181
183
  ];
182
184
  }
183
185
  get filter() {
@@ -185,7 +187,7 @@ var M = class extends n(b) {
185
187
  }
186
188
  set filter(e) {
187
189
  let t = this._filter;
188
- this._filter = a(e, k, "contains"), this.requestUpdate("filter", t);
190
+ this._filter = a(e, A, "contains"), this.requestUpdate("filter", t);
189
191
  }
190
192
  get value() {
191
193
  return this._value;
@@ -223,7 +225,7 @@ var M = class extends n(b) {
223
225
  super.connectedCallback(), this._optionPortal.bindHost(), this._trigger.bind(), this.addEventListener("keydown", this._onKeydown), this.addEventListener("focusout", this._onFocusOut), document.addEventListener("click", this._onClickOutside);
224
226
  }
225
227
  _syncTriggerSlot() {
226
- let e = Array.from(this.children).some(A);
228
+ let e = Array.from(this.children).some(j);
227
229
  this._hasTriggerSlot !== e && (this._hasTriggerSlot = e, this.hasUpdated && this._reconfigureOverlay());
228
230
  }
229
231
  attributeChangedCallback(e, t, n) {
@@ -294,7 +296,7 @@ var M = class extends n(b) {
294
296
  let t = this._options.filter((e) => !e.disabled && !e.hasAttribute("data-filtered"));
295
297
  if (!t.length) return;
296
298
  let n = this._activeIndex >= 0 ? t.indexOf(this._options[this._activeIndex]) : e > 0 ? -1 : 0;
297
- this._activeIndex = this._options.indexOf(t[f(t.length, n, e)]), this._syncActiveOption();
299
+ this._activeIndex = this._options.indexOf(t[p(t.length, n, e)]), this._syncActiveOption();
298
300
  }
299
301
  _setInitialActiveOption() {
300
302
  let e = this._options.findIndex((e) => !e.disabled && !e.hasAttribute("data-filtered"));
@@ -347,7 +349,7 @@ var M = class extends n(b) {
347
349
  this._openController.close();
348
350
  }
349
351
  _dispatchOpenChange() {
350
- s(this, this._isOpen);
352
+ c(this, this._isOpen);
351
353
  }
352
354
  _openOverlay(e = !1) {
353
355
  this._panel.open(e), this._syncOverlayInert();
@@ -362,25 +364,25 @@ var M = class extends n(b) {
362
364
  this._scrollLock.sync(e && !this.noScrollLock);
363
365
  }
364
366
  _createPortal() {
365
- let e = _().make({
367
+ let e = v().make({
366
368
  container: this.overlayContainer,
367
369
  target: this,
368
- style: `${t}\n${o}\n${y}`,
370
+ style: `${t}\n${o}\n${b}`,
369
371
  className: "wui-glass autocomplete-overlay portal wui-floating-panel",
370
372
  onContentChange: () => {
371
373
  this._optionPortal.scheduleRefresh();
372
374
  }
373
375
  });
374
- this._portal = e, g(e.panel, this, [
376
+ this._portal = e, _(e.panel, this, [
375
377
  "--wui-overlay-min-width",
376
378
  "--wui-autocomplete-max-width",
377
379
  "--wui-autocomplete-max-height"
378
380
  ]), e.panel.setAttribute("aria-hidden", "true"), e.panel.addEventListener("pointerdown", this._handlePanelPointerDown);
379
381
  let n = document.createElement("div");
380
- n.className = "autocomplete-scroll";
382
+ n.className = "autocomplete-scroll wui-scroll";
381
383
  let r = document.createElement("div");
382
384
  r.className = "autocomplete-content", this._portalContent = r, n.append(r), e.panel.append(n);
383
- for (let t of Array.from(this.childNodes)) t instanceof Comment || A(t) || j(t) || e.appendContent([t], r);
385
+ for (let t of Array.from(this.childNodes)) t instanceof Comment || j(t) || M(t) || e.appendContent([t], r);
384
386
  return e;
385
387
  }
386
388
  _getLabelledbyText() {
@@ -392,10 +394,10 @@ var M = class extends n(b) {
392
394
  }).filter(Boolean).join(" ") : "";
393
395
  }
394
396
  render() {
395
- let e = `${this._idPrefix}-listbox`, t = `${this._idPrefix}-label`, n = this._getLabelledbyText(), r = this._options.filter((e) => !e.hasAttribute("data-filtered")), i = this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex] : void 0, a = i ? this._getA11yOptionId(i) : S;
396
- return x`
397
+ let e = `${this._idPrefix}-listbox`, t = `${this._idPrefix}-label`, n = this._getLabelledbyText(), r = this._options.filter((e) => !e.hasAttribute("data-filtered")), i = this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex] : void 0, a = i ? this._getA11yOptionId(i) : C;
398
+ return S`
397
399
  <div class="wui-autocomplete-inner">
398
- ${n ? x`<span class="autocomplete-a11y-only" id=${t}>${n}</span>` : S}
400
+ ${n ? S`<span class="autocomplete-a11y-only" id=${t}>${n}</span>` : C}
399
401
  <div
400
402
  class="autocomplete-trigger"
401
403
  ?data-custom-trigger=${this._hasTriggerSlot}
@@ -405,14 +407,14 @@ var M = class extends n(b) {
405
407
  aria-autocomplete="list"
406
408
  aria-controls=${e}
407
409
  aria-disabled=${String(this._isDisabled)}
408
- aria-readonly=${this.readonly ? "true" : S}
409
- aria-label=${D(this.ariaLabel)}
410
- aria-labelledby=${n ? t : S}
410
+ aria-readonly=${this.readonly ? "true" : C}
411
+ aria-label=${O(this.ariaLabel)}
412
+ aria-labelledby=${n ? t : C}
411
413
  aria-activedescendant=${a}
412
414
  tabindex="-1"
413
415
  >
414
416
  <slot name="trigger" @slotchange=${this._onTriggerSlotChange}></slot>
415
- ${this._hasTriggerSlot ? S : x`<web-ui-input
417
+ ${this._hasTriggerSlot ? C : S`<web-ui-input
416
418
  class="autocomplete-input"
417
419
  .value=${this._value}
418
420
  placeholder=${this.placeholder}
@@ -421,7 +423,7 @@ var M = class extends n(b) {
421
423
  ?disabled=${this._isDisabled}
422
424
  ?readonly=${this.readonly}
423
425
  ?required=${this.required}
424
- aria-label=${D(this.ariaLabel || n || void 0)}
426
+ aria-label=${O(this.ariaLabel || n || void 0)}
425
427
  ></web-ui-input>`}
426
428
  </div>
427
429
  <div
@@ -431,7 +433,7 @@ var M = class extends n(b) {
431
433
  ?hidden=${!this._isOpen}
432
434
  aria-hidden=${String(!this._isOpen)}
433
435
  >
434
- ${r.map((e) => x`<div
436
+ ${r.map((e) => S`<div
435
437
  id=${this._getA11yOptionId(e)}
436
438
  role="option"
437
439
  aria-selected=${e.value === this._selectedValue ? "true" : "false"}
@@ -447,7 +449,7 @@ var M = class extends n(b) {
447
449
  aria-hidden="true"
448
450
  @pointerdown=${this._handlePanelPointerDown}
449
451
  >
450
- <div class="autocomplete-scroll">
452
+ <div class="autocomplete-scroll wui-scroll">
451
453
  <div class="autocomplete-content">
452
454
  <slot @slotchange=${this._onSlotChange}></slot>
453
455
  </div>
@@ -457,46 +459,46 @@ var M = class extends n(b) {
457
459
  `;
458
460
  }
459
461
  };
460
- e([T({
462
+ e([E({
461
463
  type: String,
462
464
  reflect: !0
463
- })], M.prototype, "placeholder", void 0), e([T({
465
+ })], N.prototype, "placeholder", void 0), e([E({
464
466
  type: Boolean,
465
467
  reflect: !0
466
- })], M.prototype, "borderless", void 0), e([T({
468
+ })], N.prototype, "borderless", void 0), e([E({
467
469
  type: Boolean,
468
470
  reflect: !0
469
- })], M.prototype, "disabled", void 0), e([T({
471
+ })], N.prototype, "disabled", void 0), e([E({
470
472
  type: Boolean,
471
473
  reflect: !0
472
- })], M.prototype, "readonly", void 0), e([T({
474
+ })], N.prototype, "readonly", void 0), e([E({
473
475
  type: Boolean,
474
476
  reflect: !0
475
- })], M.prototype, "required", void 0), e([T({
477
+ })], N.prototype, "required", void 0), e([E({
476
478
  type: Boolean,
477
479
  reflect: !0
478
- })], M.prototype, "portal", void 0), e([T({
480
+ })], N.prototype, "portal", void 0), e([E({
479
481
  type: Boolean,
480
482
  reflect: !0,
481
483
  attribute: "no-scroll-lock"
482
- })], M.prototype, "noScrollLock", void 0), e([T({
484
+ })], N.prototype, "noScrollLock", void 0), e([E({
483
485
  type: Boolean,
484
486
  reflect: !0,
485
487
  attribute: "allow-custom-value"
486
- })], M.prototype, "allowCustomValue", void 0), e([T({ attribute: !1 })], M.prototype, "overlayContainer", void 0), e([T({
488
+ })], N.prototype, "allowCustomValue", void 0), e([E({ attribute: !1 })], N.prototype, "overlayContainer", void 0), e([E({
487
489
  type: String,
488
490
  reflect: !0
489
- })], M.prototype, "name", void 0), e([T({
491
+ })], N.prototype, "name", void 0), e([E({
490
492
  type: String,
491
493
  attribute: "aria-label"
492
- })], M.prototype, "ariaLabel", void 0), e([T({
494
+ })], N.prototype, "ariaLabel", void 0), e([E({
493
495
  type: String,
494
496
  attribute: "aria-labelledby"
495
- })], M.prototype, "ariaLabelledby", void 0), e([T({
497
+ })], N.prototype, "ariaLabelledby", void 0), e([E({
496
498
  type: String,
497
499
  reflect: !0
498
- })], M.prototype, "filter", null), e([E()], M.prototype, "_value", void 0), e([E()], M.prototype, "_selectedValue", void 0), e([E()], M.prototype, "_isOpen", void 0), e([E()], M.prototype, "_activeIndex", void 0), e([E()], M.prototype, "_focused", void 0), e([E()], M.prototype, "_hasTriggerSlot", void 0), M = O = e([w("web-ui-autocomplete")], M);
500
+ })], N.prototype, "filter", null), e([D()], N.prototype, "_value", void 0), e([D()], N.prototype, "_selectedValue", void 0), e([D()], N.prototype, "_isOpen", void 0), e([D()], N.prototype, "_activeIndex", void 0), e([D()], N.prototype, "_focused", void 0), e([D()], N.prototype, "_hasTriggerSlot", void 0), N = k = e([T("web-ui-autocomplete")], N);
499
501
  //#endregion
500
- export { M as WebUiAutocomplete };
502
+ export { N as WebUiAutocomplete };
501
503
 
502
504
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/autocomplete/index.ts"],"sourcesContent":["import '@/components/input'\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 glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport type { WebUiOption } from '@/components/option'\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 defineComboboxTrigger,\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\nconst FILTER_MODES = ['none', 'prefix', 'contains'] as const\ntype FilterMode = (typeof FILTER_MODES)[number]\n\n// 自定义 trigger 与 select 同判据:必须留在宿主,不随 options 迁入 portal 面板\nfunction isTriggerSlotNode(node: Node): node is Element {\n return node instanceof Element && node.slot === 'trigger'\n}\n\n// 已移除的 empty slot 仍可能留在既有消费者 light DOM;不得把它作为普通内容迁入 portal。\nfunction isEmptySlotNode(node: Node): node is Element {\n return node instanceof Element && node.slot === 'empty'\n}\n\n/**\n * `web-ui-autocomplete`:可输入并过滤候选的单值选择器。\n *\n * 与 `web-ui-select` 共用 `<web-ui-option>` 子项注册协议与浮层能力,但触发区是\n * 可编辑输入框:`value` 即当前输入文本(表单值),键入时按 `filter` 模式过滤候选,\n * 选择 option 时文本回填为该项 label,`selected-value` 暴露该项的 value。\n * `allow-custom-value` 开启后,Enter 可把不匹配候选的原文作为 custom value 显式提交。\n *\n * 触发器跟随 select 的 wrapper div 模式:`slot[name=\"trigger\"]` 可替换默认触发器\n * (shadow 内的 `web-ui-input`);多行触发器(如 `web-ui-textarea`)保留 Enter 换行语义,\n * 关闭面板用 Escape 或 blur。\n * tab 位只属于触发器自身:默认触发器是 shadow 内 input,自定义触发器由消费者提供\n * 可聚焦元素(README 契约);包装 div 恒为 tabindex=\"-1\",不占顺序焦点,避免双 tab 位。\n */\n@customElement('web-ui-autocomplete')\nexport class WebUiAutocomplete extends FormAssociated(LitElement) {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: Boolean, reflect: true }) borderless = false\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) readonly = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' })\n noScrollLock = false\n @property({ type: Boolean, reflect: true, attribute: 'allow-custom-value' })\n allowCustomValue = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n @property({ type: String, reflect: true }) name = ''\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n @property({ type: String, attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined\n\n private _filter: FilterMode = 'contains'\n\n @property({ type: String, reflect: true })\n get filter(): FilterMode {\n return this._filter\n }\n set filter(v: string) {\n const old = this._filter\n this._filter = normalizeLiteral(v, FILTER_MODES, 'contains')\n this.requestUpdate('filter', old)\n }\n\n // value 不反射 attribute,attribute 只参与首次声明式初始化。\n @state() private _value = ''\n\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.requestUpdate('value', old)\n }\n\n // selected-value:文本精确匹配 option label 时派生出的 option value(只读反射)。\n @state() private _selectedValue = ''\n\n get selectedValue(): string {\n return this._selectedValue\n }\n\n private _setSelectedValue(value: string) {\n const old = this._selectedValue\n if (old === value && this.getAttribute('selected-value') === value) return\n\n this._selectedValue = value\n this.setAttribute('selected-value', value)\n if (old !== value) this.requestUpdate('selectedValue', 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) this._value = attrValue\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 _focused = false\n @state() private _hasTriggerSlot = false\n\n private static _nextInstanceId = 0\n private readonly _idPrefix = `web-ui-autocomplete-${++WebUiAutocomplete._nextInstanceId}`\n private readonly _a11yOptionIds = new WeakMap<WebUiOption, string>()\n private _nextA11yOptionId = 0\n private _options: WebUiOption[] = []\n private _portal?: OverlayPortal\n private _portalContent?: HTMLElement\n private readonly _scrollLock = defineScrollLockLease().make()\n\n // option 注册表 / portal 同步 / 微任务调度收敛到 shared 模块(select 同款)\n private readonly _optionPortal = defineOptionPortal().make({\n element: this,\n idPrefix: `${this._idPrefix}-option`,\n getPortal: () => this._portal,\n getPortalContent: () => this._portalContent,\n isOpen: () => this.portal && this._isOpen,\n // 默认 slot 内容随面板迁移;trigger 与已移除的 empty slot 留在宿主,不进面板。\n getMigratableNodes: () =>\n Array.from(this.childNodes).filter(node => !isTriggerSlotNode(node) && !isEmptySlotNode(node)),\n hasUpdated: () => this.hasUpdated,\n requestUpdate: () => this.requestUpdate(),\n bindOption: option => this._bindOption(option),\n unbindOption: option => this._unbindOption(option)\n })\n /*\n * 触发器委托层:默认触发器(shadow 内 web-ui-input)与 slot[name=\"trigger\"] 自定义\n * 触发器对组件暴露同一形状,监听统一挂在 trigger 包装 div 上,两条路径不特判。\n */\n private readonly _trigger = defineComboboxTrigger().make({\n getWrapper: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-trigger') ?? null,\n getCustomTrigger: () => {\n const assigned = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')?.assignedElements()[0]\n return assigned instanceof HTMLElement ? assigned : null\n },\n getFallbackTrigger: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-input') ?? null,\n onInput: value => this._onTriggerInput(value),\n onClick: () => this._onTriggerClick(),\n onFocusIn: event => this._onTriggerFocusIn(event),\n onFocusOut: event => this._onTriggerFocusOut(event)\n })\n /*\n * 开启态浮层承载「我开着吗」(issue #120 Block 1):宿主级 keydown 在 portal 模式下\n * 收不到面板内的 Escape,改由唯一仲裁者在 document 捕获阶段判定最内层。\n * 宿主接口除 requestClose 外只再提供一个 isConnected(仅供惰性回收读取):开启状态是\n * 声明而非询问。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._close(),\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n // 锚点取当前生效的触发器 host:默认触发器或自定义 trigger slot 内容\n getAnchor: () =>\n this._trigger.getTrigger() ?? this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-overlay') ?? null,\n getPositioning: () => ({\n placement: 'bottom-start',\n offset: 4,\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 /*\n * 公共焦点委托:聚焦/失焦当前生效的触发器(默认 web-ui-input 或自定义触发器)。\n * 组件自带 focus 重定向时落到内部原生控件;自定义触发器没有该能力时,\n * 原生 focus() 聚焦 host 自身。无触发器(尚未首渲或已断开)时静默返回。\n */\n override focus(options?: FocusOptions): void {\n this._trigger.focusTrigger(options)\n }\n\n override blur(): void {\n this._trigger.blurTrigger()\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this._isOpen) return\n\n // 在监听器内部判定:composedPath() 在派发结束后会被清空。\n const isInside = e.composedPath().includes(this) || !!this._panel.getHandle()?.containsEvent(e)\n if (!isInside) this._close()\n }\n\n private _onFocusOut = () => {\n handleComboboxFocusOut(\n this,\n () => this._panel.getHandle(),\n () => this._isOpen,\n () => this._close()\n )\n }\n\n private _handlePanelPointerDown = (e: PointerEvent) => {\n // 非 option 区域不可聚焦;阻止 pointerdown 的默认聚焦行为,保持 combobox 焦点,\n // 使点击 empty state、滚动区和面板 padding 不会被 focusout 误判为外部交互。\n e.preventDefault()\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._optionPortal.bindHost()\n // 宿主可能被上层浮层 portal 迁移(断开重连):shadow 内的包装 div 仍在,重新绑定委托监听\n this._trigger.bind()\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n document.addEventListener('click', this._onClickOutside)\n }\n\n private _onTriggerSlotChange = () => {\n this._syncTriggerSlot()\n }\n\n /*\n * 自定义触发器判定必须同步:slotchange 在首次渲染之后才派发,只依赖它会让默认\n * web-ui-input 先渲染一帧再被替换,自定义触发器出现时会闪一下默认输入框。\n * 判据与 portal 迁移排除(isTriggerSlotNode)同源:宿主直接子节点带 slot=\"trigger\"。\n */\n private _syncTriggerSlot() {\n const hasTriggerSlot = Array.from(this.children).some(isTriggerSlotNode)\n if (this._hasTriggerSlot === hasTriggerSlot) return\n this._hasTriggerSlot = hasTriggerSlot\n // 触发器在默认与自定义之间切换:anchor 与 portal 会话按新触发器重建。\n // 首次渲染前尚无 portal 会话,无需重建。\n if (this.hasUpdated) this._reconfigureOverlay()\n }\n\n override attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n super.attributeChangedCallback(name, oldValue, newValue)\n if (name === 'selected-value' && this.isConnected && newValue !== this._selectedValue) {\n queueMicrotask(() => {\n if (this.isConnected) this._syncSelectedValue()\n })\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._optionPortal.dispose()\n this._trigger.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._close()\n this._portal = undefined\n this._portalContent = undefined\n // 撤销登记由 _panel.dispose() 完成(句柄归它持有),不再需要单独 dispose 仲裁者。\n this._panel.dispose()\n this._scrollLock.release()\n }\n\n override firstUpdated() {\n this._trigger.bind()\n requestAnimationFrame(() => {\n if (this.isConnected) this._optionPortal.scheduleRefresh()\n })\n }\n\n override willUpdate() {\n this._syncTriggerSlot()\n this._refreshOptions()\n this._optionPortal.ensureOptionIds(this._options)\n this._syncSelectedValue()\n this._applyFilter()\n this._syncOptionA11y()\n this._syncActiveOption()\n }\n\n override updated(changed: PropertyValues) {\n // 文本回写经委托层落到当前触发器(默认 web-ui-input 或自定义触发器)\n this._trigger.setValue(this._value)\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n if (changed.has('noScrollLock')) this._syncScrollLock()\n this.toggleAttribute('focused', this._focused)\n this._syncOpenAttribute()\n this._syncOverlayInert()\n this._syncValidity()\n this._syncOpenWithMatches()\n }\n\n override formDisabledCallback(disabled: boolean) {\n this._formAssociation.setDisabled(disabled)\n if (disabled && this._isOpen) this._close()\n }\n\n private _syncValidity() {\n const internals = this._formAssociation.getInternals()\n if (!internals || typeof internals.setValidity !== 'function') return\n // readonly 与 disabled 一致:值不可由用户修改,视为通过校验(原生 barred-from-validation 语义)\n if (this._isDisabled || this.readonly || !this.required || this._value) internals.setValidity({})\n else internals.setValidity({ valueMissing: true }, '请输入内容')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n /*\n * 禁用/只读态不响应 Escape。仲裁者仍在(吞掉按键并压掉原生 cancel),只是不走关闭\n * 入口 —— 与旧的「跳过候选」语义不同:旧语义放任事件落到下层浮层,把外层一起关掉。\n * 每次渲染后同步即可覆盖 disabled / readonly 属性与表单禁用三条来源。\n */\n private _syncOverlayInert() {\n this._panel.getHandle()?.setInert(this._isDisabled || this.readonly)\n }\n\n private _syncSelectedValue() {\n const query = this._value.trim().toLowerCase()\n const next = query\n ? (this._options.find(o => !o.disabled && o.label.trim().toLowerCase() === query)?.value ?? '')\n : ''\n this._setSelectedValue(next)\n }\n\n private _syncOptionA11y() {\n this._options.forEach(o => {\n o.setAttribute('role', 'option')\n o.setAttribute('aria-selected', o.value === this._selectedValue ? 'true' : 'false')\n o.setAttribute('aria-hidden', 'true')\n })\n }\n\n private _getA11yOptionId(option: WebUiOption): string {\n let id = this._a11yOptionIds.get(option)\n if (!id) {\n id = `${this._idPrefix}-a11y-option-${++this._nextA11yOptionId}`\n this._a11yOptionIds.set(option, id)\n }\n return id\n }\n\n // 按当前文本与 filter 模式过滤候选,非匹配项以 data-filtered 隐藏并跳过导航\n private _applyFilter() {\n const query = this._value.trim().toLowerCase()\n const mode = this._filter\n this._options.forEach(o => {\n const label = o.label.trim().toLowerCase()\n const match = mode === 'none' || !query || (mode === 'prefix' ? label.startsWith(query) : label.includes(query))\n o.toggleAttribute('data-filtered', !match)\n })\n // 活动项被过滤或禁用时清除键盘激活,避免激活不可见项\n const active = this._options[this._activeIndex]\n if (this._activeIndex >= 0 && (!active || active.hasAttribute('data-filtered') || active.disabled)) {\n this._activeIndex = -1\n this._syncActiveOption()\n }\n }\n\n private _hasMatchingOptions() {\n return this._options.some(option => !option.hasAttribute('data-filtered'))\n }\n\n private _syncOpenWithMatches() {\n if (this._isOpen && !this._hasMatchingOptions()) this._close()\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 const next = this._optionPortal.refresh(this._options, activeOption)\n this._options = next.options\n this._activeIndex = next.activeIndex\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) return\n this._selectOption(option)\n }\n\n private _onOptionUpdate = () => {\n this._optionPortal.scheduleRefresh()\n }\n\n private _handleOptionPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (!this._isOpen || !(e.currentTarget instanceof HTMLElement)) return\n\n // 指针接管后只保留 :hover,避免键盘激活项与悬停项同时高亮。\n this._activeIndex = -1\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持输入框焦点,避免 focusout 在 click 前关闭浮层。\n e.preventDefault()\n }\n\n // slotchange 不冒泡,只能由模板内 slot 自行监听;稳定引用避免 Lit 重挂载\n private _onSlotChange = () => {\n this._optionPortal.scheduleRefresh()\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this._isDisabled || this.readonly) return\n this._applyFilter()\n this._syncOpenWithMatches()\n\n // Escape 不在本组件处理:由共享仲裁者在 document 捕获阶段归属(issue #120 Block 1)。\n switch (e.key) {\n /*\n * 多行触发器(textarea)的方向键归光标移动:面板打开时不接管、不\n * preventDefault,与 Enter 的 multiline 例外同判据。面板关闭时方向键\n * 仍是打开入口(键盘可达性不依赖指针)。\n */\n case 'ArrowDown':\n case 'ArrowUp': {\n if (this._isOpen && this._trigger.isMultilineEdit(e)) break\n e.preventDefault()\n if (!this._isOpen) this._open(true)\n else this._navigateActive(e.key === 'ArrowDown' ? 1 : -1)\n break\n }\n case 'Enter': {\n /*\n * 面板打开时接管 Enter:选择候选或提交 custom value。\n * 零匹配时面板会被过滤状态收敛关闭,但 allow-custom-value 仍需在关闭态提交。\n * 多行触发器(textarea)保留换行语义,不接管为选中高亮项。\n */\n const canSubmitCustomValue = this._canSubmitCustomValue()\n if (\n !this._trigger.isMultilineEdit(e) &&\n (this._isOpen || (!this._hasMatchingOptions() && canSubmitCustomValue))\n ) {\n e.preventDefault()\n if (this._isOpen) {\n const option = this._options[this._activeIndex]\n if (option && !option.disabled && !option.hasAttribute('data-filtered')) {\n this._selectOption(option)\n return\n }\n\n const exactOption = this._findExactOption(this._value)\n if (exactOption) {\n this._selectOption(exactOption)\n return\n }\n }\n\n if (canSubmitCustomValue) this._selectCustomValue()\n }\n break\n }\n }\n }\n\n private _navigateActive(delta: number) {\n const enabled = this._options.filter(o => !o.disabled && !o.hasAttribute('data-filtered'))\n if (!enabled.length) return\n\n const currentIdx = this._activeIndex >= 0 ? enabled.indexOf(this._options[this._activeIndex]) : delta > 0 ? -1 : 0\n this._activeIndex = this._options.indexOf(enabled[nextWrappingIndex(enabled.length, currentIdx, delta)])\n this._syncActiveOption()\n }\n\n private _setInitialActiveOption() {\n const firstEnabled = this._options.findIndex(o => !o.disabled && !o.hasAttribute('data-filtered'))\n this._activeIndex = firstEnabled\n this._syncActiveOption()\n }\n\n private _syncActiveOption() {\n this._options.forEach((option, index) => option.toggleAttribute('active', index === this._activeIndex))\n }\n\n private _selectOption(option: WebUiOption) {\n if (this.readonly) return\n // value 即输入文本:选择后回填为 option label,selected-value 取 option value\n this.value = option.label\n this._setSelectedValue(option.value)\n this._close()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _findExactOption(value: string): WebUiOption | undefined {\n const query = value.trim().toLowerCase()\n if (!query) return undefined\n\n return this._options.find(option => !option.disabled && option.label.trim().toLowerCase() === query)\n }\n\n private _hasExactOption(value: string): boolean {\n const query = value.trim().toLowerCase()\n return this._options.some(option => option.label.trim().toLowerCase() === query)\n }\n\n private _canSubmitCustomValue() {\n return this.allowCustomValue && !!this._value && !this._hasExactOption(this._value)\n }\n\n private _selectCustomValue() {\n // Custom value 的 identity 由消费端管理;组件不隐式创建 option,selected-value 保持派生空值。\n this._close()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _onTriggerInput = (value: string) => {\n if (this._isDisabled || this.readonly) return\n if (value === this._value) return\n this.value = value\n this._activeIndex = -1\n this._syncActiveOption()\n this._open()\n }\n\n private _onTriggerClick = () => {\n if (this._isDisabled || this.readonly) return\n this._open()\n }\n\n /*\n * focus/blur 不冒泡,委托层监听等价且冒泡的 focusin/focusout。\n * 自定义触发器位于 light DOM,其焦点变化不会跨 shadow 边界到达宿主,这里补发\n * 公共 focus/blur 兑现 README 事件契约;默认触发器在 shadow 内,原生事件已能\n * 到达宿主,重复派发会让消费端收到两次。\n */\n private _onTriggerFocusIn = (event: FocusEvent) => {\n if (this._isDisabled) return\n this._focused = true\n // composed 与原生 focus 一致(宿主内 retarget):跨 shadow 边界的消费者能收到,\n // 但不 bubbles —— focus/blur 的公共契约本来就不冒泡。\n // relatedTarget 透传:消费端靠它判断焦点来回,补发事件不该丢这个信息\n if (this._isSlottedFocus(event))\n this.dispatchEvent(new FocusEvent('focus', { composed: true, relatedTarget: event.relatedTarget }))\n }\n\n private _onTriggerFocusOut = (event: FocusEvent) => {\n this._focused = false\n if (this._isSlottedFocus(event))\n this.dispatchEvent(new FocusEvent('blur', { composed: true, relatedTarget: event.relatedTarget }))\n }\n\n private _isSlottedFocus(event: FocusEvent): boolean {\n const target = event.target\n return target instanceof Node && !!this.shadowRoot && !this.shadowRoot.contains(target)\n }\n\n // 开合生命周期不变量收敛在 shared combobox-shell;autocomplete 注入\n // readonly guard 与 close 前的 portal 内容收敛钩子\n private readonly _openController = createComboboxOpenController({\n canOpen: () => !this._isDisabled && !this.readonly,\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 if (isKeyboardNavigation) this._setInitialActiveOption()\n else this._syncActiveOption()\n },\n onBeforeClose: () => {\n // Portal 内容可能在当前微任务尚未完成同步;先把 light DOM 中新增或重排的节点\n // 收回当前 content,再关闭并 restore,避免 restoreContent() 按旧 tracking 顺序把\n // 新 option 插到旧 option 前面。\n this._optionPortal.syncPortalContent()\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._applyFilter()\n if (!this._hasMatchingOptions()) {\n if (this._isOpen) this._close()\n return\n }\n this._openController.open(isKeyboardNavigation)\n }\n\n private _close() {\n this._openController.close()\n }\n\n private _dispatchOpenChange() {\n dispatchOpenChangeEvent(this, this._isOpen)\n }\n\n private _openOverlay(isKeyboardNavigation = false) {\n this._panel.open(isKeyboardNavigation)\n // 新会话的句柄刚建立,惰性状态需按当前 disabled/readonly 重新同步。\n this._syncOverlayInert()\n }\n\n private async _closeOverlay() {\n const closed = await this._panel.close(() => this._isOpen)\n if (closed) {\n this._portal = undefined\n this._portalContent = undefined\n }\n }\n\n private _reconfigureOverlay() {\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 _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'wui-glass autocomplete-overlay portal wui-floating-panel',\n onContentChange: () => {\n this._optionPortal.scheduleRefresh()\n }\n })\n this._portal = portal\n applyOverlayVariables(portal.panel, this, [\n '--wui-overlay-min-width',\n '--wui-autocomplete-max-width',\n '--wui-autocomplete-max-height'\n ])\n portal.panel.setAttribute('aria-hidden', 'true')\n portal.panel.addEventListener('pointerdown', this._handlePanelPointerDown)\n const scroll = document.createElement('div')\n scroll.className = 'autocomplete-scroll'\n const content = document.createElement('div')\n content.className = 'autocomplete-content'\n this._portalContent = content\n scroll.append(content)\n portal.panel.append(scroll)\n for (const node of Array.from(this.childNodes)) {\n // 框架注释锚点(v-if/v-for 占位)必须留在宿主:锚点进面板后 Vue 下次翻转\n // 会以面板内节点为插入基准;portal 的 marker 注释同理不参与迁移。\n if (node instanceof Comment) continue\n // 自定义 trigger 与 select(:461)同判据:留在宿主,不随 options 迁入浮层\n if (isTriggerSlotNode(node)) continue\n // 已移除的 empty slot 不能作为普通内容出现在新 portal 面板中\n if (isEmptySlotNode(node)) continue\n portal.appendContent([node], content)\n }\n return portal\n }\n\n private _getLabelledbyText(): string {\n if (!this.ariaLabelledby) return ''\n\n const root = this.getRootNode()\n if (!(root instanceof Document || root instanceof ShadowRoot)) return ''\n\n return this.ariaLabelledby\n .trim()\n .split(/\\s+/)\n .map(id => {\n const escapedId = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(id) : id\n return root.querySelector(`#${escapedId}`)?.textContent?.trim() ?? ''\n })\n .filter(Boolean)\n .join(' ')\n }\n\n override render() {\n const listboxId = `${this._idPrefix}-listbox`\n const labelId = `${this._idPrefix}-label`\n const labelledbyText = this._getLabelledbyText()\n const visibleOptions = this._options.filter(option => !option.hasAttribute('data-filtered'))\n const activeOption = this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex] : undefined\n const activeDescendant = activeOption ? this._getA11yOptionId(activeOption) : nothing\n\n return html`\n <div class=\"wui-autocomplete-inner\">\n ${labelledbyText ? html`<span class=\"autocomplete-a11y-only\" id=${labelId}>${labelledbyText}</span>` : nothing}\n <div\n class=\"autocomplete-trigger\"\n ?data-custom-trigger=${this._hasTriggerSlot}\n role=\"combobox\"\n aria-expanded=${this._isOpen}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-controls=${listboxId}\n aria-disabled=${String(this._isDisabled)}\n aria-readonly=${this.readonly ? 'true' : nothing}\n aria-label=${ifDefined(this.ariaLabel)}\n aria-labelledby=${labelledbyText ? labelId : nothing}\n aria-activedescendant=${activeDescendant}\n tabindex=\"-1\"\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n ${\n !this._hasTriggerSlot\n ? html`<web-ui-input\n class=\"autocomplete-input\"\n .value=${this._value}\n placeholder=${this.placeholder}\n name=${this.name}\n ?borderless=${this.borderless}\n ?disabled=${this._isDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-label=${ifDefined(this.ariaLabel || labelledbyText || undefined)}\n ></web-ui-input>`\n : nothing\n }\n </div>\n <div\n class=\"autocomplete-a11y-listbox\"\n id=${listboxId}\n role=\"listbox\"\n ?hidden=${!this._isOpen}\n aria-hidden=${String(!this._isOpen)}\n >\n ${visibleOptions.map(\n option =>\n html`<div\n id=${this._getA11yOptionId(option)}\n role=\"option\"\n aria-selected=${option.value === this._selectedValue ? 'true' : 'false'}\n aria-hidden=${String(!this._isOpen)}\n aria-disabled=${String(option.disabled)}\n >\n ${option.label}\n </div>`\n )}\n </div>\n <div\n class=\"autocomplete-overlay wui-floating-panel wui-glass\"\n hidden\n aria-hidden=\"true\"\n @pointerdown=${this._handlePanelPointerDown}\n >\n <div class=\"autocomplete-scroll\">\n <div class=\"autocomplete-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 focus: FocusEvent\n blur: FocusEvent\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-autocomplete': WebUiAutocomplete\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/autocomplete/index.ts"],"sourcesContent":["import '@/components/input'\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 glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport type { WebUiOption } from '@/components/option'\nimport internalScrollbars from '@/scrollbars/internal.css?inline'\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 defineComboboxTrigger,\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\nconst FILTER_MODES = ['none', 'prefix', 'contains'] as const\ntype FilterMode = (typeof FILTER_MODES)[number]\n\n// 自定义 trigger 与 select 同判据:必须留在宿主,不随 options 迁入 portal 面板\nfunction isTriggerSlotNode(node: Node): node is Element {\n return node instanceof Element && node.slot === 'trigger'\n}\n\n// 已移除的 empty slot 仍可能留在既有消费者 light DOM;不得把它作为普通内容迁入 portal。\nfunction isEmptySlotNode(node: Node): node is Element {\n return node instanceof Element && node.slot === 'empty'\n}\n\n/**\n * `web-ui-autocomplete`:可输入并过滤候选的单值选择器。\n *\n * 与 `web-ui-select` 共用 `<web-ui-option>` 子项注册协议与浮层能力,但触发区是\n * 可编辑输入框:`value` 即当前输入文本(表单值),键入时按 `filter` 模式过滤候选,\n * 选择 option 时文本回填为该项 label,`selected-value` 暴露该项的 value。\n * `allow-custom-value` 开启后,Enter 可把不匹配候选的原文作为 custom value 显式提交。\n *\n * 触发器跟随 select 的 wrapper div 模式:`slot[name=\"trigger\"]` 可替换默认触发器\n * (shadow 内的 `web-ui-input`);多行触发器(如 `web-ui-textarea`)保留 Enter 换行语义,\n * 关闭面板用 Escape 或 blur。\n * tab 位只属于触发器自身:默认触发器是 shadow 内 input,自定义触发器由消费者提供\n * 可聚焦元素(README 契约);包装 div 恒为 tabindex=\"-1\",不占顺序焦点,避免双 tab 位。\n */\n@customElement('web-ui-autocomplete')\nexport class WebUiAutocomplete extends FormAssociated(LitElement) {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(internalScrollbars), unsafeCSS(style)]\n\n @property({ type: String, reflect: true }) placeholder = ''\n @property({ type: Boolean, reflect: true }) borderless = false\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true }) readonly = false\n @property({ type: Boolean, reflect: true }) required = false\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' })\n noScrollLock = false\n @property({ type: Boolean, reflect: true, attribute: 'allow-custom-value' })\n allowCustomValue = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n @property({ type: String, reflect: true }) name = ''\n @property({ type: String, attribute: 'aria-label' }) override ariaLabel: string | null = null\n @property({ type: String, attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined\n\n private _filter: FilterMode = 'contains'\n\n @property({ type: String, reflect: true })\n get filter(): FilterMode {\n return this._filter\n }\n set filter(v: string) {\n const old = this._filter\n this._filter = normalizeLiteral(v, FILTER_MODES, 'contains')\n this.requestUpdate('filter', old)\n }\n\n // value 不反射 attribute,attribute 只参与首次声明式初始化。\n @state() private _value = ''\n\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.requestUpdate('value', old)\n }\n\n // selected-value:文本精确匹配 option label 时派生出的 option value(只读反射)。\n @state() private _selectedValue = ''\n\n get selectedValue(): string {\n return this._selectedValue\n }\n\n private _setSelectedValue(value: string) {\n const old = this._selectedValue\n if (old === value && this.getAttribute('selected-value') === value) return\n\n this._selectedValue = value\n this.setAttribute('selected-value', value)\n if (old !== value) this.requestUpdate('selectedValue', 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) this._value = attrValue\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 _focused = false\n @state() private _hasTriggerSlot = false\n\n private static _nextInstanceId = 0\n private readonly _idPrefix = `web-ui-autocomplete-${++WebUiAutocomplete._nextInstanceId}`\n private readonly _a11yOptionIds = new WeakMap<WebUiOption, string>()\n private _nextA11yOptionId = 0\n private _options: WebUiOption[] = []\n private _portal?: OverlayPortal\n private _portalContent?: HTMLElement\n private readonly _scrollLock = defineScrollLockLease().make()\n\n // option 注册表 / portal 同步 / 微任务调度收敛到 shared 模块(select 同款)\n private readonly _optionPortal = defineOptionPortal().make({\n element: this,\n idPrefix: `${this._idPrefix}-option`,\n getPortal: () => this._portal,\n getPortalContent: () => this._portalContent,\n isOpen: () => this.portal && this._isOpen,\n // 默认 slot 内容随面板迁移;trigger 与已移除的 empty slot 留在宿主,不进面板。\n getMigratableNodes: () =>\n Array.from(this.childNodes).filter(node => !isTriggerSlotNode(node) && !isEmptySlotNode(node)),\n hasUpdated: () => this.hasUpdated,\n requestUpdate: () => this.requestUpdate(),\n bindOption: option => this._bindOption(option),\n unbindOption: option => this._unbindOption(option)\n })\n /*\n * 触发器委托层:默认触发器(shadow 内 web-ui-input)与 slot[name=\"trigger\"] 自定义\n * 触发器对组件暴露同一形状,监听统一挂在 trigger 包装 div 上,两条路径不特判。\n */\n private readonly _trigger = defineComboboxTrigger().make({\n getWrapper: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-trigger') ?? null,\n getCustomTrigger: () => {\n const assigned = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')?.assignedElements()[0]\n return assigned instanceof HTMLElement ? assigned : null\n },\n getFallbackTrigger: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-input') ?? null,\n onInput: value => this._onTriggerInput(value),\n onClick: () => this._onTriggerClick(),\n onFocusIn: event => this._onTriggerFocusIn(event),\n onFocusOut: event => this._onTriggerFocusOut(event)\n })\n /*\n * 开启态浮层承载「我开着吗」(issue #120 Block 1):宿主级 keydown 在 portal 模式下\n * 收不到面板内的 Escape,改由唯一仲裁者在 document 捕获阶段判定最内层。\n * 宿主接口除 requestClose 外只再提供一个 isConnected(仅供惰性回收读取):开启状态是\n * 声明而非询问。\n */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._close(),\n isConnected: () => this.isConnected\n })\n private readonly _panel = defineAnchoredPanel().make({\n // 锚点取当前生效的触发器 host:默认触发器或自定义 trigger slot 内容\n getAnchor: () =>\n this._trigger.getTrigger() ?? this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.autocomplete-overlay') ?? null,\n getPositioning: () => ({\n placement: 'bottom-start',\n offset: 4,\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 /*\n * 公共焦点委托:聚焦/失焦当前生效的触发器(默认 web-ui-input 或自定义触发器)。\n * 组件自带 focus 重定向时落到内部原生控件;自定义触发器没有该能力时,\n * 原生 focus() 聚焦 host 自身。无触发器(尚未首渲或已断开)时静默返回。\n */\n override focus(options?: FocusOptions): void {\n this._trigger.focusTrigger(options)\n }\n\n override blur(): void {\n this._trigger.blurTrigger()\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this._isOpen) return\n\n // 在监听器内部判定:composedPath() 在派发结束后会被清空。\n const isInside = e.composedPath().includes(this) || !!this._panel.getHandle()?.containsEvent(e)\n if (!isInside) this._close()\n }\n\n private _onFocusOut = () => {\n handleComboboxFocusOut(\n this,\n () => this._panel.getHandle(),\n () => this._isOpen,\n () => this._close()\n )\n }\n\n private _handlePanelPointerDown = (e: PointerEvent) => {\n // 非 option 区域不可聚焦;阻止 pointerdown 的默认聚焦行为,保持 combobox 焦点,\n // 使点击 empty state、滚动区和面板 padding 不会被 focusout 误判为外部交互。\n e.preventDefault()\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._optionPortal.bindHost()\n // 宿主可能被上层浮层 portal 迁移(断开重连):shadow 内的包装 div 仍在,重新绑定委托监听\n this._trigger.bind()\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n document.addEventListener('click', this._onClickOutside)\n }\n\n private _onTriggerSlotChange = () => {\n this._syncTriggerSlot()\n }\n\n /*\n * 自定义触发器判定必须同步:slotchange 在首次渲染之后才派发,只依赖它会让默认\n * web-ui-input 先渲染一帧再被替换,自定义触发器出现时会闪一下默认输入框。\n * 判据与 portal 迁移排除(isTriggerSlotNode)同源:宿主直接子节点带 slot=\"trigger\"。\n */\n private _syncTriggerSlot() {\n const hasTriggerSlot = Array.from(this.children).some(isTriggerSlotNode)\n if (this._hasTriggerSlot === hasTriggerSlot) return\n this._hasTriggerSlot = hasTriggerSlot\n // 触发器在默认与自定义之间切换:anchor 与 portal 会话按新触发器重建。\n // 首次渲染前尚无 portal 会话,无需重建。\n if (this.hasUpdated) this._reconfigureOverlay()\n }\n\n override attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n super.attributeChangedCallback(name, oldValue, newValue)\n if (name === 'selected-value' && this.isConnected && newValue !== this._selectedValue) {\n queueMicrotask(() => {\n if (this.isConnected) this._syncSelectedValue()\n })\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._optionPortal.dispose()\n this._trigger.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._close()\n this._portal = undefined\n this._portalContent = undefined\n // 撤销登记由 _panel.dispose() 完成(句柄归它持有),不再需要单独 dispose 仲裁者。\n this._panel.dispose()\n this._scrollLock.release()\n }\n\n override firstUpdated() {\n this._trigger.bind()\n requestAnimationFrame(() => {\n if (this.isConnected) this._optionPortal.scheduleRefresh()\n })\n }\n\n override willUpdate() {\n this._syncTriggerSlot()\n this._refreshOptions()\n this._optionPortal.ensureOptionIds(this._options)\n this._syncSelectedValue()\n this._applyFilter()\n this._syncOptionA11y()\n this._syncActiveOption()\n }\n\n override updated(changed: PropertyValues) {\n // 文本回写经委托层落到当前触发器(默认 web-ui-input 或自定义触发器)\n this._trigger.setValue(this._value)\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n if (changed.has('noScrollLock')) this._syncScrollLock()\n this.toggleAttribute('focused', this._focused)\n this._syncOpenAttribute()\n this._syncOverlayInert()\n this._syncValidity()\n this._syncOpenWithMatches()\n }\n\n override formDisabledCallback(disabled: boolean) {\n this._formAssociation.setDisabled(disabled)\n if (disabled && this._isOpen) this._close()\n }\n\n private _syncValidity() {\n const internals = this._formAssociation.getInternals()\n if (!internals || typeof internals.setValidity !== 'function') return\n // readonly 与 disabled 一致:值不可由用户修改,视为通过校验(原生 barred-from-validation 语义)\n if (this._isDisabled || this.readonly || !this.required || this._value) internals.setValidity({})\n else internals.setValidity({ valueMissing: true }, '请输入内容')\n }\n\n private _syncOpenAttribute() {\n this.toggleAttribute('open', this._isOpen)\n }\n\n /*\n * 禁用/只读态不响应 Escape。仲裁者仍在(吞掉按键并压掉原生 cancel),只是不走关闭\n * 入口 —— 与旧的「跳过候选」语义不同:旧语义放任事件落到下层浮层,把外层一起关掉。\n * 每次渲染后同步即可覆盖 disabled / readonly 属性与表单禁用三条来源。\n */\n private _syncOverlayInert() {\n this._panel.getHandle()?.setInert(this._isDisabled || this.readonly)\n }\n\n private _syncSelectedValue() {\n const query = this._value.trim().toLowerCase()\n const next = query\n ? (this._options.find(o => !o.disabled && o.label.trim().toLowerCase() === query)?.value ?? '')\n : ''\n this._setSelectedValue(next)\n }\n\n private _syncOptionA11y() {\n this._options.forEach(o => {\n o.setAttribute('role', 'option')\n o.setAttribute('aria-selected', o.value === this._selectedValue ? 'true' : 'false')\n o.setAttribute('aria-hidden', 'true')\n })\n }\n\n private _getA11yOptionId(option: WebUiOption): string {\n let id = this._a11yOptionIds.get(option)\n if (!id) {\n id = `${this._idPrefix}-a11y-option-${++this._nextA11yOptionId}`\n this._a11yOptionIds.set(option, id)\n }\n return id\n }\n\n // 按当前文本与 filter 模式过滤候选,非匹配项以 data-filtered 隐藏并跳过导航\n private _applyFilter() {\n const query = this._value.trim().toLowerCase()\n const mode = this._filter\n this._options.forEach(o => {\n const label = o.label.trim().toLowerCase()\n const match = mode === 'none' || !query || (mode === 'prefix' ? label.startsWith(query) : label.includes(query))\n o.toggleAttribute('data-filtered', !match)\n })\n // 活动项被过滤或禁用时清除键盘激活,避免激活不可见项\n const active = this._options[this._activeIndex]\n if (this._activeIndex >= 0 && (!active || active.hasAttribute('data-filtered') || active.disabled)) {\n this._activeIndex = -1\n this._syncActiveOption()\n }\n }\n\n private _hasMatchingOptions() {\n return this._options.some(option => !option.hasAttribute('data-filtered'))\n }\n\n private _syncOpenWithMatches() {\n if (this._isOpen && !this._hasMatchingOptions()) this._close()\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 const next = this._optionPortal.refresh(this._options, activeOption)\n this._options = next.options\n this._activeIndex = next.activeIndex\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) return\n this._selectOption(option)\n }\n\n private _onOptionUpdate = () => {\n this._optionPortal.scheduleRefresh()\n }\n\n private _handleOptionPointerOver = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (!this._isOpen || !(e.currentTarget instanceof HTMLElement)) return\n\n // 指针接管后只保留 :hover,避免键盘激活项与悬停项同时高亮。\n this._activeIndex = -1\n this._syncActiveOption()\n }\n\n private _handleOptionPointerDown = (e: PointerEvent) => {\n // 保持输入框焦点,避免 focusout 在 click 前关闭浮层。\n e.preventDefault()\n }\n\n // slotchange 不冒泡,只能由模板内 slot 自行监听;稳定引用避免 Lit 重挂载\n private _onSlotChange = () => {\n this._optionPortal.scheduleRefresh()\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this._isDisabled || this.readonly) return\n this._applyFilter()\n this._syncOpenWithMatches()\n\n // Escape 不在本组件处理:由共享仲裁者在 document 捕获阶段归属(issue #120 Block 1)。\n switch (e.key) {\n /*\n * 多行触发器(textarea)的方向键归光标移动:面板打开时不接管、不\n * preventDefault,与 Enter 的 multiline 例外同判据。面板关闭时方向键\n * 仍是打开入口(键盘可达性不依赖指针)。\n */\n case 'ArrowDown':\n case 'ArrowUp': {\n if (this._isOpen && this._trigger.isMultilineEdit(e)) break\n e.preventDefault()\n if (!this._isOpen) this._open(true)\n else this._navigateActive(e.key === 'ArrowDown' ? 1 : -1)\n break\n }\n case 'Enter': {\n /*\n * 面板打开时接管 Enter:选择候选或提交 custom value。\n * 零匹配时面板会被过滤状态收敛关闭,但 allow-custom-value 仍需在关闭态提交。\n * 多行触发器(textarea)保留换行语义,不接管为选中高亮项。\n */\n const canSubmitCustomValue = this._canSubmitCustomValue()\n if (\n !this._trigger.isMultilineEdit(e) &&\n (this._isOpen || (!this._hasMatchingOptions() && canSubmitCustomValue))\n ) {\n e.preventDefault()\n if (this._isOpen) {\n const option = this._options[this._activeIndex]\n if (option && !option.disabled && !option.hasAttribute('data-filtered')) {\n this._selectOption(option)\n return\n }\n\n const exactOption = this._findExactOption(this._value)\n if (exactOption) {\n this._selectOption(exactOption)\n return\n }\n }\n\n if (canSubmitCustomValue) this._selectCustomValue()\n }\n break\n }\n }\n }\n\n private _navigateActive(delta: number) {\n const enabled = this._options.filter(o => !o.disabled && !o.hasAttribute('data-filtered'))\n if (!enabled.length) return\n\n const currentIdx = this._activeIndex >= 0 ? enabled.indexOf(this._options[this._activeIndex]) : delta > 0 ? -1 : 0\n this._activeIndex = this._options.indexOf(enabled[nextWrappingIndex(enabled.length, currentIdx, delta)])\n this._syncActiveOption()\n }\n\n private _setInitialActiveOption() {\n const firstEnabled = this._options.findIndex(o => !o.disabled && !o.hasAttribute('data-filtered'))\n this._activeIndex = firstEnabled\n this._syncActiveOption()\n }\n\n private _syncActiveOption() {\n this._options.forEach((option, index) => option.toggleAttribute('active', index === this._activeIndex))\n }\n\n private _selectOption(option: WebUiOption) {\n if (this.readonly) return\n // value 即输入文本:选择后回填为 option label,selected-value 取 option value\n this.value = option.label\n this._setSelectedValue(option.value)\n this._close()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _findExactOption(value: string): WebUiOption | undefined {\n const query = value.trim().toLowerCase()\n if (!query) return undefined\n\n return this._options.find(option => !option.disabled && option.label.trim().toLowerCase() === query)\n }\n\n private _hasExactOption(value: string): boolean {\n const query = value.trim().toLowerCase()\n return this._options.some(option => option.label.trim().toLowerCase() === query)\n }\n\n private _canSubmitCustomValue() {\n return this.allowCustomValue && !!this._value && !this._hasExactOption(this._value)\n }\n\n private _selectCustomValue() {\n // Custom value 的 identity 由消费端管理;组件不隐式创建 option,selected-value 保持派生空值。\n this._close()\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }))\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }))\n }\n\n private _onTriggerInput = (value: string) => {\n if (this._isDisabled || this.readonly) return\n if (value === this._value) return\n this.value = value\n this._activeIndex = -1\n this._syncActiveOption()\n this._open()\n }\n\n private _onTriggerClick = () => {\n if (this._isDisabled || this.readonly) return\n this._open()\n }\n\n /*\n * focus/blur 不冒泡,委托层监听等价且冒泡的 focusin/focusout。\n * 自定义触发器位于 light DOM,其焦点变化不会跨 shadow 边界到达宿主,这里补发\n * 公共 focus/blur 兑现 README 事件契约;默认触发器在 shadow 内,原生事件已能\n * 到达宿主,重复派发会让消费端收到两次。\n */\n private _onTriggerFocusIn = (event: FocusEvent) => {\n if (this._isDisabled) return\n this._focused = true\n // composed 与原生 focus 一致(宿主内 retarget):跨 shadow 边界的消费者能收到,\n // 但不 bubbles —— focus/blur 的公共契约本来就不冒泡。\n // relatedTarget 透传:消费端靠它判断焦点来回,补发事件不该丢这个信息\n if (this._isSlottedFocus(event))\n this.dispatchEvent(new FocusEvent('focus', { composed: true, relatedTarget: event.relatedTarget }))\n }\n\n private _onTriggerFocusOut = (event: FocusEvent) => {\n this._focused = false\n if (this._isSlottedFocus(event))\n this.dispatchEvent(new FocusEvent('blur', { composed: true, relatedTarget: event.relatedTarget }))\n }\n\n private _isSlottedFocus(event: FocusEvent): boolean {\n const target = event.target\n return target instanceof Node && !!this.shadowRoot && !this.shadowRoot.contains(target)\n }\n\n // 开合生命周期不变量收敛在 shared combobox-shell;autocomplete 注入\n // readonly guard 与 close 前的 portal 内容收敛钩子\n private readonly _openController = createComboboxOpenController({\n canOpen: () => !this._isDisabled && !this.readonly,\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 if (isKeyboardNavigation) this._setInitialActiveOption()\n else this._syncActiveOption()\n },\n onBeforeClose: () => {\n // Portal 内容可能在当前微任务尚未完成同步;先把 light DOM 中新增或重排的节点\n // 收回当前 content,再关闭并 restore,避免 restoreContent() 按旧 tracking 顺序把\n // 新 option 插到旧 option 前面。\n this._optionPortal.syncPortalContent()\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._applyFilter()\n if (!this._hasMatchingOptions()) {\n if (this._isOpen) this._close()\n return\n }\n this._openController.open(isKeyboardNavigation)\n }\n\n private _close() {\n this._openController.close()\n }\n\n private _dispatchOpenChange() {\n dispatchOpenChangeEvent(this, this._isOpen)\n }\n\n private _openOverlay(isKeyboardNavigation = false) {\n this._panel.open(isKeyboardNavigation)\n // 新会话的句柄刚建立,惰性状态需按当前 disabled/readonly 重新同步。\n this._syncOverlayInert()\n }\n\n private async _closeOverlay() {\n const closed = await this._panel.close(() => this._isOpen)\n if (closed) {\n this._portal = undefined\n this._portalContent = undefined\n }\n }\n\n private _reconfigureOverlay() {\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 _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'wui-glass autocomplete-overlay portal wui-floating-panel',\n onContentChange: () => {\n this._optionPortal.scheduleRefresh()\n }\n })\n this._portal = portal\n applyOverlayVariables(portal.panel, this, [\n '--wui-overlay-min-width',\n '--wui-autocomplete-max-width',\n '--wui-autocomplete-max-height'\n ])\n portal.panel.setAttribute('aria-hidden', 'true')\n portal.panel.addEventListener('pointerdown', this._handlePanelPointerDown)\n const scroll = document.createElement('div')\n scroll.className = 'autocomplete-scroll wui-scroll'\n const content = document.createElement('div')\n content.className = 'autocomplete-content'\n this._portalContent = content\n scroll.append(content)\n portal.panel.append(scroll)\n for (const node of Array.from(this.childNodes)) {\n // 框架注释锚点(v-if/v-for 占位)必须留在宿主:锚点进面板后 Vue 下次翻转\n // 会以面板内节点为插入基准;portal 的 marker 注释同理不参与迁移。\n if (node instanceof Comment) continue\n // 自定义 trigger 与 select(:461)同判据:留在宿主,不随 options 迁入浮层\n if (isTriggerSlotNode(node)) continue\n // 已移除的 empty slot 不能作为普通内容出现在新 portal 面板中\n if (isEmptySlotNode(node)) continue\n portal.appendContent([node], content)\n }\n return portal\n }\n\n private _getLabelledbyText(): string {\n if (!this.ariaLabelledby) return ''\n\n const root = this.getRootNode()\n if (!(root instanceof Document || root instanceof ShadowRoot)) return ''\n\n return this.ariaLabelledby\n .trim()\n .split(/\\s+/)\n .map(id => {\n const escapedId = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(id) : id\n return root.querySelector(`#${escapedId}`)?.textContent?.trim() ?? ''\n })\n .filter(Boolean)\n .join(' ')\n }\n\n override render() {\n const listboxId = `${this._idPrefix}-listbox`\n const labelId = `${this._idPrefix}-label`\n const labelledbyText = this._getLabelledbyText()\n const visibleOptions = this._options.filter(option => !option.hasAttribute('data-filtered'))\n const activeOption = this._isOpen && this._activeIndex >= 0 ? this._options[this._activeIndex] : undefined\n const activeDescendant = activeOption ? this._getA11yOptionId(activeOption) : nothing\n\n return html`\n <div class=\"wui-autocomplete-inner\">\n ${labelledbyText ? html`<span class=\"autocomplete-a11y-only\" id=${labelId}>${labelledbyText}</span>` : nothing}\n <div\n class=\"autocomplete-trigger\"\n ?data-custom-trigger=${this._hasTriggerSlot}\n role=\"combobox\"\n aria-expanded=${this._isOpen}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-controls=${listboxId}\n aria-disabled=${String(this._isDisabled)}\n aria-readonly=${this.readonly ? 'true' : nothing}\n aria-label=${ifDefined(this.ariaLabel)}\n aria-labelledby=${labelledbyText ? labelId : nothing}\n aria-activedescendant=${activeDescendant}\n tabindex=\"-1\"\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n ${\n !this._hasTriggerSlot\n ? html`<web-ui-input\n class=\"autocomplete-input\"\n .value=${this._value}\n placeholder=${this.placeholder}\n name=${this.name}\n ?borderless=${this.borderless}\n ?disabled=${this._isDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-label=${ifDefined(this.ariaLabel || labelledbyText || undefined)}\n ></web-ui-input>`\n : nothing\n }\n </div>\n <div\n class=\"autocomplete-a11y-listbox\"\n id=${listboxId}\n role=\"listbox\"\n ?hidden=${!this._isOpen}\n aria-hidden=${String(!this._isOpen)}\n >\n ${visibleOptions.map(\n option =>\n html`<div\n id=${this._getA11yOptionId(option)}\n role=\"option\"\n aria-selected=${option.value === this._selectedValue ? 'true' : 'false'}\n aria-hidden=${String(!this._isOpen)}\n aria-disabled=${String(option.disabled)}\n >\n ${option.label}\n </div>`\n )}\n </div>\n <div\n class=\"autocomplete-overlay wui-floating-panel wui-glass\"\n hidden\n aria-hidden=\"true\"\n @pointerdown=${this._handlePanelPointerDown}\n >\n <div class=\"autocomplete-scroll wui-scroll\">\n <div class=\"autocomplete-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 focus: FocusEvent\n blur: FocusEvent\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-autocomplete': WebUiAutocomplete\n }\n}\n"],"mappings":"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"}