@xihan-ui/web-components 1.0.0-alpha.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.
@@ -0,0 +1,67 @@
1
+ import { a as ReactiveControllerHost, i as ReactiveController, n as PropertyDeclarations, r as PropertyValues, t as PropertyDeclaration } from "./types-BvWWqMd_.js";
2
+ //#region src/reactive/element.d.ts
3
+ /**
4
+ * 无 DOM 时的基座替身。类定义式在模块求值那一刻就会取 HTMLElement,
5
+ * 而任何 meta-framework 都会在 Node 里把入口模块求值一次。
6
+ * 元素在没有 customElements 的环境里本就不会被注册,替身只需让定义式成立。
7
+ */
8
+ declare const HostBase: typeof HTMLElement;
9
+ /**
10
+ * 响应式自定义元素基类:属性 → 字段的单向转换、批量异步更新、控制器生命周期。
11
+ * 不做 shadow DOM、不做样式、不做模板渲染、不回写属性。
12
+ */
13
+ declare class XhReactiveElement extends HostBase implements ReactiveControllerHost {
14
+ /** 子类以 `static properties = { 字段名: 选项 }` 声明响应式属性。 */
15
+ static properties: PropertyDeclarations;
16
+ /** 定稿后的全部声明,含从父类继承来的。 */
17
+ static elementProperties: Map<string, PropertyDeclaration>;
18
+ /** 浏览器在 customElements.define() 时读它,属性声明就在这一刻定稿。本基类自身返回 [](Lit 那边是 undefined)。 */
19
+ static get observedAttributes(): string[];
20
+ /** 合并父类声明并逐条建访问器。递归到本基类为止(它已预先登记为定稿);中途抛错时不登记,下次读还抛同一条。 */
21
+ protected static finalize(): void;
22
+ /** 登记一条声明,并在原型上装一个"写入即排更新"的访问器。 */
23
+ protected static createProperty(name: string, options: PropertyDeclaration): void;
24
+ /** createRenderRoot() 的产物。 */
25
+ renderRoot: HTMLElement | DocumentFragment;
26
+ private readonly controllers;
27
+ private changedProperties;
28
+ private pendingUpdate;
29
+ private hasUpdated;
30
+ /** 升级前就写在实例上的字段值,首轮更新时补写回去。 */
31
+ private instanceProperties;
32
+ private updatePromise;
33
+ private startUpdating;
34
+ constructor();
35
+ /** 元素还没 upgrade 时被赋的字段值会盖住原型访问器,先摘下来存着。 */
36
+ private saveInstanceProperties;
37
+ /** 渲染根,默认就是元素自己(Light DOM)。 */
38
+ protected createRenderRoot(): HTMLElement | DocumentFragment;
39
+ addController(controller: ReactiveController): void;
40
+ removeController(controller: ReactiveController): void;
41
+ connectedCallback(): void;
42
+ disconnectedCallback(): void;
43
+ /** 属性变化转成字段值;单向,不回写属性。 */
44
+ attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
45
+ /**
46
+ * 排一轮更新。带 name 时先按判等过滤,同值直接返回。
47
+ * 一拍内调多次只排一轮。
48
+ */
49
+ requestUpdate(name?: PropertyKey, oldValue?: unknown): void;
50
+ /**
51
+ * 本轮更新落定后 resolve;值为 false 表示更新过程中又排了新一轮(要等的是新的 updateComplete)。
52
+ * 元素连上之前永不 resolve。
53
+ */
54
+ get updateComplete(): Promise<boolean>;
55
+ private enqueueUpdate;
56
+ private performUpdate;
57
+ private markUpdated;
58
+ /** 更新主体。子类覆盖时必须调 super.update(),否则这轮永远结不掉。 */
59
+ protected update(_changed: PropertyValues): void;
60
+ /** 首轮更新后调一次。 */
61
+ protected firstUpdated(_changed: PropertyValues): void;
62
+ /** 每轮更新后调。 */
63
+ protected updated(_changed: PropertyValues): void;
64
+ }
65
+ //#endregion
66
+ export { XhReactiveElement as t };
67
+ //# sourceMappingURL=element-DRoFjrYO.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-DRoFjrYO.d.ts","names":[],"sources":["../src/reactive/element.ts"],"mappings":";;;;;;;cAiGM,iBAAiB;;;;;cASV,0BAA0B,oBAAoB;;SAElD,YAAY;;SAGZ,mBAAmB,YAAY;;aAG3B;;mBAOM;;mBA6BA,eAAe,cAAc,SAAS;;EAwBvD,YAAa,cAAc;mBAEV;UACT;UACA;UACA;;UAEA;UACA;UACA;;;UAaA;;YAYE,oBAAoB,cAAc;EAI5C,cAAc,YAAY;EAO1B,iBAAiB,YAAY;EAI7B;EAMA;;EAKA,yBAAyB,cAAc,qBAAqB;;;;;EAc5D,cAAc,OAAO,aAAa;;;;;MAiB9B,kBAAkB;UAIR;UAaN;UAyBA;;YAME,OAAO,UAAU;;YAKjB,aAAa,UAAU;;YAGvB,QAAQ,UAAU"}
@@ -0,0 +1,251 @@
1
+ //#region package.json
2
+ var version = "1.0.0-alpha.0";
3
+ //#endregion
4
+ //#region src/reactive/element.ts
5
+ const finalizedClasses = /* @__PURE__ */ new WeakSet();
6
+ const attributeMaps = /* @__PURE__ */ new WeakMap();
7
+ const installedAccessors = /* @__PURE__ */ new WeakMap();
8
+ const SUPPORTED_DECLARATION_KEYS = /* @__PURE__ */ new Set([
9
+ "attribute",
10
+ "converter",
11
+ "type"
12
+ ]);
13
+ /** 按声明的 type 解读属性字符串。 */
14
+ function defaultFromAttribute(value, type) {
15
+ switch (type) {
16
+ case Boolean: return value !== null;
17
+ case Number: return value === null ? null : Number(value);
18
+ case Object:
19
+ case Array: try {
20
+ return JSON.parse(value);
21
+ } catch {
22
+ return null;
23
+ }
24
+ default: return value;
25
+ }
26
+ }
27
+ function fromAttributeOf(options) {
28
+ const converter = options.converter;
29
+ if (typeof converter === "function") return converter;
30
+ return converter?.fromAttribute ?? defaultFromAttribute;
31
+ }
32
+ /** 判等:Object.is 同值不排更新(NaN 与 NaN 同值,+0 与 -0 不同值)。声明里不接受自定义 hasChanged。 */
33
+ function valueChanged(value, old) {
34
+ return !Object.is(value, old);
35
+ }
36
+ /** 让本类持有自己的 elementProperties。未定稿时顺原型链读到的是父类那一个 Map 实例,直接写会污染父类并泄漏给兄弟子类。 */
37
+ function prepareOwnProperties(ctor) {
38
+ if (Object.hasOwn(ctor, "elementProperties")) return;
39
+ const superCtor = Object.getPrototypeOf(ctor);
40
+ ctor.elementProperties = new Map(superCtor.elementProperties);
41
+ }
42
+ /** 声明键只认 attribute / converter / type,其余当场抛(Lit 的那几个键在这里不生效,不能静默吞)。 */
43
+ function assertSupportedDeclaration(ctor, name, options) {
44
+ for (const key of Reflect.ownKeys(options)) {
45
+ if (typeof key === "string" && SUPPORTED_DECLARATION_KEYS.has(key)) continue;
46
+ throw new TypeError(`${ctor.name}.properties.${name}: 不支持的声明键 ${String(key)}。本运行时只实现 attribute / converter / type:不回写属性(无 reflect)、判等固定 Object.is(无 hasChanged)、声明必装访问器(无 noAccessor / state)。`);
47
+ }
48
+ }
49
+ /** 原型上已有同名成员就抛:装访问器会把它整块盖掉,此后作者写的 get/set 或方法永不被调用。 */
50
+ function assertPrototypeFree(ctor, name) {
51
+ if (installedAccessors.get(ctor.prototype)?.has(name)) return;
52
+ const existing = Object.getOwnPropertyDescriptor(ctor.prototype, name);
53
+ if (existing === void 0) return;
54
+ const kind = existing.get !== void 0 || existing.set !== void 0 ? "get/set 访问器" : "成员";
55
+ throw new TypeError(`${ctor.name}.prototype.${name} 已有 ${kind},响应式属性会把它整块盖掉。本运行时不做 Lit 那样的包装:请给字段改名,或删掉 ${ctor.name}.properties.${name} 这条声明。`);
56
+ }
57
+ /** 该字段观察哪个属性;undefined 表示不观察。 */
58
+ function attributeNameFor(name, options) {
59
+ const { attribute } = options;
60
+ if (attribute === false) return void 0;
61
+ return typeof attribute === "string" ? attribute : name.toLowerCase();
62
+ }
63
+ /**
64
+ * 无 DOM 时的基座替身。类定义式在模块求值那一刻就会取 HTMLElement,
65
+ * 而任何 meta-framework 都会在 Node 里把入口模块求值一次。
66
+ * 元素在没有 customElements 的环境里本就不会被注册,替身只需让定义式成立。
67
+ */
68
+ const HostBase = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
69
+ /**
70
+ * 响应式自定义元素基类:属性 → 字段的单向转换、批量异步更新、控制器生命周期。
71
+ * 不做 shadow DOM、不做样式、不做模板渲染、不回写属性。
72
+ */
73
+ var XhReactiveElement = class extends HostBase {
74
+ /** 子类以 `static properties = { 字段名: 选项 }` 声明响应式属性。 */
75
+ static properties = {};
76
+ /** 定稿后的全部声明,含从父类继承来的。 */
77
+ static elementProperties = /* @__PURE__ */ new Map();
78
+ /** 浏览器在 customElements.define() 时读它,属性声明就在这一刻定稿。本基类自身返回 [](Lit 那边是 undefined)。 */
79
+ static get observedAttributes() {
80
+ this.finalize();
81
+ const attrs = attributeMaps.get(this);
82
+ return attrs === void 0 ? [] : [...attrs.keys()];
83
+ }
84
+ /** 合并父类声明并逐条建访问器。递归到本基类为止(它已预先登记为定稿);中途抛错时不登记,下次读还抛同一条。 */
85
+ static finalize() {
86
+ if (finalizedClasses.has(this)) return;
87
+ Object.getPrototypeOf(this).finalize();
88
+ prepareOwnProperties(this);
89
+ if (Object.hasOwn(this, "properties")) {
90
+ const declarations = this.properties;
91
+ const symbols = Object.getOwnPropertySymbols(declarations);
92
+ if (symbols.length > 0) throw new TypeError(`${this.name}.properties 含 symbol 键 ${String(symbols[0])}:只支持字符串键(symbol 键映射不出属性名)。`);
93
+ for (const name of Object.getOwnPropertyNames(declarations)) this.createProperty(name, declarations[name] ?? {});
94
+ }
95
+ const attributes = /* @__PURE__ */ new Map();
96
+ for (const [name, options] of this.elementProperties) {
97
+ const attribute = attributeNameFor(name, options);
98
+ if (attribute !== void 0) attributes.set(attribute, name);
99
+ }
100
+ attributeMaps.set(this, attributes);
101
+ finalizedClasses.add(this);
102
+ }
103
+ /** 登记一条声明,并在原型上装一个"写入即排更新"的访问器。 */
104
+ static createProperty(name, options) {
105
+ prepareOwnProperties(this);
106
+ assertSupportedDeclaration(this, name, options);
107
+ assertPrototypeFree(this, name);
108
+ this.elementProperties.set(name, options);
109
+ const key = Symbol(name);
110
+ Object.defineProperty(this.prototype, name, {
111
+ configurable: true,
112
+ enumerable: true,
113
+ get() {
114
+ return this[key];
115
+ },
116
+ set(value) {
117
+ const old = this[key];
118
+ this[key] = value;
119
+ this.requestUpdate(name, old);
120
+ }
121
+ });
122
+ const installed = installedAccessors.get(this.prototype) ?? /* @__PURE__ */ new Set();
123
+ installed.add(name);
124
+ installedAccessors.set(this.prototype, installed);
125
+ }
126
+ /** createRenderRoot() 的产物。 */
127
+ renderRoot;
128
+ controllers = /* @__PURE__ */ new Set();
129
+ changedProperties = /* @__PURE__ */ new Map();
130
+ pendingUpdate = false;
131
+ hasUpdated = false;
132
+ /** 升级前就写在实例上的字段值,首轮更新时补写回去。 */
133
+ instanceProperties;
134
+ updatePromise;
135
+ startUpdating;
136
+ constructor() {
137
+ super();
138
+ this.updatePromise = new Promise((resolve) => {
139
+ this.startUpdating = resolve;
140
+ });
141
+ this.saveInstanceProperties();
142
+ this.requestUpdate();
143
+ }
144
+ /** 元素还没 upgrade 时被赋的字段值会盖住原型访问器,先摘下来存着。 */
145
+ saveInstanceProperties() {
146
+ const self = this;
147
+ for (const name of this.constructor.elementProperties.keys()) {
148
+ if (!Object.hasOwn(this, name)) continue;
149
+ this.instanceProperties ??= /* @__PURE__ */ new Map();
150
+ this.instanceProperties.set(name, self[name]);
151
+ delete self[name];
152
+ }
153
+ }
154
+ /** 渲染根,默认就是元素自己(Light DOM)。 */
155
+ createRenderRoot() {
156
+ return this;
157
+ }
158
+ addController(controller) {
159
+ this.controllers.add(controller);
160
+ if (this.renderRoot !== void 0 && this.isConnected) controller.hostConnected?.();
161
+ }
162
+ removeController(controller) {
163
+ this.controllers.delete(controller);
164
+ }
165
+ connectedCallback() {
166
+ this.renderRoot ??= this.createRenderRoot();
167
+ this.startUpdating(true);
168
+ for (const controller of this.controllers) controller.hostConnected?.();
169
+ }
170
+ disconnectedCallback() {
171
+ for (const controller of this.controllers) controller.hostDisconnected?.();
172
+ }
173
+ /** 属性变化转成字段值;单向,不回写属性。 */
174
+ attributeChangedCallback(name, _old, value) {
175
+ const ctor = this.constructor;
176
+ const property = attributeMaps.get(ctor)?.get(name);
177
+ if (property === void 0) return;
178
+ const options = ctor.elementProperties.get(property) ?? {};
179
+ const self = this;
180
+ self[property] = fromAttributeOf(options)(value, options.type);
181
+ }
182
+ /**
183
+ * 排一轮更新。带 name 时先按判等过滤,同值直接返回。
184
+ * 一拍内调多次只排一轮。
185
+ */
186
+ requestUpdate(name, oldValue) {
187
+ if (name !== void 0) {
188
+ const value = this[name];
189
+ if (!valueChanged(value, oldValue)) return;
190
+ if (!this.changedProperties.has(name)) this.changedProperties.set(name, this.hasUpdated ? oldValue : void 0);
191
+ }
192
+ if (!this.pendingUpdate) this.updatePromise = this.enqueueUpdate();
193
+ }
194
+ /**
195
+ * 本轮更新落定后 resolve;值为 false 表示更新过程中又排了新一轮(要等的是新的 updateComplete)。
196
+ * 元素连上之前永不 resolve。
197
+ */
198
+ get updateComplete() {
199
+ return this.updatePromise;
200
+ }
201
+ async enqueueUpdate() {
202
+ this.pendingUpdate = true;
203
+ try {
204
+ await this.updatePromise;
205
+ } catch (error) {
206
+ Promise.reject(error);
207
+ }
208
+ this.performUpdate();
209
+ return !this.pendingUpdate;
210
+ }
211
+ performUpdate() {
212
+ if (!this.pendingUpdate) return;
213
+ if (!this.hasUpdated && this.instanceProperties) {
214
+ const self = this;
215
+ for (const [name, value] of this.instanceProperties) self[name] = value;
216
+ this.instanceProperties = void 0;
217
+ }
218
+ const changed = this.changedProperties;
219
+ try {
220
+ for (const controller of this.controllers) controller.hostUpdate?.();
221
+ this.update(changed);
222
+ } catch (error) {
223
+ this.markUpdated();
224
+ throw error;
225
+ }
226
+ for (const controller of this.controllers) controller.hostUpdated?.();
227
+ if (!this.hasUpdated) {
228
+ this.hasUpdated = true;
229
+ this.firstUpdated(changed);
230
+ }
231
+ this.updated(changed);
232
+ }
233
+ markUpdated() {
234
+ this.changedProperties = /* @__PURE__ */ new Map();
235
+ this.pendingUpdate = false;
236
+ }
237
+ /** 更新主体。子类覆盖时必须调 super.update(),否则这轮永远结不掉。 */
238
+ update(_changed) {
239
+ this.markUpdated();
240
+ }
241
+ /** 首轮更新后调一次。 */
242
+ firstUpdated(_changed) {}
243
+ /** 每轮更新后调。 */
244
+ updated(_changed) {}
245
+ };
246
+ finalizedClasses.add(XhReactiveElement);
247
+ attributeMaps.set(XhReactiveElement, /* @__PURE__ */ new Map());
248
+ //#endregion
249
+ export { version as n, XhReactiveElement as t };
250
+
251
+ //# sourceMappingURL=element-xjYY5Oe2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-xjYY5Oe2.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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"}
@@ -0,0 +1,47 @@
1
+ import { a as ReactiveControllerHost, i as ReactiveController } from "./types-BvWWqMd_.js";
2
+ import { n as createSpreader, t as Spreader } from "./spread-Ch8ZXZDC.js";
3
+ import { Scope } from "@xihan-ui/kernel";
4
+ import { MachineConfig, MachineSchema, ReactiveRuntime, Service } from "@xihan-ui/machine";
5
+ //#region src/dom/normalize.d.ts
6
+ declare const wcNormalize: import("@xihan-ui/kernel").NormalizeProps<import("@xihan-ui/kernel").PropTypes<import("@xihan-ui/kernel").Dict<unknown>>>;
7
+ //#endregion
8
+ //#region src/dom/parts.d.ts
9
+ declare function discoverParts(host: HTMLElement): Map<string, HTMLElement[]>;
10
+ //#endregion
11
+ //#region src/runtime/lit-runtime.d.ts
12
+ interface LitRuntime extends ReactiveRuntime {
13
+ /** hostConnected 调用,跑排队的 onMount。 */
14
+ mount: () => void;
15
+ /** hostDisconnected 调用,逆序跑一次 cleanup。 */
16
+ unmount: () => void;
17
+ /** hostUpdate 调用,逐 tracker 比对依赖、变则触发。 */
18
+ runTrackers: () => void;
19
+ }
20
+ declare function createLitRuntime(host: ReactiveControllerHost): LitRuntime;
21
+ //#endregion
22
+ //#region src/runtime/machine-controller.d.ts
23
+ interface MachineControllerOptions<T extends MachineSchema> {
24
+ scope?: Scope;
25
+ /** 每次建机器后回调,用于注入 refs。 */
26
+ onBuilt?: (service: Service<T>) => void;
27
+ }
28
+ declare class MachineController<T extends MachineSchema> implements ReactiveController {
29
+ private readonly host;
30
+ private readonly machine;
31
+ private readonly props;
32
+ private readonly opts;
33
+ service: Service<T>;
34
+ private runtime;
35
+ private started;
36
+ constructor(host: ReactiveControllerHost, machine: MachineConfig<T>, props: () => Partial<T['props']>, opts?: MachineControllerOptions<T>);
37
+ private build;
38
+ hostConnected(): void;
39
+ hostUpdate(): void;
40
+ hostDisconnected(): void;
41
+ }
42
+ //#endregion
43
+ //#region src/runtime/registry.d.ts
44
+ declare function defineElement(tag: string, ctor: CustomElementConstructor, version: string): void;
45
+ //#endregion
46
+ export { type LitRuntime, MachineController, type Spreader, createLitRuntime, createSpreader, defineElement, discoverParts, wcNormalize };
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/dom/normalize.ts","../src/dom/parts.ts","../src/runtime/lit-runtime.ts","../src/runtime/machine-controller.ts","../src/runtime/registry.ts"],"mappings":";;;;;cAGa,wCAAW,0CAAA,qCAAA;;;iBCMR,cAAc,MAAM,cAAc,YAAY;;;UCJ7C,mBAAmB;;EAElC;;EAEA;;EAEA;;iBAYc,iBAAiB,MAAM,yBAAyB;;;UChB/C,yBAAyB,UAAU;EAClD,QAAQ;;EAER,WAAW,SAAS,QAAQ;;cAIjB,kBAAkB,UAAU,0BAA0B;mBAM9C;mBACA;mBACA;mBACA;EARnB,SAAU,QAAQ;UACV;UACA;EAGW,YAAA,MAAM,wBACN,SAAS,cAAc,IACvB,aAAa,QAAQ,aACrB,OAAM,yBAAyB;UAM1C;EAMR;EASA;EAIA;;;;iBCnCc,cAAc,aAAa,MAAM,0BAA0B"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { a as discoverParts, n as createLitRuntime, o as wcNormalize, r as createSpreader, t as MachineController } from "./machine-controller-Bnr5jbhz.js";
2
+ import { t as defineElement } from "./registry-DR6I2_zF.js";
3
+ export { MachineController, createLitRuntime, createSpreader, defineElement, discoverParts, wcNormalize };