@xihan-ui/web-components 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +4706 -6
  2. package/README.md +10 -3
  3. package/custom-elements.json +36929 -19159
  4. package/dist/backgrounds.d.ts +7 -7
  5. package/dist/backgrounds.d.ts.map +1 -1
  6. package/dist/backgrounds.js +8 -8
  7. package/dist/backgrounds.js.map +1 -1
  8. package/dist/{config-Cz16-P4i.d.ts → config-etfwIorI.d.ts} +17 -8
  9. package/dist/config-etfwIorI.d.ts.map +1 -0
  10. package/dist/define.d.ts +8383 -4143
  11. package/dist/define.d.ts.map +1 -1
  12. package/dist/define.js +11235 -5943
  13. package/dist/define.js.map +1 -1
  14. package/dist/{element-b0p0Q8Py.js → element-BKQR3ce3.js} +4 -4
  15. package/dist/element-BKQR3ce3.js.map +1 -0
  16. package/dist/{element-DRoFjrYO.d.ts → element-DFbmhZLP.d.ts} +3 -3
  17. package/dist/{element-DRoFjrYO.d.ts.map → element-DFbmhZLP.d.ts.map} +1 -1
  18. package/dist/index.d.ts +11 -12
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/{machine-controller-DE6edQbK.js → machine-controller-C1ffftux.js} +35 -29
  22. package/dist/machine-controller-C1ffftux.js.map +1 -0
  23. package/dist/registry-DR6I2_zF.js.map +1 -1
  24. package/dist/services.d.ts +184 -0
  25. package/dist/services.d.ts.map +1 -0
  26. package/dist/services.js +701 -0
  27. package/dist/services.js.map +1 -0
  28. package/dist/toast-BTlM12YF.js +1405 -0
  29. package/dist/toast-BTlM12YF.js.map +1 -0
  30. package/dist/{types-BvWWqMd_.d.ts → types-C1Bybm6P.d.ts} +2 -2
  31. package/dist/{types-BvWWqMd_.d.ts.map → types-C1Bybm6P.d.ts.map} +1 -1
  32. package/package.json +23 -17
  33. package/dist/config-Cz16-P4i.d.ts.map +0 -1
  34. package/dist/element-b0p0Q8Py.js.map +0 -1
  35. package/dist/machine-controller-DE6edQbK.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast-BTlM12YF.js","names":["BOOLEAN_CONVERTER","STRING_CONVERTER","STRING_CONVERTER","NUMBER_CONVERTER","BOOLEAN_CONVERTER","STRING_CONVERTER","NUMBER_CONVERTER","BOOLEAN_CONVERTER"],"sources":["../src/dom/part-contract.ts","../src/dom/stacking-context.ts","../src/element-base.ts","../src/overlay-exit.ts","../src/elements/button.ts","../src/runtime/portal-lease-controller.ts","../src/runtime/anchored-portal-controller.ts","../src/runtime/portal-host.ts","../src/elements/dialog.ts","../src/elements/loading-bar.ts","../src/elements/notification.ts","../src/elements/toast.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 角色节点契约校验:作者写的 Light DOM 与组件解剖对不上时投递诊断。\nimport type { ComponentMeta } from '@xihan-ui/headless'\nimport { DIAGNOSTIC_CODES, getDiagnostics, reportDiagnostic } from '@xihan-ui/core'\n\n/** 只取校验用得上的两项,避免把 `Anatomy<具体 part 联合>` 收窄成 `Anatomy<string>` 时不可赋值。 */\nexport interface PartContract {\n readonly anatomy: { readonly name: string, readonly parts: readonly string[] }\n readonly meta: ComponentMeta\n /**\n * 部件必须使用的标签名。只登记写错后会静默失效的部件:\n * 例如 field 的 label 不是原生 `<label>` 时,`for` 整条失效,点击标签不再聚焦控件。\n */\n readonly tags?: Readonly<Record<string, readonly string[]>>\n /**\n * 委派出去的内嵌部件解剖。\n *\n * 有的宿主把内嵌部件的 DOM 摊在自己的 Light DOM 里接线(date-picker 之于 date-field 与\n * calendar 就是这样),这些角色节点归内嵌部件的 scope 管,本就不该出现在宿主自己的解剖里。\n * 不登记的话它们会被当成解剖外的野节点逐个报警,而它们恰恰是被正常接线的。\n *\n * `name` 须是已注册元素 `xh-<name>` 的解剖名;`parts` 是作者写的角色名。\n * 与宿主解剖重名的角色名归宿主,其余的接线后 data-scope 必须是 `name`。\n */\n readonly delegates?: readonly { readonly name: string, readonly parts: readonly string[] }[]\n /**\n * 双重身份的角色节点:作者按本组件的角色名写,接线后 data-part 却是同一 scope 里的另一个部件。\n *\n * 子菜单形态的 Menu 就是这样:作者写 data-xh-part=\"trigger\"(它是本子菜单的触发器,发现与\n * 接线都按这个名找它),Headless 的 getSubmenuTriggerProps 却铺的是父菜单的 item 部件属性——\n * 父层的方向键、高亮与集合条目皮肤都按 data-part=\"item\" 认它,三端 DOM 一致。\n * 不登记的话示例门禁会把它当成接错了名。键是作者写的角色名,值是允许接出来的 data-part。\n */\n readonly rewired?: Readonly<Record<string, readonly string[]>>\n}\n\n/** 元素类上挂的契约,只取校验用得上的那一项。 */\ninterface ContractHolder { partContract?: PartContract }\n\n/** `name` 是否已注册为 `xh-<name>` 元素、且该元素的解剖名就是它。 */\nexport function isRegisteredScope(name: string): boolean {\n if (typeof customElements === 'undefined')\n return false\n const ctor = customElements.get(`xh-${name}`) as ContractHolder | undefined\n return ctor?.partContract?.anatomy.name === name\n}\n\n/**\n * 委派登记里真正归内嵌部件管的作者名 → 允许的 scope 集合。\n * 与宿主解剖重名的角色名由宿主自己接线(date-picker 的 root / control 等),不进这张表。\n */\nexport function delegatedScopesOf(contract: PartContract): ReadonlyMap<string, ReadonlySet<string>> {\n const own = new Set(contract.anatomy.parts)\n const out = new Map<string, Set<string>>()\n for (const delegate of contract.delegates ?? []) {\n for (const part of delegate.parts) {\n if (own.has(part))\n continue\n const scopes = out.get(part)\n if (scopes)\n scopes.add(delegate.name)\n else\n out.set(part, new Set([delegate.name]))\n }\n }\n return out\n}\n\n/**\n * 比对已发现的角色节点与契约:缺必需 part 报 error,出现解剖外的 part 名报 warn,\n * 委派目标不是已注册元素的解剖名报 error。\n * 委派节点的接线结果排到微任务里核:宿主在本函数返回后同步接线,微任务里读到的已是接线后的 data-scope。\n * 通道静默时直接返回,不做扫描。\n */\nexport function validatePartContract(\n contract: PartContract,\n parts: ReadonlyMap<string, HTMLElement[]>,\n host: HTMLElement,\n instanceId: string,\n): void {\n if (getDiagnostics().getLevel() === 'silent')\n return\n\n const scope = contract.anatomy.name\n\n for (const part of contract.meta.requiredParts) {\n if (parts.has(part))\n continue\n reportDiagnostic({\n code: DIAGNOSTIC_CODES.wcMissingPart,\n level: 'error',\n message: `缺少必需的角色节点 data-xh-part=\"${part}\",该部件不会被接线`,\n scope,\n instanceId,\n part,\n node: host,\n detail: { tag: host.tagName.toLowerCase(), requiredParts: contract.meta.requiredParts },\n })\n }\n\n const known = new Set<string>(contract.anatomy.parts)\n for (const delegate of contract.delegates ?? []) {\n for (const part of delegate.parts)\n known.add(part)\n }\n for (const part of parts.keys()) {\n if (known.has(part))\n continue\n reportDiagnostic({\n code: DIAGNOSTIC_CODES.wcUnknownPart,\n level: 'warn',\n message: `角色节点 data-xh-part=\"${part}\" 不在 ${scope} 的解剖内,不会被接线`,\n scope,\n instanceId,\n part,\n node: parts.get(part)?.[0] ?? host,\n detail: { tag: host.tagName.toLowerCase(), knownParts: contract.anatomy.parts },\n })\n }\n\n for (const [part, allowed] of Object.entries(contract.tags ?? {})) {\n for (const el of parts.get(part) ?? []) {\n const tag = el.tagName.toLowerCase()\n if (allowed.includes(tag))\n continue\n reportDiagnostic({\n code: DIAGNOSTIC_CODES.wcWrongPartTag,\n level: 'warn',\n message: `角色节点 data-xh-part=\"${part}\" 是 <${tag}>,须是 ${allowed.map(t => `<${t}>`).join(' 或 ')},否则原生语义静默失效`,\n scope,\n instanceId,\n part,\n node: el,\n detail: { tag, allowed },\n })\n }\n }\n\n if (!contract.delegates?.length)\n return\n const unregistered = new Set<string>()\n for (const delegate of contract.delegates) {\n if (isRegisteredScope(delegate.name))\n continue\n unregistered.add(delegate.name)\n reportDiagnostic({\n code: DIAGNOSTIC_CODES.invariant,\n level: 'error',\n message: `partContract.delegates 登记的 \"${delegate.name}\" 不是已注册元素 <xh-${delegate.name}> 的解剖名,委派给它的角色节点无从核对`,\n scope,\n instanceId,\n node: host,\n detail: { tag: host.tagName.toLowerCase(), delegate: delegate.name, parts: delegate.parts },\n })\n }\n\n queueMicrotask(() => validateDelegatedParts(contract, parts, host, instanceId, unregistered))\n}\n\n/**\n * 核对委派节点的接线结果:登记为归内嵌部件的角色节点,接线后 data-scope 必须是登记的 scope。\n * 没拿到 data-scope 即没被接线(多半是写错了位置),拿到别的 scope 即登记与接线对不上。\n * 已从宿主离场的节点与登记目标未注册的委派跳过。\n */\nexport function validateDelegatedParts(\n contract: PartContract,\n parts: ReadonlyMap<string, HTMLElement[]>,\n host: HTMLElement,\n instanceId: string,\n skipScopes: ReadonlySet<string> = new Set(),\n): void {\n if (!host.isConnected || getDiagnostics().getLevel() === 'silent')\n return\n const scope = contract.anatomy.name\n for (const [part, scopes] of delegatedScopesOf(contract)) {\n const expected = [...scopes].filter(s => !skipScopes.has(s))\n if (expected.length === 0)\n continue\n for (const el of parts.get(part) ?? []) {\n if (!host.contains(el))\n continue\n const wired = el.getAttribute('data-scope')\n if (wired !== null && expected.includes(wired))\n continue\n const target = expected.map(s => `\"${s}\"`).join(' 或 ')\n reportDiagnostic({\n code: wired === null ? DIAGNOSTIC_CODES.wcUnknownPart : DIAGNOSTIC_CODES.invariant,\n level: wired === null ? 'warn' : 'error',\n message: wired === null\n ? `角色节点 data-xh-part=\"${part}\" 登记为委派给 ${target},接线后没有 data-scope:没被接线,检查它是否放在了该放的部件里`\n : `角色节点 data-xh-part=\"${part}\" 登记为委派给 ${target},接线后 data-scope 却是 \"${wired}\",契约登记与接线对不上`,\n scope,\n instanceId,\n part,\n node: el,\n detail: { tag: host.tagName.toLowerCase(), expectedScopes: expected, wiredScope: wired },\n })\n }\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 层叠上下文诊断:浮层在 Light DOM 原地渲染,祖先只要建了层叠上下文,\n// 浮层的层号就退化成那个上下文里的局部序号,会被上层兄弟盖住。\nimport { DIAGNOSTIC_CODES, getDiagnostics, reportDiagnostic } from '@xihan-ui/core'\n\n/** 命中层叠上下文判据的那条属性。 */\nexport interface StackingCause {\n /** CSS 属性名。 */\n readonly property: string\n /** 该属性的计算值。 */\n readonly value: string\n}\n\n/** 困住浮层的那个祖先,与它命中的那条属性。 */\nexport interface StackingTrap {\n readonly ancestor: HTMLElement\n readonly cause: StackingCause\n}\n\n/** 初始值是 none 的一批:取任何别的值都建层叠上下文。 */\nconst NONE_INITIAL = [\n 'transform',\n 'translate',\n 'rotate',\n 'scale',\n 'perspective',\n 'filter',\n 'backdrop-filter',\n 'clip-path',\n 'mask-image',\n 'view-transition-name',\n] as const\n\n/** 建层叠上下文的那几档 contain;单独的 size 与 style 不算。 */\nconst CONTAIN = /\\b(?:layout|paint|strict|content)\\b/\n\n/** container-type 只有带 size 的两档施加布局限制;normal 与 scroll-state 不算。 */\nconst CONTAINER_TYPE = /\\bsize\\b/\n\n/** will-change 点到这些属性时,元素照样建层叠上下文。前缀能覆盖 transform-style、backdrop-filter、mask-image 等派生名。 */\nconst WILL_CHANGE = /\\b(?:transform|translate|rotate|scale|perspective|filter|opacity|mix-blend-mode|isolation|clip-path|mask|contain|content-visibility|container-type|view-transition-name)\\b/\n\nconst FLEX_OR_GRID = /^(?:inline-)?(?:flex|grid)$/\n\n/** 未设置的属性在部分无头 DOM 实现里回空串而不是初始值,两者一并当没设。 */\nfunction unset(value: string, initial: string): boolean {\n return value === '' || value === initial\n}\n\n/** 元素标识:标签名 + id + 前几个类名,够在页面里认出是哪一个。 */\nexport function describeElement(el: Element): string {\n const id = el.id ? `#${el.id}` : ''\n const names = Array.from(el.classList)\n const cls = names.length ? `.${names.slice(0, 3).join('.')}${names.length > 3 ? '…' : ''}` : ''\n return `${el.tagName.toLowerCase()}${id}${cls}`\n}\n\n/**\n * 这个元素建不建层叠上下文。命中即回那条属性与取值。\n * 判据与「抢走包含块」不同:position 本身与 z-index 在这里算数,而 container-type 收窄到带 size 的两档。\n */\nexport function stackingCauseOf(el: HTMLElement): StackingCause | null {\n const view = el.ownerDocument.defaultView\n if (!view)\n return null\n const style = view.getComputedStyle(el)\n const read = (property: string): string => style.getPropertyValue(property)\n const cause = (property: string): StackingCause => ({ property, value: read(property) })\n\n for (const property of NONE_INITIAL) {\n if (!unset(read(property), 'none'))\n return cause(property)\n }\n if (read('transform-style') === 'preserve-3d')\n return cause('transform-style')\n const opacity = Number.parseFloat(read('opacity'))\n if (Number.isFinite(opacity) && opacity < 1)\n return cause('opacity')\n if (!unset(read('mix-blend-mode'), 'normal'))\n return cause('mix-blend-mode')\n if (read('isolation') === 'isolate')\n return cause('isolation')\n if (CONTAIN.test(read('contain')))\n return cause('contain')\n if (/^(?:auto|hidden)$/.test(read('content-visibility')))\n return cause('content-visibility')\n if (CONTAINER_TYPE.test(read('container-type')))\n return cause('container-type')\n if (WILL_CHANGE.test(read('will-change')))\n return cause('will-change')\n\n const position = read('position')\n if (position === 'fixed' || position === 'sticky')\n return cause('position')\n if (unset(read('z-index'), 'auto'))\n return null\n if (position === 'relative' || position === 'absolute')\n return cause('z-index')\n // flex/grid 子项的 z-index 不必定位也生效\n const parent = el.parentElement\n if (parent && FLEX_OR_GRID.test(view.getComputedStyle(parent).display))\n return cause('z-index')\n return null\n}\n\n/**\n * 从浮层往上找第一个建层叠上下文的祖先,走到 body 为止。\n * 撞上外层浮层的 positioner 即止步:那一层由它自己的宿主去查。\n * body 与 documentElement 不算:页面内容与浮层同在其中,相对次序不受影响,\n * 而滚动锁本来就会给 body 写上 position: fixed。\n */\nexport function findStackingTrap(positioner: HTMLElement): StackingTrap | null {\n const doc = positioner.ownerDocument\n const stop = doc.body ?? doc.documentElement\n for (let node = positioner.parentElement; node && node !== stop; node = node.parentElement) {\n if (node.dataset.part === 'positioner')\n return null\n const cause = stackingCauseOf(node)\n if (cause)\n return { ancestor: node, cause }\n }\n return null\n}\n\n/**\n * 浮层展开后查一次祖先链,被层叠上下文困住就投诊断。\n * 通道静默时直接返回,不做扫描。\n */\nexport function reportStackingTrap(positioner: HTMLElement, scope: string | undefined, instanceId: string): void {\n if (getDiagnostics().getLevel() === 'silent')\n return\n const trap = findStackingTrap(positioner)\n if (!trap)\n return\n const where = describeElement(trap.ancestor)\n const { property, value } = trap.cause\n reportDiagnostic({\n code: DIAGNOSTIC_CODES.overlayStackingTrap,\n level: 'warn',\n message: `浮层的祖先 <${where}> 用 ${property}: ${value} 建了层叠上下文,浮层的层号只在它内部有效,会被上层兄弟盖住;去掉该祖先这条属性,或别把浮层放进这类容器`,\n scope,\n instanceId,\n part: 'positioner',\n node: trap.ancestor,\n detail: { ancestor: where, property, value },\n })\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 element base 相关实现。\n\nimport type { PartContract } from './dom/part-contract'\nimport type { Spreader } from './dom/spread'\nimport { onXhConfigChange, withXhConfig } from './config'\nimport { validatePartContract } from './dom/part-contract'\nimport { containsPart, discoverParts } from './dom/parts'\nimport { createSpreader } from './dom/spread'\nimport { reportStackingTrap } from './dom/stacking-context'\nimport { XhReactiveElement } from './reactive'\n\nlet instanceSeq = 0\n\n/**\n * 变动中是否真有角色节点进出。只认进出的元素自身是角色节点、或其子树中有角色节点:\n * 业务内容(图表、虚拟列表、面板中的业务 DOM)的增删与 part 集合无关,不应引发重新接线;\n * 更重要的是切断一条死循环:角色节点若本身是会在属性变化时改写自身子节点的自定义元素,\n * 宿主重新接线、写属性、该节点改子节点、再次命中观察器会形成环。\n */\nfunction touchesParts(record: MutationRecord): boolean {\n for (const list of [record.addedNodes, record.removedNodes]) {\n for (const node of Array.from(list)) {\n if (node.nodeType === 1 && containsPart(node as Element))\n return true\n }\n }\n return false\n}\n\n/**\n * 角色节点上属于作者的声明(与状态机写入的状态分属两侧),改变即等于更换了一个条目,必须重新接线。\n * 只观察这几个而不是所有属性:wire() 每帧都向角色节点写 aria- 与 data-,全量观察等于自己触发自己。\n */\nconst AUTHORED_ATTRS = ['value', 'name', 'data-path', 'disabled', 'aria-disabled'] as const\n\nfunction rewritesDeclaration(record: MutationRecord): boolean {\n if (record.type !== 'attributes' || !record.attributeName)\n return false\n const el = record.target as Element\n return containsPart(el) && (AUTHORED_ATTRS as readonly string[]).includes(record.attributeName)\n}\n\n// Light-DOM 行为宿主基类:不渲染结构,发现用户写的 data-xh-part 角色节点并往上打属性/事件。\nexport abstract class XhElement extends XhReactiveElement {\n /** 子类声明所属组件的解剖与元数据,接线后据它校验作者写的角色节点。 */\n static partContract?: PartContract\n\n protected readonly spreader: Spreader = createSpreader()\n protected partMap: Map<string, HTMLElement[]> = new Map()\n private partObserver: MutationObserver | undefined\n private readonly instanceId = `${++instanceSeq}`\n\n protected override createRenderRoot(): HTMLElement | DocumentFragment {\n return this // Light DOM,不建 shadowRoot\n }\n\n // 取角色节点,命名避开 HTMLElement.part。\n protected getPart(name: string, index = 0): HTMLElement | null {\n return this.partMap.get(name)?.[index] ?? null\n }\n\n protected getParts(name: string): HTMLElement[] {\n return this.partMap.get(name) ?? []\n }\n\n /**\n * 仍归本实例所有、但为脱离祖先层叠上下文而迁移到 Portal 的角色根。\n * 默认没有;返回的根必须与宿主属于同一 Document。\n */\n protected externalPartRoots(): readonly HTMLElement[] {\n return []\n }\n\n /** 接管前记下角色节点上作者写的内联 display。 */\n private readonly authorDisplay = new WeakMap<HTMLElement, string>()\n\n /**\n * 用内联 display 保证收起态:作者层若为该 part 声明了 display,会覆盖 UA 的 `[hidden]{display:none}`,\n * 仅靠 hidden 属性无法收起。展开时恢复作者原本的内联值而不是清为 '':后者会把作者写在该节点上的\n * `style=\"display:grid\"` 一并清除,且无法恢复。\n */\n protected setPartHidden(el: HTMLElement | null, hidden: boolean): void {\n if (!el)\n return\n if (!this.authorDisplay.has(el))\n this.authorDisplay.set(el, el.style.display)\n el.style.display = hidden ? 'none' : (this.authorDisplay.get(el) ?? '')\n }\n\n protected refreshParts(): void {\n const externalRoots = this.externalPartRoots()\n const ownerDocument = this.ownerDocument\n for (const root of externalRoots) {\n if (root.ownerDocument !== ownerDocument)\n throw new Error('[xh] Web Component 的 Portal 角色根必须与宿主属于同一 Document')\n }\n const next = discoverParts(this as unknown as HTMLElement, externalRoots)\n const live = new Set<HTMLElement>()\n for (const els of next.values()) {\n for (const el of els) live.add(el)\n }\n const gone: HTMLElement[] = []\n for (const els of this.partMap.values()) {\n for (const el of els) {\n if (!live.has(el))\n gone.push(el)\n }\n }\n // 先知会子类再交还:release 会撤掉本机器写过的属性,身份标记(data-value 等)一并消失,之后就认不出离场的是哪个条目\n if (gone.length)\n this.onPartsReleased(gone)\n // 离开本宿主的角色节点必须交还:否则它带着本机器的属性与监听器走,被挪进另一台同类元素后\n // 会同时挂上两台机器的处理器(一次点击驱动两台);单纯被移除的节点也仍能派事件、改本组状态\n for (const el of gone) this.spreader.release(el)\n this.partMap = next\n this.syncPartObservers()\n }\n\n /**\n * 角色节点即将离开本宿主时的回调,交还前调用(节点上仍带着本状态机写入的标记)。\n * 承载焦点的节点被移除时浏览器不派发 focusout(Chrome 如此),状态机无法得知,需要焦点语义的子类在此如实上报。\n */\n protected onPartsReleased(_nodes: readonly HTMLElement[]): void {}\n\n override connectedCallback(): void {\n super.connectedCallback()\n this.observeParts()\n // 配置一变就重铺:文案、locale、尺寸档都可能从全局或某个 <xh-config> 进来\n this.stopConfigWatch ??= onXhConfigChange(() => this.requestUpdate())\n // 重连(元素在 DOM 中被移动)时 controller 会重建机器,但重建前后状态相同、cell 不 bump 版本,\n // 于是不会自动排更新——wire 不再跑,角色节点上仍挂着指向已停机器的处理器(送事件会被静默丢弃,等于全是死的)。\n // 这里显式排一次;首帧与基类的初次更新合并,不多跑一帧\n this.requestUpdate()\n }\n\n private stopConfigWatch: (() => void) | undefined\n\n /**\n * 把沿祖先链解析到的全局配置合入这份 props:translations 按组件名分桶合并,\n * locale 与 size 在元素上未提供时取配置中的值。不运行状态机的元素在 wire() 中用它包一层。\n */\n protected configured<T extends object>(component: string, props: T): T {\n return withXhConfig(component, props, this)\n }\n\n /** 已排了断开后的交还,还没跑到。 */\n private releaseScheduled = false\n\n override disconnectedCallback(): void {\n super.disconnectedCallback()\n this.stopConfigWatch?.()\n this.stopConfigWatch = undefined\n this.partObserver?.disconnect()\n this.partObserver = undefined\n this.scheduleRelease()\n }\n\n /**\n * 排一次断开后的交还,到微任务里再按 isConnected 决定跑不跑。\n * 元素被移动(remove 后同步 append 到别处)走的也是 disconnect,延到微任务才分得清移动与真离场。\n */\n private scheduleRelease(): void {\n if (this.releaseScheduled)\n return\n this.releaseScheduled = true\n queueMicrotask(() => {\n this.releaseScheduled = false\n if (!this.isConnected)\n this.releaseAllParts()\n })\n }\n\n /**\n * 交还全部角色节点并清空 partMap,重连时由 refreshParts 重新发现。\n * 宿主离场后没有观察器再触发更新,refreshParts 那条交还路径够不着,没摘的监听器会经节点钉住整台宿主。\n */\n private releaseAllParts(): void {\n const gone: HTMLElement[] = []\n for (const els of this.partMap.values()) gone.push(...els)\n if (!gone.length)\n return\n this.onPartsReleased(gone)\n for (const el of gone) this.spreader.release(el)\n this.partMap = new Map()\n }\n\n /** 层叠上下文那条诊断已经查过。 */\n private stackingChecked = false\n\n /**\n * 浮层首次展开后查一次祖先链有没有建层叠上下文,命中即投诊断。\n * 每个实例只查一次,重定位与后续展开不再重复。\n */\n private checkStackingTrap(scope: string | undefined): void {\n if (this.stackingChecked)\n return\n const positioner = this.getParts('positioner').find(el => el.dataset.state === 'open')\n if (!positioner)\n return\n this.stackingChecked = true\n reportStackingTrap(positioner, scope, this.instanceId)\n }\n\n /** 标记 wire() 正在写属性。 */\n private wiring = false\n\n /**\n * 作者在运行期改动 Light DOM 后重新接线,两类改动都要接住:增删角色节点(漏掉会留下没有\n * data-scope/data-part 与处理器的\"死条目\");原地改写节点上的声明(列表换数据复用节点时就是这形状,\n * 漏掉会留着上一轮写的 aria-selected=\"true\",而它自称的 value 已经变了,读屏念出的选中项就不是真的选中项)。\n */\n private observeParts(): void {\n if (this.partObserver)\n return\n this.partObserver = new MutationObserver((records) => {\n if (this.wiring)\n return\n const hit = records.some(r => (touchesParts(r) || rewritesDeclaration(r)) && this.ownsSubtree(r.target))\n if (hit)\n this.requestUpdate()\n })\n this.syncPartObservers()\n }\n\n private syncPartObservers(): void {\n const observer = this.partObserver\n if (!observer)\n return\n observer.disconnect()\n const observe = (root: Node): void => observer.observe(root, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [...AUTHORED_ATTRS],\n })\n observe(this)\n for (const root of this.externalPartRoots())\n observe(root)\n }\n\n /** 目标是否归本宿主管:嵌套 xh-* 子树归内层元素自己管,外层不替它重跑 wire(discoverParts 本来也跳过它们)。 */\n private ownsSubtree(target: Node): boolean {\n for (const root of this.externalPartRoots()) {\n if (target !== root && !root.contains(target))\n continue\n for (let node: Node | null = target; node; node = node.parentNode) {\n if (node === root)\n return true\n const tag = (node as Element).tagName\n if (typeof tag === 'string' && tag.toLowerCase().startsWith('xh-'))\n break\n }\n }\n for (let node: Node | null = target; node; node = node.parentNode) {\n if (node === this)\n return true\n const tag = (node as Element).tagName\n if (typeof tag === 'string' && tag.toLowerCase().startsWith('xh-'))\n return false\n }\n return false\n }\n\n protected override updated(changed: Map<PropertyKey, unknown>): void {\n super.updated(changed)\n // 断开的宿主机器已停机,再接线只会把指向死机器的监听器挂回去、覆盖已接管这些节点的存活宿主;\n // 重连时 connectedCallback 会排一轮补上\n if (!this.isConnected)\n return\n this.refreshParts()\n const contract = (this.constructor as typeof XhElement).partContract\n if (contract)\n validatePartContract(contract, this.partMap, this as unknown as HTMLElement, this.instanceId)\n // 观察器与 wire() 写的是同一批节点,不圈出本区间会自己触发自己;观察器回调是微任务,故圈到微任务排空为止。\n this.wiring = true\n try {\n this.wire()\n }\n finally {\n queueMicrotask(() => {\n this.wiring = false\n })\n }\n // 排在 wire() 之后:data-state 得先落进 DOM,才认得出浮层这一帧是不是展开的\n this.checkStackingTrap(contract?.anatomy.name)\n }\n\n /** 子类实现:把 connect 产出接到角色节点上。 */\n protected abstract wire(): void\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 退场闸门:把「几时真的收起浮层子树」从展开态挪到 presence 上。\n//\n// Light DOM 下元素无权增删作者的节点,所以这里被 presence 拉长的不是「节点存在的时间」\n// 而是「可见的时间」——收起从跟着 open 走,改成跟着 presence 走。\n\nimport type { Cleanup, RuntimeConfig } from '@xihan-ui/core'\nimport type { PresenceHandle } from '@xihan-ui/core/presence'\nimport { attachCssExit, createPresence } from '@xihan-ui/core/presence'\n\nexport interface OverlayExit {\n /** 行为资源与视觉退场共享的同一份租约。 */\n readonly presence: PresenceHandle\n /** 浮层子树当前是否应当可见:展开时为真,退场动画播完之前也为真。 */\n readonly visible: boolean\n /** content 节点就位或更换时调用,把它的 CSS 退场动画接到退出租约上。 */\n track: (...nodes: Array<HTMLElement | null>) => void\n /** data-state 写进 DOM 之后调用。 */\n update: (open: boolean) => void\n /** 元素离场:立即结清,visible 归 false。幂等。 */\n dispose: () => void\n}\n\nexport interface OverlayExitOptions {\n config: RuntimeConfig\n open: boolean\n /** 退场结束时回调,宿主据此排一次更新,把收起真正落到 display 上。 */\n onExitComplete: () => void\n}\n\nexport function createOverlayExit(options: OverlayExitOptions): OverlayExit {\n let disposed = false\n const tracked = new Map<HTMLElement, Cleanup>()\n\n const presence: PresenceHandle = createPresence({\n config: options.config,\n open: options.open,\n onRenderedChange: (rendered) => {\n if (!rendered && !disposed)\n options.onExitComplete()\n },\n })\n\n return {\n presence,\n get visible() {\n return !disposed && presence.rendered\n },\n track(...nodes) {\n if (disposed)\n return\n const next = new Set(nodes.filter((node): node is HTMLElement => node !== null))\n for (const node of next) {\n if (!tracked.has(node))\n tracked.set(node, attachCssExit(node, presence))\n }\n for (const [node, detach] of tracked) {\n if (!next.has(node)) {\n tracked.delete(node)\n detach()\n }\n }\n },\n update(open) {\n if (!disposed)\n presence.update(open)\n },\n dispose() {\n if (disposed)\n return\n disposed = true\n presence.dispose()\n for (const detach of tracked.values()) detach()\n tracked.clear()\n },\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 button 相关实现。\n\nimport type { ActionVariant, Size, Tone } from '@xihan-ui/core'\nimport type { ButtonProps, ButtonSchema } from '@xihan-ui/headless'\nimport { buttonAnatomy, buttonMachine, buttonMeta, connectButton } from '@xihan-ui/headless'\nimport { wcNormalize } from '../dom/normalize'\nimport { XhElement } from '../element-base'\nimport { MachineController } from '../runtime/machine-controller'\n\n/**\n * `<xh-button>`:按钮行为宿主,宿主属性即 button props;机器只承载按压通道(data-pressed)。\n *\n * @customElement xh-button\n * @attr {'button'|'submit'|'reset'} type - 原生按钮类型,默认 button\n * @attr {boolean} disabled - 禁用(原生 disabled,失去焦点)\n * @attr {boolean} icon-only - 仅图标:左右内边距清零、宽高相等;作者须自行提供可及名\n * @attr {boolean} full-width - 撑满行宽\n * @attr {boolean} loading - 加载中(aria-disabled,保留焦点并拦截点击)\n * @attr {'solid'|'subtle'|'outline'|'ghost'} variant - 视觉变体,默认 solid(只有 Button 缺省品牌实心,其余触发器缺省中性)\n * @attr {'brand'|'neutral'|'success'|'warning'|'danger'|'info'} tone - 颜色\n * @attr {'sm'|'md'|'lg'} size - 尺寸\n * @attr {'button'|'a'} as - 根节点渲染的标签,默认 button;写 a 时不再产出 type 与原生 disabled\n * @csspart root - 承载 data-scope/data-part/data-* 的原生 button(as=\"a\" 时是 a)\n */\nexport class XhButtonElement extends XhElement {\n static override partContract = { anatomy: buttonAnatomy, meta: buttonMeta }\n\n static override properties = {\n type: {},\n disabled: { type: Boolean },\n iconOnly: { type: Boolean, attribute: 'icon-only' },\n fullWidth: { type: Boolean, attribute: 'full-width' },\n loading: { type: Boolean },\n variant: {},\n tone: {},\n size: {},\n as: {},\n }\n\n declare type?: 'button' | 'submit' | 'reset'\n declare disabled?: boolean\n declare iconOnly?: boolean\n declare fullWidth?: boolean\n declare loading?: boolean\n declare variant?: ActionVariant\n declare tone?: Tone\n declare size?: Size\n declare as?: ButtonProps['as']\n\n private readonly ctrl = new MachineController<ButtonSchema>(this, buttonMachine, () => this.machineProps())\n\n private machineProps(): Partial<ButtonSchema['props']> {\n const root = this.getPart('root')\n return {\n type: this.type,\n disabled: this.disabled,\n loading: this.loading,\n variant: this.variant,\n tone: this.tone,\n size: this.size,\n as: this.as,\n iconOnly: this.iconOnly,\n fullWidth: this.fullWidth,\n // 作者写在根节点上的可及名转告连接层,图标按钮缺名时由它提醒\n ariaLabel: root?.getAttribute('aria-label') ?? undefined,\n ariaLabelledby: root?.getAttribute('aria-labelledby') ?? undefined,\n }\n }\n\n protected wire(): void {\n const root = this.getPart('root')\n if (!root)\n return\n const api = connectButton(this.ctrl.service, wcNormalize)\n this.spreader.spread(root, api.getRootProps() as Record<string, unknown>)\n\n // label / prefix / suffix / indicator 都是可选角色节点,作者写了才接\n const put = (name: string, props: Record<string, unknown>): void => {\n const el = this.getPart(name)\n if (el)\n this.spreader.spread(el, props)\n }\n put('label', api.getLabelProps() as Record<string, unknown>)\n put('prefix', api.getPrefixProps() as Record<string, unknown>)\n put('suffix', api.getSuffixProps() as Record<string, unknown>)\n put('indicator', api.getIndicatorProps() as Record<string, unknown>)\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 portal lease controller 相关实现。\n\nimport type { Cleanup, PortalLease, RuntimeConfig } from '@xihan-ui/core'\nimport { createPortalLease } from '@xihan-ui/core'\n\nexport interface PortalLeaseControllerOptions {\n /** 诊断中的组件名。 */\n name: string\n /** 当前宿主所属 Document 的 RuntimeConfig。 */\n config: () => RuntimeConfig | null\n /** 实例或 xh-config 声明的 Portal 容器解析器;缺席时才回落 RuntimeConfig。 */\n portalContainer?: () => (() => Element | null) | undefined\n /** Portal 视觉环境的逻辑来源。 */\n source: () => Element | null\n /** 同一租约原子搬迁的根。 */\n roots: () => readonly HTMLElement[]\n /** 根搬迁前建立适配器逻辑所有权;清理在根归位后执行。 */\n onShellReady?: (shell: HTMLElement) => Cleanup | void\n /** 租约换代后让 XhElement 重建外部部件发现与 MutationObserver。 */\n onChange: () => void\n}\n\n/**\n * Web Components 对 Core PortalLease 的共享生命周期接线。\n * placeholder、独占壳、视觉桥、事务回滚与精确归位仍全部由 Core 持有。\n */\nexport class PortalLeaseController {\n private lease: PortalLease | null = null\n\n constructor(private readonly options: PortalLeaseControllerOptions) {}\n\n /** XhElement 用它继续发现已经迁移到宿主外的全部角色节点。 */\n get roots(): readonly HTMLElement[] {\n return this.lease?.roots ?? []\n }\n\n /**\n * 某个根在作者结构里的落点:未搬迁时就是它自己,搬迁中是租约留在原位的占位节点。\n * 宿主自己生成、要排在浮层之前的节点(表单出口)按它定位,浮层归位后顺序不变。\n */\n homeOf(root: HTMLElement): Node {\n const index = this.lease?.roots.indexOf(root) ?? -1\n return index >= 0 ? this.lease!.placeholders[index]! : root\n }\n\n /** Presence 仍可见时持有租约;退场完成或必要节点缺席时精确归位。 */\n sync(active: boolean): void {\n const source = this.options.source()\n const roots = this.options.roots()\n if (!active || !source || !roots.length) {\n if (this.release())\n this.options.onChange()\n return\n }\n\n const target = this.resolveTarget()\n\n if (\n this.lease?.source === source\n && this.lease.target === target\n && roots.length === this.lease.roots.length\n && roots.every((root, index) => root === this.lease!.roots[index])\n ) {\n return\n }\n\n this.release()\n this.lease = createPortalLease({ source, target, roots, onShellReady: this.options.onShellReady })\n this.options.onChange()\n }\n\n /** 宿主断开或 realm 换代时立即归位;Core 的 release 自身幂等。 */\n dispose(): void {\n this.release()\n }\n\n private release(): boolean {\n const lease = this.lease\n if (!lease)\n return false\n this.lease = null\n lease.release()\n return true\n }\n\n private resolveTarget(): Element {\n const resolver = this.options.portalContainer?.() ?? this.options.config()?.portalContainer\n let target: Element | null | undefined\n try {\n target = resolver?.()\n }\n catch (error) {\n if (this.release())\n this.options.onChange()\n throw error\n }\n if (target)\n return target\n if (this.release())\n this.options.onChange()\n throw new Error(`[xh] ${this.options.name} 的 portalContainer 必须返回已连接的同 Document Element`)\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 anchored portal controller 相关实现。\n\nimport type { Cleanup, RuntimeConfig } from '@xihan-ui/core'\nimport { PortalLeaseController } from './portal-lease-controller'\n\nexport interface AnchoredPortalControllerOptions {\n /** 诊断中的组件名。 */\n name: string\n /** 当前宿主所属 Document 的 RuntimeConfig。 */\n config: () => RuntimeConfig | null\n /** 实例或 xh-config 声明的 Portal 容器解析器;缺席时才回落 RuntimeConfig。 */\n portalContainer?: () => (() => Element | null) | undefined\n /** 视觉环境来源,通常是 trigger;组合输入使用 control。 */\n source: () => Element | null\n /** 被物理搬迁的 positioner 根。 */\n root: () => HTMLElement | null\n /** 根搬迁前建立适配器逻辑所有权;清理在根归位后执行。 */\n onShellReady?: (shell: HTMLElement) => Cleanup | void\n /** 租约换代后让 XhElement 重建外部部件发现与 MutationObserver。 */\n onChange: () => void\n}\n\n/**\n * 锚定浮层的 Web Components 共享 Portal 接线。\n * placeholder、独占壳、视觉桥、事务回滚与精确归位全部由 Core PortalLease 持有。\n */\nexport class AnchoredPortalController {\n private readonly portal: PortalLeaseController\n\n constructor(private readonly options: AnchoredPortalControllerOptions) {\n this.portal = new PortalLeaseController({\n ...options,\n roots: () => {\n const root = options.root()\n return root ? [root] : []\n },\n })\n }\n\n /** XhElement 用它继续发现已经迁移到宿主外的全部角色节点。 */\n get roots(): readonly HTMLElement[] {\n return this.portal.roots\n }\n\n /** positioner 在作者结构里的落点:未搬迁时是它自己,搬迁中是占位节点;缺席时为 null。 */\n home(): Node | null {\n const root = this.options.root()\n return root ? this.portal.homeOf(root) : null\n }\n\n /** Presence 仍可见时持有租约;退场完成或必要节点缺席时精确归位。 */\n sync(active: boolean): void {\n this.portal.sync(active)\n }\n\n /** 宿主断开或 realm 换代时立即归位;Core 的 release 自身幂等。 */\n dispose(): void {\n this.portal.dispose()\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 portal host 相关实现。\n\nimport type { PropertyDeclarations } from '../reactive'\nimport type { AnchoredPortalControllerOptions } from './anchored-portal-controller'\nimport type { PortalLeaseControllerOptions } from './portal-lease-controller'\nimport { resolveXhConfig } from '../config'\nimport { XhElement } from '../element-base'\nimport { AnchoredPortalController } from './anchored-portal-controller'\nimport { PortalLeaseController } from './portal-lease-controller'\n\nexport type PortalContainerResolver = () => Element | null\n\n/**\n * 只供真正物理 Portal 宿主继承;普通 XhElement(包括 NavigationMenu)不公开此能力。\n * property 响应式由基类统一声明,实例变化会自然触发各宿主既有 wire/sync。\n */\nexport abstract class XhPortalHostElement extends XhElement {\n static override properties: PropertyDeclarations = {\n portalContainer: { attribute: false },\n }\n\n /** 本实例的 Portal 目标解析器;显式设置后不回退 xh-config 或 RuntimeConfig。 */\n declare portalContainer?: PortalContainerResolver\n\n protected createPortalLeaseController(\n options: Omit<PortalLeaseControllerOptions, 'portalContainer'>,\n ): PortalLeaseController {\n return new PortalLeaseController({\n ...options,\n portalContainer: () => this.portalContainer ?? resolveXhConfig(this).portalContainer,\n })\n }\n\n protected createAnchoredPortalController(\n options: Omit<AnchoredPortalControllerOptions, 'portalContainer'>,\n ): AnchoredPortalController {\n return new AnchoredPortalController({\n ...options,\n portalContainer: () => this.portalContainer ?? resolveXhConfig(this).portalContainer,\n })\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 dialog 相关实现。\n\nimport type { Cleanup, IdGenerator, Layer, OverlayBackdropVariant, RuntimeConfig, Service, Size } from '@xihan-ui/core'\nimport type { DialogOpenChangeDetails, DialogSchema } from '@xihan-ui/headless'\nimport type { OverlayExit } from '../overlay-exit'\nimport { createCounterIdGenerator, createRuntimeConfig, createScope } from '@xihan-ui/core'\nimport { connectDialog, dialogAnatomy, dialogMachine, dialogMeta } from '@xihan-ui/headless'\nimport { resolveXhConfig } from '../config'\nimport { wcNormalize } from '../dom/normalize'\nimport { createOverlayExit } from '../overlay-exit'\nimport { MachineController } from '../runtime/machine-controller'\nimport { XhPortalHostElement } from '../runtime/portal-host'\n\n// 三态布尔:缺席=undefined(用默认值)、=\"false\"=false、其余=true。\nconst BOOLEAN_CONVERTER = { fromAttribute: (v: string | null) => (v === null ? undefined : v !== 'false') }\n// 属性缺席翻成 undefined,缺省值由皮肤的缺省档决定。\nconst STRING_CONVERTER = { fromAttribute: (v: string | null) => v ?? undefined }\n\n/**\n * `<xh-dialog>`:Light-DOM 行为宿主,运行 dialog 状态机并把 connect 产出接到角色节点上,\n * 关闭时用内联 style.display 隐藏浮层子树。\n *\n * @customElement xh-dialog\n * @attr {boolean} open - 受控开合;未提供该属性即非受控\n * @attr {boolean} default-open - 非受控初始为打开\n * @attr {boolean} modal - 模态(陷入焦点、锁定滚动、遮罩交互外关闭),默认 true\n * @attr {'dialog'|'alertdialog'} role - 语义角色,默认 dialog\n * @attr {boolean} close-on-escape - Esc 关闭,默认 true\n * @attr {boolean} restore-focus - 关闭后把焦点归还触发元素,默认 true\n * @attr {string} initial-focus - 展开后先聚焦到 content 内匹配此选择器的元素\n * @attr {'sm'|'md'|'lg'} size - 尺寸:只影响 content 的最大宽度,写在 content 上\n * @attr {'opaque'|'blur'|'transparent'} variant - 遮罩形态:只影响 backdrop 的底色与模糊\n * @fires open-change - open 状态变化;detail 为 `{ open: boolean }`\n * @fires exit-complete - 退出完成且本层资源已释放\n * @csspart trigger - 触发按钮\n * @csspart backdrop - 遮罩层\n * @csspart positioner - 浮层定位容器\n * @csspart content - 对话框内容(role / aria-modal / 焦点陷阱所在)\n * @csspart header - 面板头:标题与说明所在的段,不随正文滚动\n * @csspart indicator - 语气徽记:未提供内容时由皮肤按节点上的 data-tone 绘制兜底字形\n * @csspart title - 标题(aria-labelledby 目标)\n * @csspart description - 描述(aria-describedby 目标)\n * @csspart body - 正文:面板中唯一会滚动的段\n * @csspart footer - 面板尾:动作按钮所在的段,不随正文滚动\n * @csspart close-trigger - 关闭按钮\n */\nexport class XhDialogElement extends XhPortalHostElement {\n /** 本实例的 Portal 容器;显式解析失败不回退配置默认。 */\n declare portalContainer?: () => Element | null\n\n static override partContract = { anatomy: dialogAnatomy, meta: dialogMeta }\n\n // role 不声明为响应式属性,复用 HTMLElement 原生反射,在 machineProps 里经 getAttribute 读取。\n static override properties = {\n open: { converter: BOOLEAN_CONVERTER },\n defaultOpen: { type: Boolean, attribute: 'default-open' },\n modal: { converter: BOOLEAN_CONVERTER },\n closeOnEscape: { converter: BOOLEAN_CONVERTER, attribute: 'close-on-escape' },\n restoreFocus: { converter: BOOLEAN_CONVERTER, attribute: 'restore-focus' },\n initialFocus: { converter: STRING_CONVERTER, attribute: 'initial-focus' },\n size: { converter: STRING_CONVERTER },\n variant: { converter: STRING_CONVERTER },\n // 对象进不了属性,只作为 property 暴露\n translations: { attribute: false },\n }\n\n declare open?: boolean\n declare defaultOpen?: boolean\n declare modal?: boolean\n declare closeOnEscape?: boolean\n declare restoreFocus?: boolean\n declare initialFocus?: string\n declare size?: Size\n declare variant?: OverlayBackdropVariant\n /** 关闭按钮的无障碍名;connect 每帧重写 aria-label,作者写在节点上的值会被覆盖,只能从此处提供。 */\n declare translations?: DialogSchema['props']['translations']\n\n private readonly idGen: IdGenerator = createCounterIdGenerator()\n // 运行时环境必须始终取宿主当前所属 Document:iframe 创建或 adopt 之后不能继续用构造时的全局 realm。\n private readonly dialogScope = createScope(() => this, this.idGen)\n private config: RuntimeConfig | null = null\n private contentNode: HTMLElement | null = null\n private exit: OverlayExit | null = null\n private backdropNode: HTMLElement | null = null\n private readonly portal = this.createPortalLeaseController({\n name: 'Dialog 视口模态',\n config: () => this.config,\n source: () => this,\n roots: () => {\n const positioner = this.getPart('positioner')\n return this.backdropNode && positioner ? [this.backdropNode, positioner] : []\n },\n onChange: () => this.requestUpdate(),\n })\n\n private readonly notify = (details: DialogOpenChangeDetails): void => {\n this.dispatchEvent(new CustomEvent('open-change', { detail: details, bubbles: true, composed: true }))\n }\n\n private readonly ctrl = new MachineController<DialogSchema>(\n this,\n dialogMachine,\n () => this.machineProps(),\n { scope: this.dialogScope, onBuilt: svc => this.injectRefs(svc) },\n )\n\n private machineProps(): Partial<DialogSchema['props']> {\n return {\n open: this.open,\n defaultOpen: this.defaultOpen ?? false,\n modal: this.modal,\n role: (this.getAttribute('role') as DialogSchema['props']['role']) ?? undefined,\n closeOnEscape: this.closeOnEscape,\n restoreFocus: this.restoreFocus,\n initialFocus: this.initialFocus,\n size: this.size,\n variant: this.variant,\n translations: this.translations,\n onOpenChange: this.notify,\n onExitComplete: () => this.dispatchEvent(new CustomEvent('exit-complete', { bubbles: true, composed: true })),\n }\n }\n\n private ensureConfig(): void {\n if (this.config)\n return\n // scrollRoot 每次现读:配置沿祖先链解析,元素搬家或 <xh-config> 改了都要跟上\n this.config = createRuntimeConfig({\n scope: this.dialogScope,\n idGenerator: this.idGen,\n scrollRoot: () => resolveXhConfig(this).scrollRoot?.() ?? null,\n })\n }\n\n /** 退场闸门建一次;presence 不是响应式 cell,退场结束要显式排一次更新才轮得到收起。 */\n private ensureExit(open: boolean): OverlayExit {\n this.ensureConfig()\n this.exit ??= createOverlayExit({\n config: this.config!,\n open,\n onExitComplete: () => this.requestUpdate(),\n })\n return this.exit\n }\n\n protected override externalPartRoots(): readonly HTMLElement[] {\n return this.portal.roots\n }\n\n // 只交注册函数,层的入栈出栈由机器的 trackOverlay 效应跟着展开态做。\n private readonly registerLayer = (): { layer: Layer, dispose: Cleanup } => {\n this.ensureConfig()\n return this.config!.layerRegistry.register({\n kind: 'modal',\n node: () => this.contentNode,\n branches: () => [],\n isModal: () => this.machineProps().modal ?? true,\n surfaces: () => [this.backdropNode].filter(Boolean) as Element[],\n })\n }\n\n // onBuilt 在 ctrl 构造期就跑,service 由参数传入。\n private injectRefs(svc: Service<DialogSchema>): void {\n this.ensureConfig()\n svc.refs.set('config', this.config)\n svc.refs.set('registerLayer', this.registerLayer)\n svc.refs.set('presence', this.ensureExit(svc.state.get() === 'open').presence)\n svc.refs.set('getContentEl', () => this.contentNode)\n svc.refs.set('getTriggerEl', () => this.getPart('trigger'))\n svc.refs.set('branches', () => [])\n }\n\n protected wire(): void {\n const svc = this.ctrl.service\n const api = connectDialog(svc, wcNormalize)\n const open = svc.state.get() === 'open'\n\n this.contentNode = this.getPart('content')\n this.backdropNode = this.getPart('backdrop')\n\n const put = (name: string, props: Record<string, unknown>): void => {\n const el = this.getPart(name)\n if (el)\n this.spreader.spread(el, props)\n }\n put('trigger', api.getTriggerProps() as Record<string, unknown>)\n put('backdrop', api.getBackdropProps() as Record<string, unknown>)\n put('positioner', api.getPositionerProps() as Record<string, unknown>)\n put('content', api.getContentProps() as Record<string, unknown>)\n put('header', api.getHeaderProps() as Record<string, unknown>)\n put('indicator', api.getIndicatorProps() as Record<string, unknown>)\n put('title', api.getTitleProps() as Record<string, unknown>)\n put('description', api.getDescriptionProps() as Record<string, unknown>)\n put('body', api.getBodyProps() as Record<string, unknown>)\n put('footer', api.getFooterProps() as Record<string, unknown>)\n put('close-trigger', api.getCloseTriggerProps() as Record<string, unknown>)\n\n // 退场动画播完之前先别收:presence 读 content 的 animationName 决定要不要多留一会儿。\n // 必须排在 put('content') 之后——data-state 得先落进 DOM,探测器才读得到退场那支动画\n const exit = this.ensureExit(open)\n const modal = this.machineProps().modal ?? true\n exit.track(this.contentNode, modal ? this.backdropNode : null)\n exit.update(open)\n const visible = exit.visible\n\n const positioner = this.getPart('positioner')\n // 非模态不领取视口租约;缺一个根时共享控制器保持既有 Light-DOM 结构。\n this.portal.sync(modal && (open || visible))\n\n // 收起用内联 display,优先级高于样式表对 [hidden] 的覆盖\n if (positioner)\n this.setPartHidden(positioner, !visible)\n if (this.backdropNode)\n this.setPartHidden(this.backdropNode, !visible || !modal)\n // positioner 不是必需部件,content 自己也要收起\n this.setPartHidden(this.contentNode, !visible)\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback()\n // 退场没播完就离场:立刻结清并把子树收起,否则作者的节点会带着已被撤掉的 data-state 留在页面上。\n // 只在机器已经收起时才强收——元素被移动(remove 后立刻 append)时展开态不该被打断\n this.exit?.dispose()\n this.exit = null\n this.portal.dispose()\n if (this.ctrl.service.state.get() !== 'open')\n this.setPartHidden(this.contentNode, true)\n this.config = null // 重连时 ensureConfig 重建\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 loading bar 相关实现。\n\nimport type { Tone } from '@xihan-ui/core'\nimport type { LoadingBarSchema, LoadingBarTranslations, LoadingBarValueChangeDetails } from '@xihan-ui/headless'\nimport { connectLoadingBar, loadingBarAnatomy, loadingBarMachine, loadingBarMeta } from '@xihan-ui/headless'\nimport { wcNormalize } from '../dom/normalize'\nimport { XhElement } from '../element-base'\nimport { MachineController } from '../runtime/machine-controller'\n\n// 属性缺席翻成 undefined,缺省值由机器与 connect 决定。\nconst STRING_CONVERTER = { fromAttribute: (v: string | null) => v ?? undefined }\n// 空串也当缺席:`value=\"\"` 经 Number() 会变成 0,那是一个货真价实的进度值,不是\"没写\"\nconst NUMBER_CONVERTER = { fromAttribute: (v: string | null) => (v == null || v === '' ? undefined : Number(v)) }\n// 缺省为真的开关(trickle)得能被 =\"false\" 关掉;三态:缺席 = undefined(用默认值),=\"false\" = false,其余 = true\nconst BOOLEAN_CONVERTER = { fromAttribute: (v: string | null) => (v === null ? undefined : v !== 'false') }\n// 厚度两用:`height=\"3\"` 按像素,`height=\"0.25rem\"` 按 CSS 长度原样交给 connect\nconst HEIGHT_CONVERTER = {\n fromAttribute: (v: string | null): string | number | undefined => {\n if (v == null || v === '')\n return undefined\n const px = Number(v)\n return Number.isFinite(px) ? px : v\n },\n}\n\n/**\n * `<xh-loading-bar>`:Light-DOM 行为宿主:作者写 root / track / range 角色节点,\n * 元素运行 loading-bar 状态机并把 connect 产出接上。\n *\n * 两种模式互不相干:提供 `value` 即为确定进度,宽度按它显示、读屏可以获取 aria-valuenow;\n * 未提供时使用模拟进度:`loading` 置真时先跳到 `minimum`,随后按 `trickle-speed` 逐拍爬升,\n * 步长按剩余量取,因此越接近满格越慢且永远到不了 100;此时按规范不报告 aria-valuenow,\n * 属性缺席本身就是进度未知的表达。`loading` 转为假时先到达 100,走完淡出窗口才归零收起。\n *\n * 收起态只给 root 加 hidden 并写一条内联 display,作者编写的结构一个都不卸载。\n *\n * @customElement xh-loading-bar\n * @attr {number} value - 受控进度值(0-100);提供后即为确定进度,内部爬升整体让位\n * @attr {number} default-value - 非受控初值,默认 0\n * @attr {boolean} loading - 加载开关:属性存在即开始,`loading=\"false\"` 或移除即结束\n * @attr {string|number} height - 进度条厚度:纯数字按像素,其余按 CSS 长度;默认 2px\n * @attr {'brand'|'neutral'|'success'|'warning'|'danger'|'info'} tone - 语气,决定进度段使用哪族颜色;提供 color 时以 color 为准\n * @attr {boolean} trickle - 不确定进度时自行向前爬升,默认开启;`trickle=\"false\"` 关闭\n * @attr {number} trickle-speed - 爬升节拍毫秒,默认 200;<=0 等同于关闭爬升\n * @attr {number} minimum - 起步值,默认 8\n * @attr {number} fade-duration - 到达 100 之后的淡出窗口毫秒,默认 200\n * @fires value-change - 进度值变化;detail 为 `{ value: number }`\n * @csspart root - progressbar 本身(承载名字、值域、data-state 与收起态)\n * @csspart track - 背景槽\n * @csspart range - 进度段;宽度由元素写入内联样式,样式层不应修改该轴\n * @csspart peg - 进度段末端的亮边(对读屏隐藏)\n */\nexport class XhLoadingBarElement extends XhElement {\n static override partContract = { anatomy: loadingBarAnatomy, meta: loadingBarMeta }\n\n // 描述符逐个写全,CEM 分析器读不了对象展开。\n static override properties = {\n value: { converter: NUMBER_CONVERTER },\n defaultValue: { converter: NUMBER_CONVERTER, attribute: 'default-value' },\n loading: { converter: BOOLEAN_CONVERTER },\n height: { converter: HEIGHT_CONVERTER },\n tone: { converter: STRING_CONVERTER },\n trickle: { converter: BOOLEAN_CONVERTER },\n trickleSpeed: { converter: NUMBER_CONVERTER, attribute: 'trickle-speed' },\n minimum: { converter: NUMBER_CONVERTER },\n fadeDuration: { converter: NUMBER_CONVERTER, attribute: 'fade-duration' },\n // 文案是对象,走不了属性;只作为 property 暴露,与 Vue 侧的 translations prop 对齐\n translations: { attribute: false },\n }\n\n declare value?: number\n declare defaultValue?: number\n declare loading?: boolean\n declare height?: string | number\n declare tone?: Tone\n declare trickle?: boolean\n declare trickleSpeed?: number\n declare minimum?: number\n declare fadeDuration?: number\n declare translations?: Partial<LoadingBarTranslations>\n\n private readonly notify = (details: LoadingBarValueChangeDetails): void => {\n this.dispatchEvent(new CustomEvent('value-change', { detail: details, bubbles: true, composed: true }))\n }\n\n // loading-bar 机器的副作用只有两个计时器(自身自足):不需要 config/layer/refs,controller 只带 props。\n private readonly ctrl = new MachineController<LoadingBarSchema>(this, loadingBarMachine, () => this.machineProps())\n\n private machineProps(): Partial<LoadingBarSchema['props']> {\n return {\n value: this.value,\n defaultValue: this.defaultValue,\n // 布尔属性经三态转换器进来:不在即 undefined,把缺省交回机器\n loading: this.loading,\n height: this.height,\n tone: this.tone,\n trickle: this.trickle,\n trickleSpeed: this.trickleSpeed,\n minimum: this.minimum,\n fadeDuration: this.fadeDuration,\n translations: this.translations,\n onValueChange: this.notify,\n }\n }\n\n protected wire(): void {\n const api = connectLoadingBar(this.ctrl.service, wcNormalize)\n\n const put = (name: string, props: Record<string, unknown>): void => {\n const el = this.getPart(name)\n if (el)\n this.spreader.spread(el, props)\n }\n put('root', api.getRootProps() as Record<string, unknown>)\n put('track', api.getTrackProps() as Record<string, unknown>)\n put('range', api.getRangeProps() as Record<string, unknown>)\n put('peg', api.getPegProps() as Record<string, unknown>)\n\n // 收起只写 hidden 属性是不够的:作者层给 root 声明的任何一条 display\n // 都会盖过 UA 的 [hidden]{display:none},只有内联 style.display 压得住\n this.setPartHidden(this.getPart('root'), !api.visible)\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 notification 相关实现。\n\nimport type {\n NotificationApi,\n NotificationDedupe,\n NotificationItemsChangeDetails,\n NotificationOptions,\n NotificationPlacement,\n NotificationRecord,\n NotificationSchema,\n NotificationTone,\n NotificationTranslations,\n ResolvedNotification,\n ToastActionDetails,\n ToastSchema,\n ToastStatusChangeDetails,\n} from '@xihan-ui/headless'\nimport {\n connectNotification,\n connectNotificationItem,\n notificationAnatomy,\n notificationMachine,\n notificationMeta,\n toastMachine,\n} from '@xihan-ui/headless'\nimport { wcNormalize } from '../dom/normalize'\nimport { XhElement } from '../element-base'\nimport { MachineController } from '../runtime/machine-controller'\n\n// 属性缺席翻成 undefined,缺省值由机器与 connect 决定。\nconst STRING_CONVERTER = { fromAttribute: (v: string | null) => v ?? undefined }\n// 空串也当缺席:max=\"\" 经 Number() 会变成 0,那会被当成不限而不是缺省\nconst NUMBER_CONVERTER = { fromAttribute: (v: string | null) => (v == null || v === '' ? undefined : Number(v)) }\n// 三态布尔:缺席=undefined(用缺省)、在场=true、显式写 \"false\"=false。\n// 缺省为真的开关(closable)只有三态才关得掉——Lit 默认的 Boolean 转换器是 v !== null,\n// 写 closable=\"false\" 照样是真,\"这条不许关\"在 HTML 里就说不出口\nconst BOOLEAN_CONVERTER = { fromAttribute: (v: string | null) => (v === null ? undefined : v !== 'false') }\n\n/**\n * 该堆叠对应哪个位置。属性缺席时交 undefined,由 connect 回落到队列的 placement。\n * 写错时照原样交出:它与九个位置没有一个匹配,该堆叠就一直为空:\n * 明显的空白好过静默冒充另一个位置,把通知放到作者未预期的角落。\n */\nfunction groupPlacement(el: HTMLElement): NotificationPlacement | undefined {\n const raw = el.getAttribute('placement')\n return raw == null || raw === '' ? undefined : (raw as NotificationPlacement)\n}\n\n/**\n * `<xh-notification>`:Light-DOM 行为宿主:作者写 root 与若干 group 角色节点,\n * 元素运行 notification 状态机并把 connect 产出接上。每个 group 用 `placement` 属性声明所在位置,\n * 未写时落在队列的 placement 上。\n *\n * 单条通知的节点由作者按队列渲染(读取 `items` 或监听 `items-change`),元素不替作者生成:\n * 生成节点等于收走模板控制权,图标、进度条、i18n 文案都无法再加入。\n * 每条渲染为一个 `<xh-notification-item>`,它走完退场会冒泡一条 status-change,本元素据此删除记录。\n *\n * @customElement xh-notification\n * @attr {'top-start'|'top'|'top-end'|'middle-start'|'middle'|'middle-end'|'bottom-start'|'bottom'|'bottom-end'} placement - 默认落位,默认 bottom-end\n * @attr {number} max - 每个位置最多同时保留几条,超出时先移除低优先级、同级中移除最旧的;默认 5,提供 Infinity 即不限\n * @attr {'id'|'content'} dedupe - 重复的处理方式,默认 id;content 则同一内容合并为一条并计数\n * @attr {number} gap - 同一组内的间距(px),默认 16\n * @attr {number} duration - 单条未写 duration 时的默认停留毫秒\n * @attr {number} remove-delay - 单条未写 remove-delay 时的默认退场窗口毫秒\n * @attr {boolean} pause-on-page-idle - 页面切到后台时暂停计时,逐条下发\n * @fires items-change - 队列变化;detail 为 `{ items: NotificationRecord[] }`\n * @csspart root - 队列的作用域包装(display: contents,不占布局),承载 data-count / data-empty\n * @csspart group - role=region 的地标,某一个位置上的一组;可自带 placement 属性,承载 data-placement / data-count / data-empty 与间距\n */\nexport class XhNotificationElement extends XhElement {\n static override partContract = { anatomy: notificationAnatomy, meta: notificationMeta }\n\n // 描述符逐个写全,CEM 分析器读不了对象展开。\n static override properties = {\n // 队列与文案都是对象,走不了属性;只作为 property 暴露,与 Vue 侧的同名 prop 对齐。\n // items 给了即受控:元素内部的写入只发 items-change,等宿主自己写回\n items: { attribute: false },\n defaultItems: { attribute: false },\n placement: { converter: STRING_CONVERTER },\n max: { converter: NUMBER_CONVERTER },\n dedupe: { converter: STRING_CONVERTER },\n gap: { converter: NUMBER_CONVERTER },\n duration: { converter: NUMBER_CONVERTER },\n removeDelay: { converter: NUMBER_CONVERTER, attribute: 'remove-delay' },\n pauseOnPageIdle: { converter: BOOLEAN_CONVERTER, attribute: 'pause-on-page-idle' },\n translations: { attribute: false },\n }\n\n declare items?: NotificationRecord[]\n declare defaultItems?: NotificationRecord[]\n declare placement?: NotificationPlacement\n declare max?: number\n declare dedupe?: NotificationDedupe\n declare gap?: number\n declare duration?: number\n declare removeDelay?: number\n declare pauseOnPageIdle?: boolean\n declare translations?: Partial<NotificationTranslations>\n\n private readonly notify = (details: NotificationItemsChangeDetails): void => {\n this.dispatchEvent(new CustomEvent('items-change', { detail: details, bubbles: true, composed: true }))\n }\n\n // 队列机器只有条目这一份状态,无副作用:不需要 config/layer/refs,controller 只带 props。\n private readonly ctrl = new MachineController<NotificationSchema>(this, notificationMachine, () => this.machineProps())\n\n private machineProps(): Partial<NotificationSchema['props']> {\n return {\n items: this.items,\n defaultItems: this.defaultItems,\n placement: this.placement,\n max: this.max,\n dedupe: this.dedupe,\n gap: this.gap,\n duration: this.duration,\n removeDelay: this.removeDelay,\n pauseOnPageIdle: this.pauseOnPageIdle,\n translations: this.translations,\n onItemsChange: this.notify,\n }\n }\n\n /**\n * 命令式入口共用的取法。状态机在进入文档(hostConnected)后才建立:\n * 尚未进入文档就发通知是调用方的时序问题,明确报错好过把通知静默丢弃。\n */\n private commands(): NotificationApi {\n if (!this.ctrl.service)\n throw new Error('[xh] <xh-notification> 还没进文档,命令式接口此时不可用')\n return connectNotification(this.ctrl.service, wcNormalize)\n }\n\n /** 入队并返回 id;同 id 已存在则就地改写,位置不变(处理中转为已完成即使用此路径)。 */\n create(options: NotificationOptions = {}): string {\n return this.commands().create(options)\n }\n\n /**\n * 刻意不命名为 `update`:那是 Lit 自身的渲染生命周期钩子,占用它会使宿主每次重渲\n * 都进入此处(并把 changedProperties 当作 id),组件将无法工作。\n * Vue 侧没有这层基类,composable 上仍命名为 `update`。\n */\n updateItem(id: string, options: Partial<NotificationOptions>): void {\n this.commands().update(id, options)\n }\n\n dismiss(id: string): void {\n this.commands().dismiss(id)\n }\n\n dismissAll(): void {\n this.commands().dismissAll()\n }\n\n /** max 之内、按加入先后排列的可见条目,已补齐默认值,可直接展开给 `<xh-notification-item>`。 */\n get visibleNotifications(): ResolvedNotification[] {\n return this.commands().visibleNotifications\n }\n\n /** 当前有条目的位置,按九宫格固定顺序。 */\n get placements(): NotificationPlacement[] {\n return this.commands().placements\n }\n\n get count(): number {\n return this.commands().count\n }\n\n getItemsByPlacement(placement: NotificationPlacement): ResolvedNotification[] {\n return this.commands().getItemsByPlacement(placement)\n }\n\n /**\n * 单条通知退场完成后会冒泡上来:记录应从队列中删除。\n * 识别元素名而不是只识别事件名:avatar 之类的部件也派发 status-change,且完全可能位于通知内部。\n */\n private readonly onItemStatus = (event: Event): void => {\n const target = event.target as Element | null\n if (target?.tagName.toLowerCase() !== 'xh-notification-item')\n return\n const detail = (event as CustomEvent<ToastStatusChangeDetails>).detail\n if (detail?.status !== 'unmounted')\n return\n // 整页拆除时可能先停机再收到最后一条:停机后送事件在 dev 下会抛\n if (this.ctrl.service?.getStatus() !== 'Started')\n return\n this.dismiss(detail.id)\n }\n\n override connectedCallback(): void {\n super.connectedCallback()\n // 挂在自己身上而不是逐条通知上:条目是作者渲染的,元素看不见它们的出生与死亡\n this.addEventListener('status-change', this.onItemStatus)\n }\n\n override disconnectedCallback(): void {\n this.removeEventListener('status-change', this.onItemStatus)\n super.disconnectedCallback()\n }\n\n protected wire(): void {\n const api = connectNotification(this.ctrl.service, wcNormalize)\n\n const root = this.getPart('root')\n if (root)\n this.spreader.spread(root, api.getRootProps() as Record<string, unknown>)\n\n // 摞是多实例 part,逐个打:位置取作者写的 placement 属性\n for (const el of this.getParts('group'))\n this.spreader.spread(el, api.getGroupProps({ placement: groupPlacement(el) }) as Record<string, unknown>)\n }\n}\n\n// 卡片元素自带一份契约:它只出现在队列渲染出来的那一层,root 与 group 不归它。\nconst ITEM_CONTRACT = { anatomy: notificationAnatomy, meta: { component: 'notification', requiredParts: ['item'] } }\n\n/**\n * `<xh-notification-item>`:单条通知卡片:作者写 item / item-indicator / item-title /\n * item-description / item-action-trigger / item-close-trigger 角色节点,\n * 元素运行生命周期状态机并把 connect 产出接上。\n *\n * item 承载 role 与 aria-live:默认 status + polite(排队等待读屏的空隙),\n * tone=\"danger\" 换为 alert + assertive(打断当前朗读)。指针停在卡片上、\n * 或焦点落进卡片内部都会暂停倒计时,离开后继续剩余部分。\n *\n * 退场窗口结束时只把卡片收起、不删除节点:作者写在其中的内容归作者,\n * 何时把该条从队列中删除是 `<xh-notification>` 的职责(它接收本元素冒泡的 status-change)。\n *\n * @customElement xh-notification-item\n * @attr {string} id - 队列身份,`<xh-notification>` 按它寻址;未提供时使用实例自身的 scope id\n * @attr {string} title - 标题文案;作者未在 item-title 部件中写内容时由元素填入\n * @attr {string} description - 补充说明;作者未在 item-description 部件中写内容时由元素填入\n * @attr {'info'|'success'|'warning'|'danger'} tone - 语气,默认 info;danger 使用 alert + assertive\n * @attr {boolean} loading - 事情尚未完成:图标换为转圈,且不自动消失\n * @attr {number} duration - 停留毫秒,默认 5000;<=0 即关闭自动消失\n * @attr {number} remove-delay - 退场窗口毫秒,默认 200,留给退场动画\n * @attr {boolean} closable - 是否提供可用的关闭按钮,默认 true;写 closable=\"false\" 关闭\n * @attr {boolean} pause-on-page-idle - 页面切到后台时暂停计时,默认关闭\n * @attr {boolean} paused - 由宿主整组一起暂停计时,默认关闭;与指针、焦点等来源并存\n * @fires status-change - 生命周期落定;detail 为 `{ id: string, status: 'dismissing'|'unmounted' }`\n * @fires action - 操作按钮被按下;detail 为 `{ id: string }`\n * @csspart item - role=status(danger 时 alert)的卡片,承载 data-tone / data-loading / data-state / data-paused\n * @csspart item-indicator - 语气指示符;留空即由皮肤按卡片上的语气绘制兜底字形,卡片加载中则换为转圈\n * @csspart item-title - 标题,aria-labelledby 的目标\n * @csspart item-description - 补充说明,aria-describedby 的目标\n * @csspart item-action-trigger - 操作按钮:先发出 action 再进入退场\n * @csspart item-progress - 倒计时条;不自动消失时收起\n * @csspart item-close-trigger - 关闭按钮;closable=false 时为原生 disabled 并收起\n */\nexport class XhNotificationItemElement extends XhElement {\n static override partContract = ITEM_CONTRACT\n\n // 字段名与属性名分家的两处都是躲原生访问器:HTMLElement 的 id 与 title 都是原生反射属性,\n // 同名声明会盖掉它们(`el.id` 从此不再是 DOM id)。属性名保持与 Vue 侧的 prop 同名。\n // 描述符逐个写全,CEM 分析器读不了对象展开。\n static override properties = {\n itemId: { converter: STRING_CONVERTER, attribute: 'id' },\n titleText: { converter: STRING_CONVERTER, attribute: 'title' },\n description: { converter: STRING_CONVERTER },\n tone: { converter: STRING_CONVERTER },\n loading: { converter: BOOLEAN_CONVERTER },\n duration: { converter: NUMBER_CONVERTER },\n removeDelay: { converter: NUMBER_CONVERTER, attribute: 'remove-delay' },\n closable: { converter: BOOLEAN_CONVERTER },\n pauseOnPageIdle: { converter: BOOLEAN_CONVERTER, attribute: 'pause-on-page-idle' },\n paused: { converter: BOOLEAN_CONVERTER },\n // 文案是对象,走不了属性;只作为 property 暴露,与 Vue 侧的 translations prop 对齐\n translations: { attribute: false },\n }\n\n declare itemId?: string\n declare titleText?: string\n declare description?: string\n declare tone?: NotificationTone\n declare loading?: boolean\n declare duration?: number\n declare removeDelay?: number\n declare closable?: boolean\n declare pauseOnPageIdle?: boolean\n declare paused?: boolean\n declare translations?: Partial<NotificationTranslations>\n\n private readonly notifyStatus = (details: ToastStatusChangeDetails): void => {\n // 必须冒泡:外层 `<xh-notification>` 就靠这条事件知道该把记录删掉了\n this.dispatchEvent(new CustomEvent('status-change', { detail: details, bubbles: true, composed: true }))\n }\n\n private readonly notifyAction = (details: ToastActionDetails): void => {\n this.dispatchEvent(new CustomEvent('action', { detail: details, bubbles: true, composed: true }))\n }\n\n // 计时器与 visibilitychange 都由机器自己经 scope 拿,不需要 config/layer/定位引擎。\n // 跑的是 toast 那台机器,文案桶却要跟着通知走:不写 configName 的话,\n // 改这颗叉的读屏名会连所有轻提示一起改\n private readonly ctrl = new MachineController<ToastSchema>(this, toastMachine, () => this.machineProps(), { configName: 'notification' })\n\n private machineProps(): Partial<ToastSchema['props']> {\n return {\n id: this.itemId,\n title: this.titleText,\n description: this.description,\n tone: this.tone,\n loading: this.loading,\n duration: this.duration,\n removeDelay: this.removeDelay,\n closable: this.closable,\n pauseOnPageIdle: this.pauseOnPageIdle,\n paused: this.paused,\n translations: this.translations,\n onStatusChange: this.notifyStatus,\n onAction: this.notifyAction,\n }\n }\n\n /** 这个部件的文字归不归作者:头一回见到它时定案,之后不再改口。 */\n private readonly authorOwnsText = new WeakMap<HTMLElement, boolean>()\n\n /**\n * 作者没往部件里写内容时,用 props 上的文案填进去。\n *\n * 归属只判一次:判完本轮就会把文字写进去,再回读分不清是作者写的还是自己写的,\n * 从那以后 title 属性改了也再刷不动(Vue 侧是响应式渲染,会跟着改,两侧就此分叉)。\n */\n private fillText(el: HTMLElement | null, text: string | undefined): void {\n if (!el)\n return\n let authored = this.authorOwnsText.get(el)\n if (authored === undefined) {\n // 头一回见到这个节点:此刻里面的东西只可能是作者写的(本轮写入尚未发生)。\n // 元素子节点也算数——只放了个图标、文字留给 props 的标题同样是作者写过的,\n // 只看文字会把那个图标当空白冲掉\n authored = el.childElementCount > 0 || (el.textContent ?? '').trim() !== ''\n this.authorOwnsText.set(el, authored)\n }\n if (authored)\n return\n const next = text ?? ''\n // 比一次再写:写文本节点会命中宿主的变动观察器,值没变就别去惊动它\n if (el.textContent !== next)\n el.textContent = next\n }\n\n protected wire(): void {\n const api = connectNotificationItem(this.ctrl.service, wcNormalize)\n\n const put = (name: string, props: Record<string, unknown>): void => {\n const el = this.getPart(name)\n if (el)\n this.spreader.spread(el, props)\n }\n put('item', api.getItemProps() as Record<string, unknown>)\n put('item-indicator', api.getItemIndicatorProps() as Record<string, unknown>)\n put('item-title', api.getItemTitleProps() as Record<string, unknown>)\n put('item-description', api.getItemDescriptionProps() as Record<string, unknown>)\n put('item-action-trigger', api.getItemActionTriggerProps() as Record<string, unknown>)\n put('item-progress', api.getItemProgressProps() as Record<string, unknown>)\n put('item-close-trigger', api.getItemCloseTriggerProps() as Record<string, unknown>)\n\n this.fillText(this.getPart('item-title'), api.title)\n this.fillText(this.getPart('item-description'), api.description)\n\n // connect 已经置了 hidden,但作者层给 [data-part=item] 写的任何一条 display\n // 都盖得过 UA 的 [hidden]{display:none};内联 style.display 优先级更高,压得住。\n // 关闭按钮同理:不可关闭时留一个按不动的叉,比压根没有叉更让人困惑\n this.setPartHidden(this.getPart('item'), api.status === 'unmounted')\n this.setPartHidden(this.getPart('item-close-trigger'), !api.closable)\n }\n}\n","/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 toast 相关实现。\n\nimport type { ToastActionDetails, ToastSchema, ToastStatusChangeDetails, ToastTone, ToastTranslations } from '@xihan-ui/headless'\nimport { connectToast, toastAnatomy, toastMachine, toastMeta } from '@xihan-ui/headless'\nimport { wcNormalize } from '../dom/normalize'\nimport { XhElement } from '../element-base'\nimport { MachineController } from '../runtime/machine-controller'\n\n// 属性缺席翻成 undefined,缺省值由机器与 connect 决定。\nconst STRING_CONVERTER = { fromAttribute: (v: string | null) => v ?? undefined }\n// 空串也当缺席:duration=\"\" 经 Number() 会变成 0,而 0 在这里是\"关掉自动消失\"的意思\nconst NUMBER_CONVERTER = { fromAttribute: (v: string | null) => (v == null || v === '' ? undefined : Number(v)) }\n// 三态布尔:缺席=undefined(用缺省)、在场=true、显式写 \"false\"=false。\n// 缺省为真的开关(closable)只有三态才关得掉——Lit 默认的 Boolean 转换器是 v !== null,\n// 写 closable=\"false\" 照样是真,\"这条不许关\"在 HTML 里就说不出口\nconst BOOLEAN_CONVERTER = { fromAttribute: (v: string | null) => (v === null ? undefined : v !== 'false') }\n\n/**\n * `<xh-toast>`:Light-DOM 行为宿主:作者写 root / title / action-trigger / close-trigger\n * 角色节点,元素运行 toast 状态机并把 connect 产出接上。\n *\n * root 承载 role 与 aria-live:默认 status + polite(排队等待读屏的空隙),\n * tone=\"danger\" 换为 alert + assertive(打断当前朗读)。指针停在提示上、\n * 或焦点落进提示内部都会暂停倒计时,离开后继续剩余部分。\n *\n * 退场窗口结束时只把 root 收起、不删除节点:作者写在其中的内容归作者,\n * 何时把该条从队列中删除是全局服务的职责(它接收本元素冒泡的 status-change)。\n *\n * @customElement xh-toast\n * @attr {string} id - 队列身份,全局服务按它寻址;未提供时使用实例自身的 scope id\n * @attr {string} title - 标题文案;作者未在 title 部件中写内容时由元素填入\n * @attr {string} description - 简短补充说明;作者未在 description 部件中写内容时由元素填入\n * @attr {'info'|'success'|'warning'|'danger'} tone - 语气,默认 info;danger 使用 alert + assertive\n * @attr {boolean} loading - 事情尚未完成:行首换为转圈,且不自动消失\n * @attr {number} duration - 停留毫秒,默认 4000;<=0 即关闭自动消失\n * @attr {number} remove-delay - 退场窗口毫秒,默认 300,留给退场动画\n * @attr {boolean} closable - 是否提供可用的关闭按钮,默认 true;写 closable=\"false\" 关闭\n * @attr {boolean} pause-on-page-idle - 页面切到后台时暂停计时,单组件默认关闭;全局服务默认开启\n * @attr {boolean} paused - 由宿主整组一起暂停计时,默认关闭;与指针、焦点等来源并存\n * @fires status-change - 生命周期落定;detail 为 `{ id: string, status: 'dismissing'|'unmounted' }`\n * @fires action - 操作按钮被按下;detail 为 `{ id: string }`\n * @csspart root - role=status(danger 时 alert)的容器,承载 data-tone / data-loading / data-state / data-paused\n * @csspart indicator - 语气指示符(对读屏隐藏),同样承载 data-loading;不渲染它时字形由 root 的伪元素兜底\n * @csspart content - 标题与说明的文本列\n * @csspart title - 标题,aria-labelledby 的目标\n * @csspart description - 可选的简短补充说明\n * @csspart action-trigger - 操作按钮:先发出 action 再进入退场\n * @csspart progress - 倒计时条;不自动消失时收起\n * @csspart close-trigger - 关闭按钮;closable=false 时为原生 disabled 并收起\n */\nexport class XhToastElement extends XhElement {\n static override partContract = { anatomy: toastAnatomy, meta: toastMeta }\n\n // 字段名与属性名分家的两处都是躲原生访问器:HTMLElement 的 id 与 title 都是原生反射属性,\n // 同名声明会盖掉它们(`el.id` 从此不再是 DOM id)。属性名保持与 Vue 侧的 prop 同名。\n // 描述符逐个写全,CEM 分析器读不了对象展开。\n static override properties = {\n toastId: { converter: STRING_CONVERTER, attribute: 'id' },\n titleText: { converter: STRING_CONVERTER, attribute: 'title' },\n descriptionText: { converter: STRING_CONVERTER, attribute: 'description' },\n tone: { converter: STRING_CONVERTER },\n loading: { converter: BOOLEAN_CONVERTER },\n duration: { converter: NUMBER_CONVERTER },\n removeDelay: { converter: NUMBER_CONVERTER, attribute: 'remove-delay' },\n closable: { converter: BOOLEAN_CONVERTER },\n pauseOnPageIdle: { converter: BOOLEAN_CONVERTER, attribute: 'pause-on-page-idle' },\n paused: { converter: BOOLEAN_CONVERTER },\n // 文案是对象,走不了属性;只作为 property 暴露,与 Vue 侧的 translations prop 对齐\n translations: { attribute: false },\n }\n\n declare toastId?: string\n declare titleText?: string\n declare descriptionText?: string\n declare tone?: ToastTone\n declare loading?: boolean\n declare duration?: number\n declare removeDelay?: number\n declare closable?: boolean\n declare pauseOnPageIdle?: boolean\n declare paused?: boolean\n declare translations?: Partial<ToastTranslations>\n\n private readonly notifyStatus = (details: ToastStatusChangeDetails): void => {\n // 必须冒泡:外层的队列宿主就靠这条事件知道该把记录删掉了\n this.dispatchEvent(new CustomEvent('status-change', { detail: details, bubbles: true, composed: true }))\n }\n\n private readonly notifyAction = (details: ToastActionDetails): void => {\n this.dispatchEvent(new CustomEvent('action', { detail: details, bubbles: true, composed: true }))\n }\n\n // toast 机器的副作用只有计时器与 visibilitychange,都由机器自己经 scope 拿,\n // 不需要 config/layer/定位引擎,故 controller 只带 props。\n private readonly ctrl = new MachineController<ToastSchema>(this, toastMachine, () => this.machineProps())\n\n private machineProps(): Partial<ToastSchema['props']> {\n return {\n id: this.toastId,\n title: this.titleText,\n description: this.descriptionText,\n tone: this.tone,\n loading: this.loading,\n duration: this.duration,\n removeDelay: this.removeDelay,\n closable: this.closable,\n pauseOnPageIdle: this.pauseOnPageIdle,\n paused: this.paused,\n translations: this.translations,\n onStatusChange: this.notifyStatus,\n onAction: this.notifyAction,\n }\n }\n\n /** 这个部件的文字归不归作者:头一回见到它时定案,之后不再改口。 */\n private readonly authorOwnsText = new WeakMap<HTMLElement, boolean>()\n\n /**\n * 作者没往部件里写内容时,用 props 上的文案填进去。\n *\n * 归属只判一次:判完本轮就会把文字写进去,再回读分不清是作者写的还是自己写的,\n * 从那以后 title 属性改了也再刷不动(Vue 侧是响应式渲染,会跟着改,两侧就此分叉)。\n */\n private fillText(el: HTMLElement | null, text: string | undefined): void {\n if (!el)\n return\n let authored = this.authorOwnsText.get(el)\n if (authored === undefined) {\n // 头一回见到这个节点:此刻里面的东西只可能是作者写的(本轮写入尚未发生)。\n // 元素子节点也算数——只放了个图标、文字留给 props 的标题同样是作者写过的,\n // 只看文字会把那个图标当空白冲掉\n authored = el.childElementCount > 0 || (el.textContent ?? '').trim() !== ''\n this.authorOwnsText.set(el, authored)\n }\n if (authored)\n return\n const next = text ?? ''\n // 比一次再写:写文本节点会命中宿主的变动观察器,值没变就别去惊动它\n if (el.textContent !== next)\n el.textContent = next\n }\n\n protected wire(): void {\n const api = connectToast(this.ctrl.service, wcNormalize)\n\n const put = (name: string, props: Record<string, unknown>): void => {\n const el = this.getPart(name)\n if (el)\n this.spreader.spread(el, props)\n }\n put('root', api.getRootProps() as Record<string, unknown>)\n put('indicator', api.getIndicatorProps() as Record<string, unknown>)\n put('content', api.getContentProps() as Record<string, unknown>)\n put('title', api.getTitleProps() as Record<string, unknown>)\n put('description', api.getDescriptionProps() as Record<string, unknown>)\n put('action-trigger', api.getActionTriggerProps() as Record<string, unknown>)\n put('progress', api.getProgressProps() as Record<string, unknown>)\n put('close-trigger', api.getCloseTriggerProps() as Record<string, unknown>)\n\n this.fillText(this.getPart('title'), api.title)\n this.fillText(this.getPart('description'), api.description)\n\n // connect 已经置了 hidden,但作者层给 [data-part=root] 写的任何一条 display\n // 都盖得过 UA 的 [hidden]{display:none};内联 style.display 优先级更高,压得住。\n // 关闭按钮同理:不可关闭时留一个按不动的叉,比压根没有叉更让人困惑\n this.setPartHidden(this.getPart('root'), api.status === 'unmounted')\n this.setPartHidden(this.getPart('close-trigger'), !api.closable)\n }\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ interface ComplexAttributeConverter<Type = unknown> {
6
6
  /** 转换器可写成对象,也可直接写成 fromAttribute 函数。 */
7
7
  type AttributeConverter<Type = unknown> = ComplexAttributeConverter<Type> | ((value: string | null, type?: unknown) => Type);
8
8
  interface PropertyDeclaration<Type = unknown> {
9
- /** false=不观察属性;字符串=指定属性名;缺省=字段名转小写(不转短横线)。 */
9
+ /** false=不观察属性;字符串=指定属性名;默认=字段名转小写(不转短横线)。 */
10
10
  readonly attribute?: boolean | string;
11
11
  /** 没配 converter 时据此选内建转换:Boolean / Number / Object / Array,其余原样取字符串。 */
12
12
  readonly type?: unknown;
@@ -43,4 +43,4 @@ interface ReactiveControllerHost {
43
43
  }
44
44
  //#endregion
45
45
  export { ReactiveControllerHost as a, ReactiveController as i, PropertyDeclarations as n, PropertyValues as r, PropertyDeclaration as t };
46
- //# sourceMappingURL=types-BvWWqMd_.d.ts.map
46
+ //# sourceMappingURL=types-C1Bybm6P.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-BvWWqMd_.d.ts","names":[],"sources":["../src/reactive/types.ts"],"mappings":";;UAGiB,0BAA0B;EACzC,iBAAiB,sBAAsB,mBAAmB;;;KAIhD,mBAAmB,kBACzB,0BAA0B,UACxB,sBAAsB,mBAAmB;UAEhC,oBAAoB;;WAE1B;;WAEA;;WAEA,YAAY,mBAAmB;;WAE/B;;WAEA;;WAEA;;WAEA;;;UAIM;YACL,eAAe;;;KAIf,iBAAiB,IAAI;;UAGhB;EACf;EACA;EACA;EACA;;;UAIe;EACf,gBAAgB,YAAY;EAC5B,mBAAmB,YAAY;EAC/B;WACS,gBAAgB"}
1
+ {"version":3,"file":"types-C1Bybm6P.d.ts","names":[],"sources":["../src/reactive/types.ts"],"mappings":";;UAQiB,0BAA0B;EACzC,iBAAiB,sBAAsB,mBAAmB;;;KAIhD,mBAAmB,kBACzB,0BAA0B,UACxB,sBAAsB,mBAAmB;UAEhC,oBAAoB;;WAE1B;;WAEA;;WAEA,YAAY,mBAAmB;;WAE/B;;WAEA;;WAEA;;WAEA;;;UAIM;YACL,eAAe;;;KAIf,iBAAiB,IAAI;;UAGhB;EACf;EACA;EACA;EACA;;;UAIe;EACf,gBAAgB,YAAY;EAC5B,mBAAmB,YAAY;EAC/B;WACS,gBAAgB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xihan-ui/web-components",
3
3
  "type": "module",
4
- "version": "1.1.0",
4
+ "version": "2.0.0",
5
5
  "description": "XiHan.UI Web Components adapter — Light-DOM behavior hosts on XhReactiveElement.",
6
6
  "author": {
7
7
  "name": "XiHanFun",
@@ -37,6 +37,10 @@
37
37
  "types": "./dist/define.d.ts",
38
38
  "import": "./dist/define.js"
39
39
  },
40
+ "./services": {
41
+ "types": "./dist/services.d.ts",
42
+ "import": "./dist/services.js"
43
+ },
40
44
  "./custom-elements.json": "./custom-elements.json"
41
45
  },
42
46
  "main": "./dist/index.js",
@@ -56,42 +60,44 @@
56
60
  },
57
61
  "customElements": "custom-elements.json",
58
62
  "peerDependencies": {
59
- "@xihan-ui/backgrounds": "^1.1.0"
63
+ "@xihan-ui/backgrounds": "^2.0.0",
64
+ "@xihan-ui/code-highlight": "^2.0.0"
60
65
  },
61
66
  "peerDependenciesMeta": {
62
67
  "@xihan-ui/backgrounds": {
63
68
  "optional": true
69
+ },
70
+ "@xihan-ui/code-highlight": {
71
+ "optional": true
64
72
  }
65
73
  },
66
74
  "dependencies": {
67
- "@xihan-ui/behavior": "^1.1.0",
68
- "@xihan-ui/code-highlight": "^1.1.0",
69
- "@xihan-ui/headless": "^1.1.0",
70
- "@xihan-ui/kernel": "^1.1.0",
71
- "@xihan-ui/machine": "^1.1.0",
72
- "@xihan-ui/motion": "^1.1.0",
73
- "@xihan-ui/pointer": "^1.1.0",
74
- "@xihan-ui/position": "^1.1.0"
75
+ "@xihan-ui/core": "^2.0.0",
76
+ "@xihan-ui/headless": "^2.0.0",
77
+ "@xihan-ui/motion": "^2.0.0",
78
+ "@xihan-ui/pointer": "^2.0.0",
79
+ "@xihan-ui/position": "^2.0.0"
75
80
  },
76
81
  "devDependencies": {
77
82
  "@custom-elements-manifest/analyzer": "^0.11.0",
78
83
  "@lit/reactive-element": "2.1.2",
79
- "@vitest/browser": "^4.1.10",
80
- "@vitest/browser-playwright": "^4.1.10",
84
+ "@vitest/browser": "^4.1.11",
85
+ "@vitest/browser-playwright": "^4.1.11",
81
86
  "jsdom": "^27.0.0",
82
87
  "playwright": "^1.62.0",
83
- "vitest": "^4.1.10",
84
- "@xihan-ui/backgrounds": "1.1.0",
88
+ "vitest": "^4.1.11",
89
+ "@xihan-ui/backgrounds": "2.0.0",
85
90
  "@xihan-ui/build": "0.0.0",
86
- "@xihan-ui/styles": "1.1.0",
91
+ "@xihan-ui/code-highlight": "2.0.0",
92
+ "@xihan-ui/styles": "2.0.0",
87
93
  "@xihan-ui/testing": "0.0.0",
88
- "@xihan-ui/tokens": "1.1.0",
94
+ "@xihan-ui/tokens": "2.0.0",
89
95
  "@xihan-ui/tsconfig": "0.0.0"
90
96
  },
91
97
  "scripts": {
92
98
  "build": "tsdown",
93
99
  "cem": "cem analyze && node scripts/enrich-cem.mjs",
94
- "typecheck": "tsc --noEmit -p tsconfig.json",
100
+ "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.test.json",
95
101
  "test": "vitest run",
96
102
  "test:browser": "vitest run --config vitest.browser.config.ts",
97
103
  "test:demos": "vitest run --config vitest.demos.config.ts --reporter verbose"
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-Cz16-P4i.d.ts","names":[],"sources":["../src/dom/spread.ts","../src/config.ts"],"mappings":";;UA2BiB;EACf,SAAS,MAAM,aAAa,OAAO;EACnC,UAAU,MAAM;;iBASF,kBAAkB;;;;KCzBtB,WAAW;;iBAWP,YAAY,MAAM;iBAYlB,eAAe,SAAS;;iBAKxB,iBAAiB;;;;;;;iBAWjB,gBAAc,MAAM,sBAAsB,MAAM,uBAAuB;;UAKtE,sBAAsB;WAC5B,UAAU;;;;;;;;iBAaL,gBAAgB,MAAM,6BAA6B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"element-b0p0Q8Py.js","names":[],"sources":["../package.json","../src/reactive/element.ts"],"sourcesContent":["","import type {\n AttributeConverter,\n PropertyDeclaration,\n PropertyDeclarations,\n PropertyValues,\n ReactiveController,\n ReactiveControllerHost,\n} from './types'\n\n// 定稿过的类,键是构造器本身;子类各登记一次。\nconst finalizedClasses = new WeakSet<object>()\n// 每个类的:属性名 → 字段名。\nconst attributeMaps = new WeakMap<object, Map<string, string>>()\n// 每个原型上由 createProperty 装过访问器的字段名。\nconst installedAccessors = new WeakMap<object, Set<string>>()\n// 声明里实现了的键,其余一律抛。\nconst SUPPORTED_DECLARATION_KEYS = new Set(['attribute', 'converter', 'type'])\n\n/** 按声明的 type 解读属性字符串。 */\nfunction defaultFromAttribute(value: string | null, type?: unknown): unknown {\n switch (type) {\n case Boolean:\n return value !== null\n case Number:\n return value === null ? null : Number(value)\n case Object:\n case Array:\n try {\n return JSON.parse(value!) as unknown\n }\n catch {\n return null\n }\n default:\n return value\n }\n}\n\nfunction fromAttributeOf(options: PropertyDeclaration): (value: string | null, type?: unknown) => unknown {\n const converter = options.converter as AttributeConverter | undefined\n if (typeof converter === 'function')\n return converter\n return converter?.fromAttribute ?? defaultFromAttribute\n}\n\n/** 判等:Object.is 同值不排更新(NaN 与 NaN 同值,+0 与 -0 不同值)。声明里不接受自定义 hasChanged。 */\nfunction valueChanged(value: unknown, old: unknown): boolean {\n return !Object.is(value, old)\n}\n\n/** 让本类持有自己的 elementProperties。未定稿时顺原型链读到的是父类那一个 Map 实例,直接写会污染父类并泄漏给兄弟子类。 */\nfunction prepareOwnProperties(ctor: typeof XhReactiveElement): void {\n if (Object.hasOwn(ctor, 'elementProperties'))\n return\n const superCtor = Object.getPrototypeOf(ctor) as typeof XhReactiveElement\n ctor.elementProperties = new Map(superCtor.elementProperties)\n}\n\n/** 声明键只认 attribute / converter / type,其余当场抛(Lit 的那几个键在这里不生效,不能静默吞)。 */\nfunction assertSupportedDeclaration(ctor: typeof XhReactiveElement, name: string, options: PropertyDeclaration): void {\n for (const key of Reflect.ownKeys(options)) {\n if (typeof key === 'string' && SUPPORTED_DECLARATION_KEYS.has(key))\n continue\n throw new TypeError(\n `${ctor.name}.properties.${name}: 不支持的声明键 ${String(key)}。`\n + `本运行时只实现 attribute / converter / type:不回写属性(无 reflect)、判等固定 Object.is(无 hasChanged)、声明必装访问器(无 noAccessor / state)。`,\n )\n }\n}\n\n/** 原型上已有同名成员就抛:装访问器会把它整块盖掉,此后作者写的 get/set 或方法永不被调用。 */\nfunction assertPrototypeFree(ctor: typeof XhReactiveElement, name: string): void {\n if (installedAccessors.get(ctor.prototype)?.has(name))\n return\n const existing = Object.getOwnPropertyDescriptor(ctor.prototype, name)\n if (existing === undefined)\n return\n const kind = existing.get !== undefined || existing.set !== undefined ? 'get/set 访问器' : '成员'\n throw new TypeError(\n `${ctor.name}.prototype.${name} 已有 ${kind},响应式属性会把它整块盖掉。`\n + `本运行时不做 Lit 那样的包装:请给字段改名,或删掉 ${ctor.name}.properties.${name} 这条声明。`,\n )\n}\n\n/** 该字段观察哪个属性;undefined 表示不观察。 */\nfunction attributeNameFor(name: string, options: PropertyDeclaration): string | undefined {\n const { attribute } = options\n if (attribute === false)\n return undefined\n return typeof attribute === 'string' ? attribute : name.toLowerCase()\n}\n\n/**\n * 无 DOM 时的基座替身。类定义式在模块求值那一刻就会取 HTMLElement,\n * 而任何 meta-framework 都会在 Node 里把入口模块求值一次。\n * 元素在没有 customElements 的环境里本就不会被注册,替身只需让定义式成立。\n */\nconst HostBase: typeof HTMLElement\n = typeof HTMLElement === 'undefined'\n ? (class {} as unknown as typeof HTMLElement)\n : HTMLElement\n\n/**\n * 响应式自定义元素基类:属性 → 字段的单向转换、批量异步更新、控制器生命周期。\n * 不做 shadow DOM、不做样式、不做模板渲染、不回写属性。\n */\nexport class XhReactiveElement extends HostBase implements ReactiveControllerHost {\n /** 子类以 `static properties = { 字段名: 选项 }` 声明响应式属性。 */\n static properties: PropertyDeclarations = {}\n\n /** 定稿后的全部声明,含从父类继承来的。 */\n static elementProperties: Map<string, PropertyDeclaration> = new Map()\n\n /** 浏览器在 customElements.define() 时读它,属性声明就在这一刻定稿。本基类自身返回 [](Lit 那边是 undefined)。 */\n static get observedAttributes(): string[] {\n this.finalize()\n const attrs = attributeMaps.get(this)\n return attrs === undefined ? [] : [...attrs.keys()]\n }\n\n /** 合并父类声明并逐条建访问器。递归到本基类为止(它已预先登记为定稿);中途抛错时不登记,下次读还抛同一条。 */\n protected static finalize(): void {\n if (finalizedClasses.has(this))\n return\n const superCtor = Object.getPrototypeOf(this) as typeof XhReactiveElement\n superCtor.finalize()\n prepareOwnProperties(this)\n if (Object.hasOwn(this, 'properties')) {\n const declarations = this.properties\n const symbols = Object.getOwnPropertySymbols(declarations)\n if (symbols.length > 0) {\n throw new TypeError(\n `${this.name}.properties 含 symbol 键 ${String(symbols[0])}:只支持字符串键(symbol 键映射不出属性名)。`,\n )\n }\n for (const name of Object.getOwnPropertyNames(declarations))\n this.createProperty(name, declarations[name] ?? {})\n }\n // 声明全部并完再算属性映射:子类给同名字段改了属性名时,基类那个旧属性名要随之作废。\n const attributes = new Map<string, string>()\n for (const [name, options] of this.elementProperties) {\n const attribute = attributeNameFor(name, options)\n if (attribute !== undefined)\n attributes.set(attribute, name)\n }\n attributeMaps.set(this, attributes)\n finalizedClasses.add(this)\n }\n\n /** 登记一条声明,并在原型上装一个\"写入即排更新\"的访问器。 */\n protected static createProperty(name: string, options: PropertyDeclaration): void {\n prepareOwnProperties(this)\n assertSupportedDeclaration(this, name, options)\n assertPrototypeFree(this, name)\n this.elementProperties.set(name, options)\n const key = Symbol(name)\n Object.defineProperty(this.prototype, name, {\n configurable: true,\n enumerable: true,\n get(this: Record<symbol, unknown>): unknown {\n return this[key]\n },\n set(this: Record<symbol, unknown> & XhReactiveElement, value: unknown) {\n const old = this[key]\n this[key] = value\n this.requestUpdate(name, old)\n },\n })\n const installed = installedAccessors.get(this.prototype) ?? new Set<string>()\n installed.add(name)\n installedAccessors.set(this.prototype, installed)\n }\n\n /** createRenderRoot() 的产物。 */\n renderRoot!: HTMLElement | DocumentFragment\n\n private readonly controllers = new Set<ReactiveController>()\n private changedProperties: PropertyValues = new Map()\n private pendingUpdate = false\n private hasUpdated = false\n /** 升级前就写在实例上的字段值,首轮更新时补写回去。 */\n private instanceProperties: Map<string, unknown> | undefined\n private updatePromise!: Promise<boolean>\n private startUpdating!: (value: boolean) => void\n\n constructor() {\n super()\n // 首轮更新等这个闸口,connectedCallback 才放行。\n this.updatePromise = new Promise<boolean>((resolve) => {\n this.startUpdating = resolve\n })\n this.saveInstanceProperties()\n this.requestUpdate()\n }\n\n /** 元素还没 upgrade 时被赋的字段值会盖住原型访问器,先摘下来存着。 */\n private saveInstanceProperties(): void {\n const self = this as unknown as Record<string, unknown>\n for (const name of (this.constructor as typeof XhReactiveElement).elementProperties.keys()) {\n if (!Object.hasOwn(this, name))\n continue\n this.instanceProperties ??= new Map()\n this.instanceProperties.set(name, self[name])\n delete self[name]\n }\n }\n\n /** 渲染根,默认就是元素自己(Light DOM)。 */\n protected createRenderRoot(): HTMLElement | DocumentFragment {\n return this\n }\n\n addController(controller: ReactiveController): void {\n this.controllers.add(controller)\n // 已经连上了就当场补一次 hostConnected(控制器常在字段初始化里注册,那时 connected 已过)。\n if (this.renderRoot !== undefined && this.isConnected)\n controller.hostConnected?.()\n }\n\n removeController(controller: ReactiveController): void {\n this.controllers.delete(controller)\n }\n\n connectedCallback(): void {\n this.renderRoot ??= this.createRenderRoot()\n this.startUpdating(true)\n for (const controller of this.controllers) controller.hostConnected?.()\n }\n\n disconnectedCallback(): void {\n for (const controller of this.controllers) controller.hostDisconnected?.()\n }\n\n /** 属性变化转成字段值;单向,不回写属性。 */\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n const ctor = this.constructor as typeof XhReactiveElement\n const property = attributeMaps.get(ctor)?.get(name)\n if (property === undefined)\n return\n const options = ctor.elementProperties.get(property) ?? {}\n const self = this as unknown as Record<string, unknown>\n self[property] = fromAttributeOf(options)(value, options.type)\n }\n\n /**\n * 排一轮更新。带 name 时先按判等过滤,同值直接返回。\n * 一拍内调多次只排一轮。\n */\n requestUpdate(name?: PropertyKey, oldValue?: unknown): void {\n if (name !== undefined) {\n const value = (this as unknown as Record<PropertyKey, unknown>)[name]\n if (!valueChanged(value, oldValue))\n return\n // 首轮更新跑完之前,changedProperties 里的旧值一律记 undefined。\n if (!this.changedProperties.has(name))\n this.changedProperties.set(name, this.hasUpdated ? oldValue : undefined)\n }\n if (!this.pendingUpdate)\n this.updatePromise = this.enqueueUpdate()\n }\n\n /**\n * 本轮更新落定后 resolve;值为 false 表示更新过程中又排了新一轮(要等的是新的 updateComplete)。\n * 元素连上之前永不 resolve。\n */\n get updateComplete(): Promise<boolean> {\n return this.updatePromise\n }\n\n private async enqueueUpdate(): Promise<boolean> {\n this.pendingUpdate = true\n try {\n await this.updatePromise\n }\n catch (error) {\n // 上一轮的失败不拖住这一轮,但也不吞掉,抛成未处理拒绝。\n void Promise.reject(error)\n }\n this.performUpdate()\n return !this.pendingUpdate\n }\n\n private performUpdate(): void {\n if (!this.pendingUpdate)\n return\n if (!this.hasUpdated && this.instanceProperties) {\n const self = this as unknown as Record<string, unknown>\n for (const [name, value] of this.instanceProperties) self[name] = value\n this.instanceProperties = undefined\n }\n const changed = this.changedProperties\n try {\n for (const controller of this.controllers) controller.hostUpdate?.()\n this.update(changed)\n }\n catch (error) {\n this.markUpdated()\n throw error\n }\n for (const controller of this.controllers) controller.hostUpdated?.()\n if (!this.hasUpdated) {\n this.hasUpdated = true\n this.firstUpdated(changed)\n }\n this.updated(changed)\n }\n\n private markUpdated(): void {\n this.changedProperties = new Map()\n this.pendingUpdate = false\n }\n\n /** 更新主体。子类覆盖时必须调 super.update(),否则这轮永远结不掉。 */\n protected update(_changed: PropertyValues): void {\n this.markUpdated()\n }\n\n /** 首轮更新后调一次。 */\n protected firstUpdated(_changed: PropertyValues): void {}\n\n /** 每轮更新后调。 */\n protected updated(_changed: PropertyValues): void {}\n}\n\n// 递归定稿的终点:本基类自己没有属性声明。\nfinalizedClasses.add(XhReactiveElement)\nattributeMaps.set(XhReactiveElement, new Map())\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"machine-controller-DE6edQbK.js","names":["mergeXhConfig","mergeBase"],"sources":["../src/config.ts","../src/dom/normalize.ts","../src/dom/parts.ts","../src/dom/spread.ts","../src/runtime/lit-runtime.ts","../src/runtime/machine-controller.ts"],"sourcesContent":["// 全局配置:locale、尺寸档与各组件内建文案的应用级默认值。\n// 取值优先级:元素上的 property > 最近一个 <xh-config> > 外层 <xh-config> > setXhConfig 的全局值 > 组件内建默认。\n//\n// 自定义元素拿不到 Vue 的 provide/inject,文案又是对象、只能走 property 不能走 attribute。\n// 这里给两条出口:setXhConfig 管整页,<xh-config> 管一棵子树,语义与 Vue 适配器的\n// provideXhConfig 对齐(那边是组件树,这边是 DOM 树)。\nimport type { XhConfigBase, XhTranslationOverrides } from '@xihan-ui/headless'\nimport { mergeXhConfig as mergeBase, withXhConfigBase } from '@xihan-ui/headless'\nimport { setMotionOverride } from '@xihan-ui/motion'\n\nexport type { XhTranslationOverrides }\n\n/** 与 Vue 适配器同一份字段;WC 是 Light DOM,浮层不搬运,没有 portalContainer。 */\nexport type XhConfig = XhConfigBase\n\nlet current: XhConfig = {}\nconst listeners = new Set<() => void>()\n\n/** 配置变了就叫一遍:全局那份改了、任一 <xh-config> 改了或进出文档,都走这里。 */\nexport function notifyXhConfigChange(): void {\n for (const listener of [...listeners]) listener()\n}\n\n/** 覆写全局配置。整份替换,不做深合并——想改一处就把整份拿去改。 */\nexport function setXhConfig(next: XhConfig): void {\n current = next\n applyMotionOverride(next)\n notifyXhConfigChange()\n}\n\n/** 配置里写了 motion 才调 setMotionOverride;缺席不碰——别的地方设的 override 不在这里清。 */\nexport function applyMotionOverride(config: XhConfig): void {\n if (config.motion !== undefined)\n setMotionOverride(config.motion)\n}\n\nexport function getXhConfig(): Readonly<XhConfig> {\n return current\n}\n\n/** 订阅配置变更,返回退订函数。已挂载的元素靠它在切语言时重渲。 */\nexport function onXhConfigChange(listener: () => void): () => void {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n}\n\n/**\n * 外层与内层逐键合并。\n *\n * 键缺席与写成 undefined 都算「这一层没说」,一律回落外层——子树里只想改文案时,\n * 不该把外层的 locale 一并抹掉。\n */\nexport function mergeXhConfig(base: XhConfig | undefined, over: XhConfig | undefined): XhConfig {\n return mergeBase(base, over)\n}\n\n/** `<xh-config>` 认领这个接口,配置解析沿 DOM 祖先链找它,不必反向依赖元素类。 */\nexport interface XhConfigScope extends Element {\n readonly xhConfig: XhConfig\n}\n\nfunction isConfigScope(node: Element): node is XhConfigScope {\n return 'xhConfig' in node\n}\n\n/**\n * 某个节点看到的配置:从全局那份起,沿祖先链自外向内逐层并进来。\n *\n * 不传节点(或它还没进文档)就只有全局那份。跨 shadow root 不追:\n * 本适配器是 Light DOM,作者的 <xh-config> 与元素天然同树。\n */\nexport function resolveXhConfig(node: Element | null | undefined): XhConfig {\n if (!node)\n return current\n const chain: XhConfigScope[] = []\n for (let el: Element | null = node; el; el = el.parentElement) {\n if (isConfigScope(el))\n chain.push(el)\n }\n // 祖先链是自内向外收的,合并要自外向内\n let out = current\n for (let i = chain.length - 1; i >= 0; i--)\n out = mergeXhConfig(out, chain[i]!.xhConfig)\n return out\n}\n\n/**\n * 把配置并进一份 props:`translations` 逐键合并、元素上的压过全局;\n * `locale` 与 `size` 在元素上没给(键在但值是 undefined)时取配置里的。\n * 一处都没并到就原样返回,不新建对象。\n *\n * host 是发起解析的元素,给了就沿它的祖先链找 `<xh-config>`;不给只看全局那份。\n */\nexport function withXhConfig<T extends object>(component: string, props: T, host?: Element | null): T {\n return withXhConfigBase(component, props, host === undefined ? current : resolveXhConfig(host))\n}\n","import { createNormalizer } from '@xihan-ui/kernel'\n\n// connect 产出的键已是 DOM 向,恒等透传,落到真实 DOM 由 spread 完成。\nexport const wcNormalize = createNormalizer(props => props)\n","/** 角色节点标记属性。 */\nexport const PART_ATTR = 'data-xh-part'\n\n/** 元素自身是角色节点,或其子树里有角色节点。 */\nexport function containsPart(el: Element): boolean {\n return el.hasAttribute(PART_ATTR) || el.querySelector(`[${PART_ATTR}]`) != null\n}\n\n// 从宿主向下遍历收集带 data-xh-part 的节点,跳过嵌套 xh-* 子树。\nexport function discoverParts(host: HTMLElement): Map<string, HTMLElement[]> {\n const out = new Map<string, HTMLElement[]>()\n\n function walk(node: Element): void {\n for (const child of Array.from(node.children)) {\n if (child.tagName.toLowerCase().startsWith('xh-'))\n continue\n const el = child as HTMLElement\n const part = el.dataset.xhPart\n if (part) {\n const arr = out.get(part)\n if (arr)\n arr.push(el)\n else\n out.set(part, [el])\n }\n walk(el)\n }\n }\n\n walk(host)\n return out\n}\n","// 把 connect 产出的 prop 字典打到 Light-DOM 角色节点上;事件每帧移旧加新,不碰 class。\n\nconst BOOLEAN_ATTRS = new Set(['disabled', 'hidden', 'inert', 'readonly', 'required', 'checked', 'selected', 'open', 'multiple'])\nconst PROP_KEYS = new Set(['value', 'checked', 'selected'])\n\ninterface NodeState {\n listeners: Map<string, EventListener>\n attrs: Set<string>\n}\n\nfunction eventName(key: string): string | null {\n if (key.length > 2 && key.startsWith('on') && key[2]! >= 'A' && key[2]! <= 'Z')\n return key.slice(2).toLowerCase()\n return null\n}\n\n// 值相同则不写,避免多余的属性变更记录。\nfunction setAttr(node: HTMLElement, key: string, value: string): void {\n if (node.getAttribute(key) !== value)\n node.setAttribute(key, value)\n}\n\nfunction removeAttr(node: HTMLElement, key: string): void {\n if (node.hasAttribute(key))\n node.removeAttribute(key)\n}\n\nexport interface Spreader {\n spread: (node: HTMLElement, props: Record<string, unknown>) => void\n release: (node: HTMLElement) => void\n}\n\n/**\n * 一个角色节点当前归哪台 spreader 管,最后写它的那台就是。\n * 只有仍持有归属的那台交还时才撤属性:两台同类宿主写的属性完全同名,接管后原宿主再撤会把接管方的一起删掉。\n */\nconst owners = new WeakMap<Element, symbol>()\n\nexport function createSpreader(): Spreader {\n const owner = Symbol('spreader')\n const state = new WeakMap<Element, NodeState>()\n\n function spread(node: HTMLElement, props: Record<string, unknown>): void {\n owners.set(node, owner)\n let s = state.get(node)\n if (!s) {\n s = { listeners: new Map(), attrs: new Set() }\n state.set(node, s)\n }\n const nextAttrs = new Set<string>()\n const nextEvents = new Set<string>()\n\n for (const [key, value] of Object.entries(props)) {\n const ev = eventName(key)\n if (ev) {\n nextEvents.add(ev)\n const prev = s.listeners.get(ev)\n if (prev)\n node.removeEventListener(ev, prev)\n if (typeof value === 'function') {\n node.addEventListener(ev, value as EventListener)\n s.listeners.set(ev, value as EventListener)\n }\n else {\n s.listeners.delete(ev)\n }\n continue\n }\n // style 传对象时逐条写内联样式;自定义属性(--开头)走 setProperty,Object.assign 写不进去\n if (key === 'style' && value !== null && typeof value === 'object') {\n for (const [styleKey, styleValue] of Object.entries(value as Record<string, string | undefined>)) {\n if (styleKey.startsWith('--')) {\n if (styleValue == null || styleValue === '')\n node.style.removeProperty(styleKey)\n else\n node.style.setProperty(styleKey, String(styleValue))\n }\n else {\n (node.style as unknown as Record<string, unknown>)[styleKey] = styleValue\n }\n }\n continue\n }\n if (value === undefined || value === null || value === false) {\n removeAttr(node, key)\n continue\n }\n nextAttrs.add(key)\n if (PROP_KEYS.has(key)) {\n (node as unknown as Record<string, unknown>)[key] = value\n continue\n }\n if (BOOLEAN_ATTRS.has(key)) {\n node.toggleAttribute(key, Boolean(value))\n continue\n }\n setAttr(node, key, String(value))\n }\n\n // 移除上一帧写过、这一帧不再写的属性与事件监听器。\n for (const key of s.attrs) {\n if (!nextAttrs.has(key))\n removeAttr(node, key)\n }\n for (const [ev, fn] of [...s.listeners]) {\n if (!nextEvents.has(ev)) {\n node.removeEventListener(ev, fn)\n s.listeners.delete(ev)\n }\n }\n s.attrs = nextAttrs\n }\n\n function release(node: HTMLElement): void {\n const s = state.get(node)\n if (!s)\n return\n for (const [ev, fn] of s.listeners) node.removeEventListener(ev, fn)\n // 节点已被另一台宿主接管时只摘监听器,属性归接管方\n if (owners.get(node) === owner) {\n for (const key of s.attrs) node.removeAttribute(key)\n owners.delete(node)\n }\n state.delete(node)\n }\n\n return { spread, release }\n}\n","import type { Bindable, CellParams, Dep, ReactiveRuntime } from '@xihan-ui/machine'\nimport type { ReactiveControllerHost } from '../reactive'\n\n// 把机器的 ReactiveRuntime 契约桥到自定义元素基类的 controller 生命周期。\n\nexport interface LitRuntime extends ReactiveRuntime {\n /** hostConnected 调用,跑排队的 onMount。 */\n mount: () => void\n /** hostDisconnected 调用,逆序跑一次 cleanup。 */\n unmount: () => void\n /** hostUpdate 调用,逐 tracker 比对依赖、变则触发。 */\n runTrackers: () => void\n}\n\ninterface Tracker {\n deps: Dep[]\n fn: () => void\n last: unknown[]\n}\n\n/** flush 最多等这么多轮更新;宿主一直自排新一轮时到此为止,回调照跑不吊死。 */\nconst MAX_FLUSH_ROUNDS = 100\n\nexport function createLitRuntime(host: ReactiveControllerHost): LitRuntime {\n const mounts: Array<() => void> = []\n const cleanups: Array<() => void> = []\n const trackers: Tracker[] = []\n let mounted = false\n\n function cell<V>(params: () => CellParams<V>): Bindable<V> {\n const p0 = params()\n const eq = p0.isEqual ?? Object.is\n const initial = (p0.defaultValue ?? p0.value) as V\n let inner = initial\n let lastSeen = initial\n let version = 0\n const isControlled = (): boolean => params().value !== undefined\n const read = (): V => (isControlled() ? (params().value as V) : inner)\n const set = (next: V | ((prev: V) => V)): void => {\n const prev = read()\n const value = typeof next === 'function' ? (next as (p: V) => V)(prev) : next\n if (eq(value, prev))\n return\n if (!isControlled())\n inner = value\n params().onChange?.(value, prev)\n host.requestUpdate()\n }\n return {\n initial,\n get: read,\n set,\n // 落点按当下 props 重算,不用挂载时冻结的 initial:宿主换了 defaultValue\n // (比如切去编辑另一条记录)就该回到新的那一份\n reset() {\n const next = params().defaultValue\n if (next === undefined)\n return undefined\n set(next)\n return next\n },\n notify: () => host.requestUpdate(),\n // 版本号按值拉取比对,受控值不经过 set。\n version: () => {\n const cur = read()\n if (!eq(cur, lastSeen)) {\n lastSeen = cur\n version += 1\n }\n return version\n },\n }\n }\n\n return {\n name: 'wc',\n isServer: false,\n cell,\n track(deps, fn) {\n trackers.push({ deps, fn, last: deps.map(d => d()) })\n },\n flush(fn) {\n void (async () => {\n // 先让出一次微任务,等这次转移把宿主的更新排上队,再去读 updateComplete\n await null\n // updateComplete resolve 成 false 表示更新途中又排了新一轮,DOM 还没落定,接着等下一轮。\n let rounds = 0\n while (!(await host.updateComplete) && rounds < MAX_FLUSH_ROUNDS)\n rounds += 1\n fn()\n })()\n },\n onMount(fn) {\n mounts.push(fn)\n if (mounted)\n fn()\n },\n onCleanup(fn) {\n cleanups.push(fn)\n },\n mount() {\n if (mounted)\n return\n mounted = true\n for (const fn of mounts) fn()\n },\n unmount() {\n if (!mounted)\n return\n mounted = false\n for (let i = cleanups.length - 1; i >= 0; i--) cleanups[i]!()\n cleanups.length = 0\n },\n runTrackers() {\n let errors: unknown[] | undefined\n for (const t of trackers) {\n const next = t.deps.map(d => d())\n if (!next.some((v, i) => !Object.is(v, t.last[i])))\n continue\n const prev = t.last\n // 跑之前先推进:fn 内部若又进到 runTrackers,不会拿同一次变化再触发一遍。\n t.last = next\n try {\n t.fn()\n }\n catch (error) {\n // 回滚到未消费,这次变化留给下一轮补跑;错误攒着,先把余下 tracker 跑完。\n t.last = prev\n errors ??= []\n errors.push(error)\n }\n }\n if (errors !== undefined)\n throw errors.length === 1 ? errors[0] : new AggregateError(errors, 'tracker 抛错')\n },\n }\n}\n","import type { Disposable, Scope } from '@xihan-ui/kernel'\nimport type { MachineConfig, MachineSchema, Service } from '@xihan-ui/machine'\nimport type { ReactiveController, ReactiveControllerHost } from '../reactive'\nimport type { LitRuntime } from './lit-runtime'\nimport { createFormResetBridge } from '@xihan-ui/behavior'\nimport { createService, declaresFormReset, FORM_RESET_EVENT } from '@xihan-ui/machine'\nimport { withXhConfig } from '../config'\n\nimport { createLitRuntime } from './lit-runtime'\n\nexport interface MachineControllerOptions<T extends MachineSchema> {\n scope?: Scope\n /** 每次建机器后回调,用于注入 refs。 */\n onBuilt?: (service: Service<T>) => void\n /**\n * 全局配置从哪个桶里取,默认取机器名。\n * 只有「跑别人机器」的元素需要写它——比如通知的卡片跑的是 toast 那台机器,\n * 文案却该跟着通知走。\n */\n configName?: string\n}\n\n// 一台机器一个 controller:hostConnected 建机器并 mount、hostUpdate 跑 trackers、hostDisconnected unmount。\nexport class MachineController<T extends MachineSchema> implements ReactiveController {\n service!: Service<T>\n private runtime: LitRuntime | undefined\n private started = false\n private formReset: Disposable | undefined\n\n private readonly props: () => Partial<T['props']>\n\n constructor(\n private readonly host: ReactiveControllerHost,\n private readonly machine: MachineConfig<T>,\n props: () => Partial<T['props']>,\n private readonly opts: MachineControllerOptions<T> = {},\n ) {\n // 全局配置在这一处并进来:所有跑机器的元素都从这里取 props,不必逐个接线。\n // 传宿主元素而不是只看全局那份:配置沿 DOM 祖先链解析,作者用 <xh-config> 包住一棵子树即可局部覆盖\n const bucket = this.opts.configName ?? machine.name\n this.props = () => withXhConfig(bucket, props(), host instanceof Element ? host : null)\n host.addController(this)\n // 延到 hostConnected 再 build,构造期 attribute 尚未反射到 reactive property。\n }\n\n private build(): void {\n this.runtime = createLitRuntime(this.host)\n this.service = createService(this.machine, { props: this.props, runtime: this.runtime, scope: this.opts.scope })\n this.opts.onBuilt?.(this.service)\n }\n\n hostConnected(): void {\n // 首次或旧机器已停止时重建,从 initialState 起。\n if (!this.started || this.service.getStatus() === 'Stopped') {\n this.build()\n this.started = true\n }\n this.runtime!.mount()\n // 必须在 mount 之后:桥一挂就可能送事件进来,而 mount 之前送会撞上 SEND_BEFORE_MOUNT\n this.attachFormReset()\n }\n\n /** 元素自己就是锚点(Light DOM)。重连时重建,指向新那台机器。 */\n private attachFormReset(): void {\n if (this.formReset || !declaresFormReset(this.machine))\n return\n const host = this.host as unknown\n if (!(host instanceof Element))\n return\n this.formReset = createFormResetBridge({\n getNode: () => host,\n onReset: () => {\n if (this.service.getStatus() === 'Started')\n this.service.send({ type: FORM_RESET_EVENT } as T['event'])\n },\n })\n }\n\n hostUpdate(): void {\n this.runtime?.runTrackers()\n }\n\n hostDisconnected(): void {\n this.formReset?.dispose()\n this.formReset = undefined\n this.runtime?.unmount()\n }\n}\n"],"mappings":"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"}