@lytjs/dom 6.4.0 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +242 -237
- package/dist/index.cjs +3 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -10
- package/dist/index.js.map +1 -1
- package/package.json +62 -62
package/README.md
CHANGED
|
@@ -1,237 +1,242 @@
|
|
|
1
|
-
# @lytjs/dom
|
|
2
|
-
|
|
3
|
-
> DOM 工具包,提供 Web Components 集成、属性反射与自定义元素增强能力
|
|
4
|
-
|
|
5
|
-
## 安装
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @lytjs/dom
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## 核心 API
|
|
12
|
-
|
|
13
|
-
### 类型转换器
|
|
14
|
-
|
|
15
|
-
内置类型转换器,用于在 JavaScript 属性值与 HTML attribute 字符串之间进行双向转换
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
import {
|
|
19
|
-
StringConverter,
|
|
20
|
-
NumberConverter,
|
|
21
|
-
BooleanConverter,
|
|
22
|
-
ObjectConverter,
|
|
23
|
-
getConverterByType,
|
|
24
|
-
} from '@lytjs/dom';
|
|
25
|
-
|
|
26
|
-
// 字符串转换
|
|
27
|
-
StringConverter.toAttribute('hello'); // 'hello'
|
|
28
|
-
StringConverter.fromAttribute(null); // ''
|
|
29
|
-
|
|
30
|
-
// 数字转换
|
|
31
|
-
NumberConverter.toAttribute(42); // '42'
|
|
32
|
-
NumberConverter.fromAttribute('42'); // 42
|
|
33
|
-
NumberConverter.fromAttribute('abc'); // null
|
|
34
|
-
|
|
35
|
-
// 布尔转换
|
|
36
|
-
BooleanConverter.toAttribute(true); // ''
|
|
37
|
-
BooleanConverter.toAttribute(false); // null
|
|
38
|
-
BooleanConverter.fromAttribute(''); // true
|
|
39
|
-
BooleanConverter.fromAttribute(null); // false
|
|
40
|
-
|
|
41
|
-
// 对象转换(JSON 序列化)
|
|
42
|
-
ObjectConverter.toAttribute({ a: 1 }); // '{"a":1}'
|
|
43
|
-
ObjectConverter.fromAttribute('{"a":1}'); // { a: 1 }
|
|
44
|
-
|
|
45
|
-
// 根据类型自动获取转换器
|
|
46
|
-
const converter = getConverterByType('number'); // NumberConverter
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### AttributeReflector
|
|
50
|
-
|
|
51
|
-
属性反射管理器,处理 JavaScript 属性与 HTML attribute 之间的双向同步
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
import { AttributeReflector } from '@lytjs/dom';
|
|
55
|
-
|
|
56
|
-
const reflector = new AttributeReflector();
|
|
57
|
-
|
|
58
|
-
// 注册属性反射配置
|
|
59
|
-
reflector.register({
|
|
60
|
-
prop: 'disabled',
|
|
61
|
-
attr: 'disabled',
|
|
62
|
-
converter: BooleanConverter,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// 批量注册
|
|
66
|
-
reflector.registerAll([
|
|
67
|
-
{ prop: 'title', converter: StringConverter },
|
|
68
|
-
{ prop: 'count', converter: NumberConverter },
|
|
69
|
-
]);
|
|
70
|
-
|
|
71
|
-
// 属性值同步到 attribute
|
|
72
|
-
reflector.reflectToAttribute(element, 'disabled', true);
|
|
73
|
-
|
|
74
|
-
// 从 attribute 同步到属性值
|
|
75
|
-
const result = reflector.reflectFromAttribute(element, 'disabled');
|
|
76
|
-
// result: { prop: 'disabled', value: true }
|
|
77
|
-
|
|
78
|
-
// 获取所有观察的 attribute 名称
|
|
79
|
-
reflector.getObservedAttributes(); // ['disabled', 'title', 'count']
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### createEnhancedElementClass
|
|
83
|
-
|
|
84
|
-
创建增强的 Web Component 基类,提供属性反射、变更观察和生命周期钩子
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
import { createEnhancedElementClass } from '@lytjs/dom';
|
|
88
|
-
|
|
89
|
-
const MyElement = createEnhancedElementClass({
|
|
90
|
-
shadow: true,
|
|
91
|
-
styles: ':host { display: block; }',
|
|
92
|
-
properties: [
|
|
93
|
-
{ name: 'title', type: 'string', default: 'Hello' },
|
|
94
|
-
{ name: 'count', type: 'number', default: 0 },
|
|
95
|
-
],
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// 继承并实现自定义逻辑
|
|
99
|
-
class MyCustomElement extends MyElement {
|
|
100
|
-
protected onConnected(): void {
|
|
101
|
-
console.log('Connected:', this.getProperty('title'));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
protected onPropertyChanged(name: string, newValue: unknown): void {
|
|
105
|
-
console.log(`${name} changed to`, newValue);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
customElements.define('my-element', MyCustomElement);
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### defineLytJSWebComponent
|
|
113
|
-
|
|
114
|
-
将 LytJS 组件注册为 Web Component(桥接功能开发中)
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
import { defineLytJSWebComponent } from '@lytjs/dom';
|
|
118
|
-
|
|
119
|
-
defineLytJSWebComponent(
|
|
120
|
-
'my-lytjs-component',
|
|
121
|
-
{
|
|
122
|
-
component: MyLytJSComponent,
|
|
123
|
-
propMapping: { title: 'label' },
|
|
124
|
-
eventMapping: { change: 'on-change' },
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
shadow: true,
|
|
128
|
-
styles: ':host { display: block; }',
|
|
129
|
-
},
|
|
130
|
-
);
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### 工具函数
|
|
134
|
-
|
|
135
|
-
Web Components 环境检测与辅助函数
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
import {
|
|
139
|
-
supportsWebComponents,
|
|
140
|
-
whenDefined,
|
|
141
|
-
isDefined,
|
|
142
|
-
upgradeAll,
|
|
143
|
-
camelToKebab,
|
|
144
|
-
kebabToCamel,
|
|
145
|
-
} from '@lytjs/dom';
|
|
146
|
-
|
|
147
|
-
// 检测浏览器支持
|
|
148
|
-
if (supportsWebComponents()) {
|
|
149
|
-
console.log('Web Components 可用');
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 等待自定义元素定义完成
|
|
153
|
-
await whenDefined('my-element');
|
|
154
|
-
|
|
155
|
-
// 检查是否已定义
|
|
156
|
-
isDefined('my-element'); // true
|
|
157
|
-
|
|
158
|
-
// 升级所有未升级的自定义元素
|
|
159
|
-
upgradeAll(document.body);
|
|
160
|
-
|
|
161
|
-
// 命名转换
|
|
162
|
-
camelToKebab('myComponent'); // 'my-component'
|
|
163
|
-
kebabToCamel('my-component'); // 'myComponent'
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## 类型定义
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
import type {
|
|
170
|
-
WCPropertyDefinition,
|
|
171
|
-
WebComponentOptions,
|
|
172
|
-
AttributeReflectionConfig,
|
|
173
|
-
LytJSBridgeOptions,
|
|
174
|
-
} from '@lytjs/dom';
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### WCPropertyDefinition
|
|
178
|
-
|
|
179
|
-
Web Component 属性定义
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
interface WCPropertyDefinition {
|
|
183
|
-
name: string;
|
|
184
|
-
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
185
|
-
default?: unknown;
|
|
186
|
-
reflect?: boolean;
|
|
187
|
-
onChange?: (newValue: unknown, oldValue: unknown) => void;
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### WebComponentOptions
|
|
192
|
-
|
|
193
|
-
Web Component 配置选项
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
interface WebComponentOptions {
|
|
197
|
-
properties?: WCPropertyDefinition[];
|
|
198
|
-
shadow?: boolean | ShadowRootInit;
|
|
199
|
-
styles?: string;
|
|
200
|
-
observedAttributes?: string[];
|
|
201
|
-
extends?: string;
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### AttributeReflectionConfig
|
|
206
|
-
|
|
207
|
-
属性反射配置
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
interface AttributeReflectionConfig {
|
|
211
|
-
prop: string;
|
|
212
|
-
attr?: string;
|
|
213
|
-
converter?: {
|
|
214
|
-
toAttribute?: (value: unknown) => string | null;
|
|
215
|
-
fromAttribute?: (value: string | null) => unknown;
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### LytJSBridgeOptions
|
|
221
|
-
|
|
222
|
-
LytJS 组件与 Web Component 桥接选项
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
interface LytJSBridgeOptions {
|
|
226
|
-
component: unknown;
|
|
227
|
-
propMapping?: Record<string, string>;
|
|
228
|
-
eventMapping?: Record<string, string>;
|
|
229
|
-
slotMapping?: Record<string, string>;
|
|
230
|
-
}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## 相关包
|
|
234
|
-
|
|
235
|
-
- [@lytjs/core](../core) - 框架核心入口
|
|
236
|
-
- [@lytjs/host-contract](../host-contract) - 渲染器宿主抽象
|
|
237
|
-
- [@lytjs/dom-runtime](../dom-runtime) - DOM 运行时工具
|
|
1
|
+
# @lytjs/dom
|
|
2
|
+
|
|
3
|
+
> DOM 工具包,提供 Web Components 集成、属性反射与自定义元素增强能力
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lytjs/dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 核心 API
|
|
12
|
+
|
|
13
|
+
### 类型转换器
|
|
14
|
+
|
|
15
|
+
内置类型转换器,用于在 JavaScript 属性值与 HTML attribute 字符串之间进行双向转换
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import {
|
|
19
|
+
StringConverter,
|
|
20
|
+
NumberConverter,
|
|
21
|
+
BooleanConverter,
|
|
22
|
+
ObjectConverter,
|
|
23
|
+
getConverterByType,
|
|
24
|
+
} from '@lytjs/dom';
|
|
25
|
+
|
|
26
|
+
// 字符串转换
|
|
27
|
+
StringConverter.toAttribute('hello'); // 'hello'
|
|
28
|
+
StringConverter.fromAttribute(null); // ''
|
|
29
|
+
|
|
30
|
+
// 数字转换
|
|
31
|
+
NumberConverter.toAttribute(42); // '42'
|
|
32
|
+
NumberConverter.fromAttribute('42'); // 42
|
|
33
|
+
NumberConverter.fromAttribute('abc'); // null
|
|
34
|
+
|
|
35
|
+
// 布尔转换
|
|
36
|
+
BooleanConverter.toAttribute(true); // ''
|
|
37
|
+
BooleanConverter.toAttribute(false); // null
|
|
38
|
+
BooleanConverter.fromAttribute(''); // true
|
|
39
|
+
BooleanConverter.fromAttribute(null); // false
|
|
40
|
+
|
|
41
|
+
// 对象转换(JSON 序列化)
|
|
42
|
+
ObjectConverter.toAttribute({ a: 1 }); // '{"a":1}'
|
|
43
|
+
ObjectConverter.fromAttribute('{"a":1}'); // { a: 1 }
|
|
44
|
+
|
|
45
|
+
// 根据类型自动获取转换器
|
|
46
|
+
const converter = getConverterByType('number'); // NumberConverter
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### AttributeReflector
|
|
50
|
+
|
|
51
|
+
属性反射管理器,处理 JavaScript 属性与 HTML attribute 之间的双向同步
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { AttributeReflector } from '@lytjs/dom';
|
|
55
|
+
|
|
56
|
+
const reflector = new AttributeReflector();
|
|
57
|
+
|
|
58
|
+
// 注册属性反射配置
|
|
59
|
+
reflector.register({
|
|
60
|
+
prop: 'disabled',
|
|
61
|
+
attr: 'disabled',
|
|
62
|
+
converter: BooleanConverter,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// 批量注册
|
|
66
|
+
reflector.registerAll([
|
|
67
|
+
{ prop: 'title', converter: StringConverter },
|
|
68
|
+
{ prop: 'count', converter: NumberConverter },
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
// 属性值同步到 attribute
|
|
72
|
+
reflector.reflectToAttribute(element, 'disabled', true);
|
|
73
|
+
|
|
74
|
+
// 从 attribute 同步到属性值
|
|
75
|
+
const result = reflector.reflectFromAttribute(element, 'disabled');
|
|
76
|
+
// result: { prop: 'disabled', value: true }
|
|
77
|
+
|
|
78
|
+
// 获取所有观察的 attribute 名称
|
|
79
|
+
reflector.getObservedAttributes(); // ['disabled', 'title', 'count']
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### createEnhancedElementClass
|
|
83
|
+
|
|
84
|
+
创建增强的 Web Component 基类,提供属性反射、变更观察和生命周期钩子
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { createEnhancedElementClass } from '@lytjs/dom';
|
|
88
|
+
|
|
89
|
+
const MyElement = createEnhancedElementClass({
|
|
90
|
+
shadow: true,
|
|
91
|
+
styles: ':host { display: block; }',
|
|
92
|
+
properties: [
|
|
93
|
+
{ name: 'title', type: 'string', default: 'Hello' },
|
|
94
|
+
{ name: 'count', type: 'number', default: 0 },
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// 继承并实现自定义逻辑
|
|
99
|
+
class MyCustomElement extends MyElement {
|
|
100
|
+
protected onConnected(): void {
|
|
101
|
+
console.log('Connected:', this.getProperty('title'));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
protected onPropertyChanged(name: string, newValue: unknown): void {
|
|
105
|
+
console.log(`${name} changed to`, newValue);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
customElements.define('my-element', MyCustomElement);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### defineLytJSWebComponent
|
|
113
|
+
|
|
114
|
+
将 LytJS 组件注册为 Web Component(桥接功能开发中)
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { defineLytJSWebComponent } from '@lytjs/dom';
|
|
118
|
+
|
|
119
|
+
defineLytJSWebComponent(
|
|
120
|
+
'my-lytjs-component',
|
|
121
|
+
{
|
|
122
|
+
component: MyLytJSComponent,
|
|
123
|
+
propMapping: { title: 'label' },
|
|
124
|
+
eventMapping: { change: 'on-change' },
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
shadow: true,
|
|
128
|
+
styles: ':host { display: block; }',
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 工具函数
|
|
134
|
+
|
|
135
|
+
Web Components 环境检测与辅助函数
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import {
|
|
139
|
+
supportsWebComponents,
|
|
140
|
+
whenDefined,
|
|
141
|
+
isDefined,
|
|
142
|
+
upgradeAll,
|
|
143
|
+
camelToKebab,
|
|
144
|
+
kebabToCamel,
|
|
145
|
+
} from '@lytjs/dom';
|
|
146
|
+
|
|
147
|
+
// 检测浏览器支持
|
|
148
|
+
if (supportsWebComponents()) {
|
|
149
|
+
console.log('Web Components 可用');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 等待自定义元素定义完成
|
|
153
|
+
await whenDefined('my-element');
|
|
154
|
+
|
|
155
|
+
// 检查是否已定义
|
|
156
|
+
isDefined('my-element'); // true
|
|
157
|
+
|
|
158
|
+
// 升级所有未升级的自定义元素
|
|
159
|
+
upgradeAll(document.body);
|
|
160
|
+
|
|
161
|
+
// 命名转换
|
|
162
|
+
camelToKebab('myComponent'); // 'my-component'
|
|
163
|
+
kebabToCamel('my-component'); // 'myComponent'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 类型定义
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import type {
|
|
170
|
+
WCPropertyDefinition,
|
|
171
|
+
WebComponentOptions,
|
|
172
|
+
AttributeReflectionConfig,
|
|
173
|
+
LytJSBridgeOptions,
|
|
174
|
+
} from '@lytjs/dom';
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### WCPropertyDefinition
|
|
178
|
+
|
|
179
|
+
Web Component 属性定义
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
interface WCPropertyDefinition {
|
|
183
|
+
name: string;
|
|
184
|
+
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
185
|
+
default?: unknown;
|
|
186
|
+
reflect?: boolean;
|
|
187
|
+
onChange?: (newValue: unknown, oldValue: unknown) => void;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### WebComponentOptions
|
|
192
|
+
|
|
193
|
+
Web Component 配置选项
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
interface WebComponentOptions {
|
|
197
|
+
properties?: WCPropertyDefinition[];
|
|
198
|
+
shadow?: boolean | ShadowRootInit;
|
|
199
|
+
styles?: string;
|
|
200
|
+
observedAttributes?: string[];
|
|
201
|
+
extends?: string;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### AttributeReflectionConfig
|
|
206
|
+
|
|
207
|
+
属性反射配置
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
interface AttributeReflectionConfig {
|
|
211
|
+
prop: string;
|
|
212
|
+
attr?: string;
|
|
213
|
+
converter?: {
|
|
214
|
+
toAttribute?: (value: unknown) => string | null;
|
|
215
|
+
fromAttribute?: (value: string | null) => unknown;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### LytJSBridgeOptions
|
|
221
|
+
|
|
222
|
+
LytJS 组件与 Web Component 桥接选项
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
interface LytJSBridgeOptions {
|
|
226
|
+
component: unknown;
|
|
227
|
+
propMapping?: Record<string, string>;
|
|
228
|
+
eventMapping?: Record<string, string>;
|
|
229
|
+
slotMapping?: Record<string, string>;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## 相关包
|
|
234
|
+
|
|
235
|
+
- [@lytjs/core](../core) - 框架核心入口
|
|
236
|
+
- [@lytjs/host-contract](../host-contract) - 渲染器宿主抽象
|
|
237
|
+
- [@lytjs/dom-runtime](../dom-runtime) - DOM 运行时工具
|
|
238
|
+
|
|
239
|
+
## 依赖版本
|
|
240
|
+
|
|
241
|
+
- [@lytjs/common-is](https://www.npmjs.com/package/@lytjs/common-is): ^6.4.0
|
|
242
|
+
- [@lytjs/common-string](https://www.npmjs.com/package/@lytjs/common-string): ^6.4.0
|
package/dist/index.cjs
CHANGED
|
@@ -153,10 +153,7 @@ function createEnhancedElementClass(options = {}) {
|
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
155
|
static get observedAttributes() {
|
|
156
|
-
return [
|
|
157
|
-
...options.observedAttributes ?? [],
|
|
158
|
-
...reflector.getObservedAttributes()
|
|
159
|
-
];
|
|
156
|
+
return [...options.observedAttributes ?? [], ...reflector.getObservedAttributes()];
|
|
160
157
|
}
|
|
161
158
|
connectedCallback() {
|
|
162
159
|
this._isConnected = true;
|
|
@@ -172,9 +169,7 @@ function createEnhancedElementClass(options = {}) {
|
|
|
172
169
|
if (reflection) {
|
|
173
170
|
const oldPropValue = this._propertyValues.get(reflection.prop);
|
|
174
171
|
this._propertyValues.set(reflection.prop, reflection.value);
|
|
175
|
-
const propDef = options.properties?.find(
|
|
176
|
-
(p) => p.name === reflection.prop
|
|
177
|
-
);
|
|
172
|
+
const propDef = options.properties?.find((p) => p.name === reflection.prop);
|
|
178
173
|
if (propDef?.onChange) {
|
|
179
174
|
propDef.onChange(reflection.value, oldPropValue);
|
|
180
175
|
}
|
|
@@ -222,9 +217,7 @@ function createEnhancedElementClass(options = {}) {
|
|
|
222
217
|
}
|
|
223
218
|
function defineLytJSWebComponent(name, bridgeOptions, options) {
|
|
224
219
|
const { component, propMapping, eventMapping, slotMapping } = bridgeOptions;
|
|
225
|
-
const mergedProperties = [
|
|
226
|
-
...options?.properties ?? []
|
|
227
|
-
];
|
|
220
|
+
const mergedProperties = [...options?.properties ?? []];
|
|
228
221
|
if (propMapping) {
|
|
229
222
|
for (const [_wcAttr, componentProp] of Object.entries(propMapping)) {
|
|
230
223
|
if (!mergedProperties.some((p) => p.name === componentProp)) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web-components.ts"],"names":["camelToKebab","kebabToCamel","hasOwn"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * @lytjs/dom - Web Components 集成模块\r\n *\r\n * 提供与原生 Web Components 的互操作性支持,包括:\r\n * - 自定义元素注册与管理\r\n * - 属性反射(Attribute Reflection)\r\n * - 属性变更观察\r\n * - 与 LytJS 组件系统的桥接\r\n *\r\n * @module @lytjs/dom/web-components\r\n * @version 6.0.0\r\n */\r\n\r\n// FIX: DTS build error - 删除未使用的导入\r\nimport { hasOwn } from '@lytjs/common-is';\r\n// FIX: P2-18 直接使用 shared 导入的函数,删除局部别名\r\nimport { camelToKebab, kebabToCamel } from '@lytjs/common-string';\r\n\r\n// ============================================================\r\n// 类型定义\r\n// ============================================================\r\n\r\n/**\r\n * Web Component 属性定义\r\n */\r\nexport interface WCPropertyDefinition {\r\n /** 属性名 */\r\n name: string;\r\n /** 属性类型 */\r\n type?: 'string' | 'number' | 'boolean' | 'object' | 'array';\r\n /** 默认值 */\r\n default?: unknown;\r\n /** 是否反射到 attribute */\r\n reflect?: boolean;\r\n /** 属性变更回调 */\r\n onChange?: (newValue: unknown, oldValue: unknown) => void;\r\n}\r\n\r\n/**\r\n * Web Component 配置选项\r\n */\r\nexport interface WebComponentOptions {\r\n /** 组件属性定义 */\r\n properties?: WCPropertyDefinition[];\r\n /** 是否使用 Shadow DOM */\r\n shadow?: boolean | ShadowRootInit;\r\n /** 样式内容(用于 Shadow DOM) */\r\n styles?: string;\r\n /** 观察的属性列表(attributeChangedCallback) */\r\n observedAttributes?: string[];\r\n /** 是否扩展内置元素 */\r\n extends?: string;\r\n}\r\n\r\n/**\r\n * 属性反射配置\r\n */\r\nexport interface AttributeReflectionConfig {\r\n /** 属性名 */\r\n prop: string;\r\n /** 对应的 attribute 名(可选,默认使用 kebab-case) */\r\n attr?: string;\r\n /** 类型转换器 */\r\n converter?: {\r\n toAttribute?: (value: unknown) => string | null;\r\n fromAttribute?: (value: string | null) => unknown;\r\n };\r\n}\r\n\r\n// ============================================================\r\n// 内置类型转换器\r\n// ============================================================\r\n\r\n/**\r\n * 字符串类型转换器\r\n */\r\nexport const StringConverter = {\r\n toAttribute: (value: unknown): string | null =>\r\n value == null ? null : String(value),\r\n fromAttribute: (value: string | null): string =>\r\n value ?? '',\r\n};\r\n\r\n/**\r\n * 数字类型转换器\r\n */\r\nexport const NumberConverter = {\r\n toAttribute: (value: unknown): string | null =>\r\n value == null || value === '' ? null : String(value),\r\n fromAttribute: (value: string | null): number | null => {\r\n if (value === null) return null;\r\n const num = Number(value);\r\n return isNaN(num) ? null : num;\r\n },\r\n};\r\n\r\n/**\r\n * 布尔类型转换器\r\n */\r\nexport const BooleanConverter = {\r\n toAttribute: (value: unknown): string | null =>\r\n value ? '' : null,\r\n fromAttribute: (value: string | null): boolean =>\r\n value !== null,\r\n};\r\n\r\n/**\r\n * 对象类型转换器(使用 JSON)\r\n */\r\nexport const ObjectConverter = {\r\n toAttribute: (value: unknown): string | null => {\r\n if (value == null) return null;\r\n try {\r\n return JSON.stringify(value);\r\n } catch {\r\n return null;\r\n }\r\n },\r\n fromAttribute: (value: string | null): unknown => {\r\n if (value === null) return null;\r\n try {\r\n return JSON.parse(value);\r\n } catch {\r\n return null;\r\n }\r\n },\r\n};\r\n\r\n/**\r\n * 获取类型对应的转换器\r\n */\r\nexport function getConverterByType(\r\n type: WCPropertyDefinition['type'],\r\n): AttributeReflectionConfig['converter'] {\r\n switch (type) {\r\n case 'string':\r\n return StringConverter;\r\n case 'number':\r\n return NumberConverter;\r\n case 'boolean':\r\n return BooleanConverter;\r\n case 'object':\r\n case 'array':\r\n return ObjectConverter;\r\n default:\r\n return StringConverter;\r\n }\r\n}\r\n\r\n// ============================================================\r\n// 属性反射工具函数\r\n// ============================================================\r\n\r\n// FIX: P2-18 直接使用从 @lytjs/shared 导入的 camelToKebab/kebabToCamel\r\n// 局部别名已删除,函数已在顶部直接导入\r\n\r\n/**\r\n * 属性反射管理器\r\n * 处理属性与 attribute 之间的双向同步\r\n */\r\nexport class AttributeReflector {\r\n private configs = new Map<string, AttributeReflectionConfig>();\r\n\r\n /**\r\n * 注册属性反射配置\r\n */\r\n register(config: AttributeReflectionConfig): void {\r\n const attrName = config.attr ?? camelToKebab(config.prop);\r\n this.configs.set(config.prop, { ...config, attr: attrName });\r\n }\r\n\r\n /**\r\n * 批量注册属性反射配置\r\n */\r\n registerAll(configs: AttributeReflectionConfig[]): void {\r\n configs.forEach((config) => this.register(config));\r\n }\r\n\r\n /**\r\n * 属性值变更时同步到 attribute\r\n */\r\n reflectToAttribute(\r\n element: HTMLElement,\r\n prop: string,\r\n value: unknown,\r\n ): void {\r\n const config = this.configs.get(prop);\r\n if (!config) return;\r\n\r\n const converter = config.converter ?? StringConverter;\r\n const attrValue = converter.toAttribute?.(value);\r\n\r\n if (attrValue === null) {\r\n element.removeAttribute(config.attr!);\r\n } else {\r\n // FIX: DTS build error - attrValue 需要是 string\r\n element.setAttribute(config.attr!, attrValue as string);\r\n }\r\n }\r\n\r\n /**\r\n * 从 attribute 同步到属性值\r\n */\r\n reflectFromAttribute(\r\n element: HTMLElement,\r\n attr: string,\r\n ): { prop: string; value: unknown } | null {\r\n for (const [prop, config] of this.configs) {\r\n if (config.attr === attr || camelToKebab(prop) === attr) {\r\n const converter = config.converter ?? StringConverter;\r\n const attrValue = element.getAttribute(attr);\r\n const value = converter.fromAttribute?.(attrValue ?? null);\r\n return { prop, value };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * 获取所有观察的 attribute 名称\r\n */\r\n getObservedAttributes(): string[] {\r\n return Array.from(this.configs.values()).map((c) => c.attr!);\r\n }\r\n\r\n /**\r\n * 获取属性名对应的 attribute 名\r\n */\r\n getAttributeName(prop: string): string | undefined {\r\n return this.configs.get(prop)?.attr;\r\n }\r\n\r\n /**\r\n * 获取 attribute 名对应的属性名\r\n */\r\n getPropertyName(attr: string): string | undefined {\r\n for (const [prop, config] of this.configs) {\r\n if (config.attr === attr) return prop;\r\n }\r\n return kebabToCamel(attr);\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Web Component 基类增强\r\n// ============================================================\r\n\r\n/**\r\n * 创建增强的 Web Component 基类\r\n * 提供属性反射、变更观察等能力\r\n * FIX: P2-v11-25 定义精确的返回类型 EnhancedElementClass,\r\n * 包含 getProperty/setProperty/onConnected 等增强方法的类型信息\r\n */\r\n// FIX: P2-v11-25 定义精确的增强元素类型接口\r\nexport interface EnhancedElementClass extends HTMLElement {\r\n getProperty<T = unknown>(name: string): T | undefined;\r\n setProperty<T = unknown>(name: string, value: T): void;\r\n isConnectedToDOM: boolean;\r\n onConnected?(): void;\r\n onDisconnected?(): void;\r\n onPropertyChanged?(name: string, newValue: unknown, oldValue: unknown): void;\r\n onAttributeChanged?(name: string, oldValue: string | null, newValue: string | null): void;\r\n}\r\n\r\nexport function createEnhancedElementClass(\r\n options: WebComponentOptions = {},\r\n): new () => EnhancedElementClass {\r\n const reflector = new AttributeReflector();\r\n\r\n // 注册属性反射\r\n if (options.properties) {\r\n options.properties.forEach((prop) => {\r\n if (prop.reflect !== false) {\r\n reflector.register({\r\n prop: prop.name,\r\n converter: getConverterByType(prop.type),\r\n });\r\n }\r\n });\r\n }\r\n\r\n class EnhancedElement extends HTMLElement {\r\n static get observedAttributes(): string[] {\r\n return [\r\n ...(options.observedAttributes ?? []),\r\n ...reflector.getObservedAttributes(),\r\n ];\r\n }\r\n\r\n private _propertyValues = new Map<string, unknown>();\r\n private _isConnected = false;\r\n\r\n constructor() {\r\n super();\r\n\r\n // 初始化 Shadow DOM\r\n if (options.shadow) {\r\n const shadowInit: ShadowRootInit =\r\n typeof options.shadow === 'object'\r\n ? options.shadow\r\n : { mode: 'open' };\r\n this.attachShadow(shadowInit);\r\n\r\n // 注入样式\r\n if (options.styles && this.shadowRoot) {\r\n const style = document.createElement('style');\r\n style.textContent = options.styles;\r\n this.shadowRoot.appendChild(style);\r\n }\r\n }\r\n\r\n // 初始化属性默认值\r\n options.properties?.forEach((prop) => {\r\n if (hasOwn(prop, 'default')) {\r\n this._propertyValues.set(prop.name, prop.default);\r\n }\r\n });\r\n }\r\n\r\n connectedCallback(): void {\r\n this._isConnected = true;\r\n this.onConnected?.();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n this._isConnected = false;\r\n this.onDisconnected?.();\r\n }\r\n\r\n attributeChangedCallback(\r\n name: string,\r\n oldValue: string | null,\r\n newValue: string | null,\r\n ): void {\r\n if (oldValue === newValue) return;\r\n\r\n const reflection = reflector.reflectFromAttribute(this, name);\r\n if (reflection) {\r\n const oldPropValue = this._propertyValues.get(reflection.prop);\r\n this._propertyValues.set(reflection.prop, reflection.value);\r\n\r\n // 触发属性变更回调\r\n const propDef = options.properties?.find(\r\n (p) => p.name === reflection.prop,\r\n );\r\n if (propDef?.onChange) {\r\n propDef.onChange(reflection.value, oldPropValue);\r\n }\r\n\r\n this.onPropertyChanged?.(reflection.prop, reflection.value, oldPropValue);\r\n }\r\n\r\n this.onAttributeChanged?.(name, oldValue, newValue);\r\n }\r\n\r\n /**\r\n * 获取属性值\r\n */\r\n getProperty<T = unknown>(name: string): T | undefined {\r\n return this._propertyValues.get(name) as T | undefined;\r\n }\r\n\r\n /**\r\n * 设置属性值(自动触发反射)\r\n */\r\n setProperty<T = unknown>(name: string, value: T): void {\r\n const oldValue = this._propertyValues.get(name);\r\n // FIX: P1-17 使用 Object.is() 替代 ===,正确处理 NaN 和 +/-0 等边界情况;\r\n // 对对象类型使用 JSON 序列化进行深度比较,避免引用不同但内容相同导致误判\r\n // FIX: P2-batch2-14 添加 try-catch 防止循环引用导致 JSON.stringify 抛出异常\r\n if (typeof value === 'object' && value !== null && typeof oldValue === 'object' && oldValue !== null) {\r\n try {\r\n if (JSON.stringify(value) === JSON.stringify(oldValue)) return;\r\n } catch {\r\n // 循环引用或其他序列化错误时,跳过深度比较,继续执行属性更新\r\n }\r\n } else if (Object.is(oldValue, value)) {\r\n return;\r\n }\r\n\r\n this._propertyValues.set(name, value);\r\n\r\n // 反射到 attribute\r\n const propDef = options.properties?.find((p) => p.name === name);\r\n if (propDef?.reflect !== false) {\r\n reflector.reflectToAttribute(this, name, value);\r\n }\r\n\r\n // 触发变更回调\r\n if (propDef?.onChange) {\r\n propDef.onChange(value, oldValue);\r\n }\r\n\r\n this.onPropertyChanged?.(name, value, oldValue);\r\n }\r\n\r\n /**\r\n * 检查组件是否已连接\r\n */\r\n get isConnectedToDOM(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n /**\r\n * 生命周期钩子:已连接\r\n */\r\n protected onConnected?(): void;\r\n\r\n /**\r\n * 生命周期钩子:已断开\r\n */\r\n protected onDisconnected?(): void;\r\n\r\n /**\r\n * 生命周期钩子:属性变更\r\n */\r\n protected onPropertyChanged?(\r\n name: string,\r\n newValue: unknown,\r\n oldValue: unknown,\r\n ): void;\r\n\r\n /**\r\n * 生命周期钩子:attribute 变更\r\n */\r\n protected onAttributeChanged?(\r\n name: string,\r\n oldValue: string | null,\r\n newValue: string | null,\r\n ): void;\r\n }\r\n\r\n return EnhancedElement as unknown as new () => EnhancedElementClass;\r\n}\r\n\r\n// ============================================================\r\n// 与 LytJS 组件系统的桥接\r\n// ============================================================\r\n\r\n/**\r\n * LytJS 组件与 Web Component 桥接选项\r\n */\r\nexport interface LytJSBridgeOptions {\r\n /** LytJS 组件定义 */\r\n component: unknown;\r\n /** 属性映射 */\r\n propMapping?: Record<string, string>;\r\n /** 事件映射 */\r\n eventMapping?: Record<string, string>;\r\n /** 插槽映射 */\r\n slotMapping?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * 创建 LytJS 组件的 Web Component 包装器\r\n *\r\n * 将 LytJS 组件的属性、事件、插槽映射到 Web Component,\r\n * 实现两个组件系统之间的互操作。\r\n */\r\nexport function defineLytJSWebComponent(\r\n name: string,\r\n bridgeOptions: LytJSBridgeOptions,\r\n options?: WebComponentOptions,\r\n): void {\r\n const { component, propMapping, eventMapping, slotMapping } = bridgeOptions;\r\n\r\n // 合并属性定义:将 propMapping 中的属性名转换为 WCPropertyDefinition\r\n const mergedProperties: WCPropertyDefinition[] = [\r\n ...(options?.properties ?? []),\r\n ];\r\n\r\n if (propMapping) {\r\n for (const [_wcAttr, componentProp] of Object.entries(propMapping)) {\r\n // 避免重复定义\r\n if (!mergedProperties.some((p) => p.name === componentProp)) {\r\n mergedProperties.push({\r\n name: componentProp,\r\n type: 'string',\r\n reflect: true,\r\n });\r\n }\r\n }\r\n }\r\n\r\n // 创建增强元素类(使用合并后的属性定义)\r\n const ElementClass = createEnhancedElementClass({\r\n ...options,\r\n properties: mergedProperties,\r\n });\r\n\r\n // 存储桥接元数据到元素类上(供运行时使用)\r\n const bridgeMeta = {\r\n component,\r\n propMapping: propMapping ?? {},\r\n eventMapping: eventMapping ?? {},\r\n slotMapping: slotMapping ?? {},\r\n };\r\n (ElementClass as unknown as Record<symbol, unknown>)[Symbol.for('lytjs.bridge')] = bridgeMeta;\r\n\r\n customElements.define(name, ElementClass);\r\n}\r\n\r\n/**\r\n * 获取 Web Component 上的 LytJS 桥接元数据\r\n *\r\n * @param element - Web Component 元素实例\r\n * @returns 桥接元数据,如果不存在则返回 null\r\n */\r\nexport function getBridgeMeta(\r\n element: Element,\r\n): { component: unknown; propMapping: Record<string, string>; eventMapping: Record<string, string>; slotMapping: Record<string, string> } | null {\r\n const constructor = element.constructor as unknown as Record<symbol, unknown>;\r\n return (constructor[Symbol.for('lytjs.bridge')] ?? null) as ReturnType<typeof getBridgeMeta>;\r\n}\r\n\r\n// ============================================================\r\n// 工具函数\r\n// ============================================================\r\n\r\n/**\r\n * 检查浏览器是否支持 Web Components\r\n */\r\nexport function supportsWebComponents(): boolean {\r\n return (\r\n typeof window !== 'undefined' &&\r\n 'customElements' in window &&\r\n 'HTMLElement' in window\r\n );\r\n}\r\n\r\n/**\r\n * 等待自定义元素定义完成\r\n */\r\n// FIX: DTS build error - whenDefined 返回 Promise<CustomElementConstructor>\r\nexport function whenDefined(name: string): Promise<CustomElementConstructor> {\r\n if (!supportsWebComponents()) {\r\n return Promise.reject(new Error('Web Components not supported'));\r\n }\r\n return customElements.whenDefined(name);\r\n}\r\n\r\n/**\r\n * 检查自定义元素是否已定义\r\n */\r\nexport function isDefined(name: string): boolean {\r\n if (!supportsWebComponents()) return false;\r\n return !!customElements.get(name);\r\n}\r\n\r\n/**\r\n * 升级页面中所有未升级的自定义元素\r\n */\r\nexport function upgradeAll(root: HTMLElement = document.body): void {\r\n if (!supportsWebComponents()) return;\r\n customElements.upgrade(root);\r\n}\r\n\r\n// ============================================================\r\n// 导出\r\n// ============================================================\r\n\r\nexport {\r\n camelToKebab,\r\n kebabToCamel,\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/web-components.ts"],"names":["camelToKebab","kebabToCamel","hasOwn"],"mappings":";;;;;;AA4EO,IAAM,eAAA,GAAkB;AAAA,EAC7B,aAAa,CAAC,KAAA,KAAmC,SAAS,IAAA,GAAO,IAAA,GAAO,OAAO,KAAK,CAAA;AAAA,EACpF,aAAA,EAAe,CAAC,KAAA,KAAiC,KAAA,IAAS;AAC5D;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,WAAA,EAAa,CAAC,KAAA,KACZ,KAAA,IAAS,QAAQ,KAAA,KAAU,EAAA,GAAK,IAAA,GAAO,MAAA,CAAO,KAAK,CAAA;AAAA,EACrD,aAAA,EAAe,CAAC,KAAA,KAAwC;AACtD,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,IAAA,MAAM,GAAA,GAAM,OAAO,KAAK,CAAA;AACxB,IAAA,OAAO,KAAA,CAAM,GAAG,CAAA,GAAI,IAAA,GAAO,GAAA;AAAA,EAC7B;AACF;AAKO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,WAAA,EAAa,CAAC,KAAA,KAAmC,KAAA,GAAQ,EAAA,GAAK,IAAA;AAAA,EAC9D,aAAA,EAAe,CAAC,KAAA,KAAkC,KAAA,KAAU;AAC9D;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,WAAA,EAAa,CAAC,KAAA,KAAkC;AAC9C,IAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAC1B,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,aAAA,EAAe,CAAC,KAAA,KAAkC;AAChD,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IACzB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,mBACd,IAAA,EACwC;AACxC,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,QAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,gBAAA;AAAA,IACT,KAAK,QAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT;AACE,MAAA,OAAO,eAAA;AAAA;AAEb;AAaO,IAAM,qBAAN,MAAyB;AAAA,EAAzB,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,OAAA,uBAAc,GAAA,EAAuC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAK7D,SAAS,MAAA,EAAyC;AAChD,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,IAAQA,yBAAA,CAAa,OAAO,IAAI,CAAA;AACxD,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,MAAA,CAAO,IAAA,EAAM,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAA,EAA4C;AACtD,IAAA,OAAA,CAAQ,QAAQ,CAAC,MAAA,KAAW,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAA,CAAmB,OAAA,EAAsB,IAAA,EAAc,KAAA,EAAsB;AAC3E,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AACpC,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,eAAA;AACtC,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,WAAA,GAAc,KAAK,CAAA;AAE/C,IAAA,IAAI,cAAc,IAAA,EAAM;AACtB,MAAA,OAAA,CAAQ,eAAA,CAAgB,OAAO,IAAK,CAAA;AAAA,IACtC,CAAA,MAAO;AAEL,MAAA,OAAA,CAAQ,YAAA,CAAa,MAAA,CAAO,IAAA,EAAO,SAAmB,CAAA;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAA,CACE,SACA,IAAA,EACyC;AACzC,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,KAAK,OAAA,EAAS;AACzC,MAAA,IAAI,OAAO,IAAA,KAAS,IAAA,IAAQA,yBAAA,CAAa,IAAI,MAAM,IAAA,EAAM;AACvD,QAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,eAAA;AACtC,QAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA;AAC3C,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,aAAA,GAAgB,SAAA,IAAa,IAAI,CAAA;AACzD,QAAA,OAAO,EAAE,MAAM,KAAA,EAAM;AAAA,MACvB;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAA,GAAkC;AAChC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAK,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,IAAA,EAAkC;AACjD,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,EAAG,IAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,IAAA,EAAkC;AAChD,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,KAAK,OAAA,EAAS;AACzC,MAAA,IAAI,MAAA,CAAO,IAAA,KAAS,IAAA,EAAM,OAAO,IAAA;AAAA,IACnC;AACA,IAAA,OAAOC,0BAAa,IAAI,CAAA;AAAA,EAC1B;AACF;AAuBO,SAAS,0BAAA,CACd,OAAA,GAA+B,EAAC,EACA;AAChC,EAAA,MAAM,SAAA,GAAY,IAAI,kBAAA,EAAmB;AAGzC,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ,CAAC,IAAA,KAAS;AACnC,MAAA,IAAI,IAAA,CAAK,YAAY,KAAA,EAAO;AAC1B,QAAA,SAAA,CAAU,QAAA,CAAS;AAAA,UACjB,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,SAAA,EAAW,kBAAA,CAAmB,IAAA,CAAK,IAAI;AAAA,SACxC,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,wBAAwB,WAAA,CAAY;AAAA,IAQxC,WAAA,GAAc;AACZ,MAAA,KAAA,EAAM;AAJR,MAAA,IAAA,CAAQ,eAAA,uBAAsB,GAAA,EAAqB;AACnD,MAAA,IAAA,CAAQ,YAAA,GAAe,KAAA;AAMrB,MAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,QAAA,MAAM,UAAA,GACJ,OAAO,OAAA,CAAQ,MAAA,KAAW,WAAW,OAAA,CAAQ,MAAA,GAAS,EAAE,IAAA,EAAM,MAAA,EAAO;AACvE,QAAA,IAAA,CAAK,aAAa,UAAU,CAAA;AAG5B,QAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,IAAA,CAAK,UAAA,EAAY;AACrC,UAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,UAAA,KAAA,CAAM,cAAc,OAAA,CAAQ,MAAA;AAC5B,UAAA,IAAA,CAAK,UAAA,CAAW,YAAY,KAAK,CAAA;AAAA,QACnC;AAAA,MACF;AAGA,MAAA,OAAA,CAAQ,UAAA,EAAY,OAAA,CAAQ,CAAC,IAAA,KAAS;AACpC,QAAA,IAAIC,eAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG;AAC3B,UAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA,QAClD;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,IA9BA,WAAW,kBAAA,GAA+B;AACxC,MAAA,OAAO,CAAC,GAAI,OAAA,CAAQ,kBAAA,IAAsB,EAAC,EAAI,GAAG,SAAA,CAAU,qBAAA,EAAuB,CAAA;AAAA,IACrF;AAAA,IA8BA,iBAAA,GAA0B;AACxB,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,MAAA,IAAA,CAAK,WAAA,IAAc;AAAA,IACrB;AAAA,IAEA,oBAAA,GAA6B;AAC3B,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,MAAA,IAAA,CAAK,cAAA,IAAiB;AAAA,IACxB;AAAA,IAEA,wBAAA,CAAyB,IAAA,EAAc,QAAA,EAAyB,QAAA,EAA+B;AAC7F,MAAA,IAAI,aAAa,QAAA,EAAU;AAE3B,MAAA,MAAM,UAAA,GAAa,SAAA,CAAU,oBAAA,CAAqB,IAAA,EAAM,IAAI,CAAA;AAC5D,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,MAAM,YAAA,GAAe,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAW,IAAI,CAAA;AAC7D,QAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAA,CAAW,IAAA,EAAM,WAAW,KAAK,CAAA;AAG1D,QAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,UAAA,CAAW,IAAI,CAAA;AAC1E,QAAA,IAAI,SAAS,QAAA,EAAU;AACrB,UAAA,OAAA,CAAQ,QAAA,CAAS,UAAA,CAAW,KAAA,EAAO,YAAY,CAAA;AAAA,QACjD;AAEA,QAAA,IAAA,CAAK,iBAAA,GAAoB,UAAA,CAAW,IAAA,EAAM,UAAA,CAAW,OAAO,YAAY,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA,EAAM,QAAA,EAAU,QAAQ,CAAA;AAAA,IACpD;AAAA;AAAA;AAAA;AAAA,IAKA,YAAyB,IAAA,EAA6B;AACpD,MAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAAA,IACtC;AAAA;AAAA;AAAA;AAAA,IAKA,WAAA,CAAyB,MAAc,KAAA,EAAgB;AACrD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAI9C,MAAA,IACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,OAAO,QAAA,KAAa,QAAA,IACpB,QAAA,KAAa,IAAA,EACb;AACA,QAAA,IAAI;AACF,UAAA,IAAI,KAAK,SAAA,CAAU,KAAK,MAAM,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,EAAG;AAAA,QAC1D,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF,CAAA,MAAA,IAAW,MAAA,CAAO,EAAA,CAAG,QAAA,EAAU,KAAK,CAAA,EAAG;AACrC,QAAA;AAAA,MACF;AAEA,MAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAGpC,MAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAC/D,MAAA,IAAI,OAAA,EAAS,YAAY,KAAA,EAAO;AAC9B,QAAA,SAAA,CAAU,kBAAA,CAAmB,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAAA,MAChD;AAGA,MAAA,IAAI,SAAS,QAAA,EAAU;AACrB,QAAA,OAAA,CAAQ,QAAA,CAAS,OAAO,QAAQ,CAAA;AAAA,MAClC;AAEA,MAAA,IAAA,CAAK,iBAAA,GAAoB,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,gBAAA,GAA4B;AAC9B,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd;AAAA;AA2BF,EAAA,OAAO,eAAA;AACT;AA0BO,SAAS,uBAAA,CACd,IAAA,EACA,aAAA,EACA,OAAA,EACM;AACN,EAAA,MAAM,EAAE,SAAA,EAAW,WAAA,EAAa,YAAA,EAAc,aAAY,GAAI,aAAA;AAG9D,EAAA,MAAM,mBAA2C,CAAC,GAAI,OAAA,EAAS,UAAA,IAAc,EAAG,CAAA;AAEhF,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,aAAa,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AAElE,MAAA,IAAI,CAAC,iBAAiB,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,aAAa,CAAA,EAAG;AAC3D,QAAA,gBAAA,CAAiB,IAAA,CAAK;AAAA,UACpB,IAAA,EAAM,aAAA;AAAA,UACN,IAAA,EAAM,QAAA;AAAA,UACN,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,eAAe,0BAAA,CAA2B;AAAA,IAC9C,GAAG,OAAA;AAAA,IACH,UAAA,EAAY;AAAA,GACb,CAAA;AAGD,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,SAAA;AAAA,IACA,WAAA,EAAa,eAAe,EAAC;AAAA,IAC7B,YAAA,EAAc,gBAAgB,EAAC;AAAA,IAC/B,WAAA,EAAa,eAAe;AAAC,GAC/B;AACA,EAAC,YAAA,iBAAoD,MAAA,CAAO,GAAA,CAAI,cAAc,CAAC,CAAA,GAAI,UAAA;AAEnF,EAAA,cAAA,CAAe,MAAA,CAAO,MAAM,YAAY,CAAA;AAC1C;AAyBO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAAe,gBAAA,IAAoB,UAAU,aAAA,IAAiB,MAAA;AACzF;AAMO,SAAS,YAAY,IAAA,EAAiD;AAC3E,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC5B,IAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,8BAA8B,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,cAAA,CAAe,YAAY,IAAI,CAAA;AACxC;AAKO,SAAS,UAAU,IAAA,EAAuB;AAC/C,EAAA,IAAI,CAAC,qBAAA,EAAsB,EAAG,OAAO,KAAA;AACrC,EAAA,OAAO,CAAC,CAAC,cAAA,CAAe,GAAA,CAAI,IAAI,CAAA;AAClC;AAKO,SAAS,UAAA,CAAW,IAAA,GAAoB,QAAA,CAAS,IAAA,EAAY;AAClE,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC9B,EAAA,cAAA,CAAe,QAAQ,IAAI,CAAA;AAC7B","file":"index.cjs","sourcesContent":["/**\n * @lytjs/dom - Web Components 集成模块\n *\n * 提供与原生 Web Components 的互操作性支持,包括:\n * - 自定义元素注册与管理\n * - 属性反射(Attribute Reflection)\n * - 属性变更观察\n * - 与 LytJS 组件系统的桥接\n *\n * @module @lytjs/dom/web-components\n * @version 6.0.0\n */\n\n// FIX: DTS build error - 删除未使用的导入\nimport { hasOwn } from '@lytjs/common-is';\n// FIX: P2-18 直接使用 shared 导入的函数,删除局部别名\nimport { camelToKebab, kebabToCamel } from '@lytjs/common-string';\n\n// ============================================================\n// 类型定义\n// ============================================================\n\n/**\n * Web Component 属性定义\n */\nexport interface WCPropertyDefinition {\n /** 属性名 */\n name: string;\n /** 属性类型 */\n type?: 'string' | 'number' | 'boolean' | 'object' | 'array';\n /** 默认值 */\n default?: unknown;\n /** 是否反射到 attribute */\n reflect?: boolean;\n /** 属性变更回调 */\n onChange?: (newValue: unknown, oldValue: unknown) => void;\n}\n\n/**\n * Web Component 配置选项\n */\nexport interface WebComponentOptions {\n /** 组件属性定义 */\n properties?: WCPropertyDefinition[];\n /** 是否使用 Shadow DOM */\n shadow?: boolean | ShadowRootInit;\n /** 样式内容(用于 Shadow DOM) */\n styles?: string;\n /** 观察的属性列表(attributeChangedCallback) */\n observedAttributes?: string[];\n /** 是否扩展内置元素 */\n extends?: string;\n}\n\n/**\n * 属性反射配置\n */\nexport interface AttributeReflectionConfig {\n /** 属性名 */\n prop: string;\n /** 对应的 attribute 名(可选,默认使用 kebab-case) */\n attr?: string;\n /** 类型转换器 */\n converter?: {\n toAttribute?: (value: unknown) => string | null;\n fromAttribute?: (value: string | null) => unknown;\n };\n}\n\n// ============================================================\n// 内置类型转换器\n// ============================================================\n\n/**\n * 字符串类型转换器\n */\nexport const StringConverter = {\n toAttribute: (value: unknown): string | null => (value == null ? null : String(value)),\n fromAttribute: (value: string | null): string => value ?? '',\n};\n\n/**\n * 数字类型转换器\n */\nexport const NumberConverter = {\n toAttribute: (value: unknown): string | null =>\n value == null || value === '' ? null : String(value),\n fromAttribute: (value: string | null): number | null => {\n if (value === null) return null;\n const num = Number(value);\n return isNaN(num) ? null : num;\n },\n};\n\n/**\n * 布尔类型转换器\n */\nexport const BooleanConverter = {\n toAttribute: (value: unknown): string | null => (value ? '' : null),\n fromAttribute: (value: string | null): boolean => value !== null,\n};\n\n/**\n * 对象类型转换器(使用 JSON)\n */\nexport const ObjectConverter = {\n toAttribute: (value: unknown): string | null => {\n if (value == null) return null;\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n },\n fromAttribute: (value: string | null): unknown => {\n if (value === null) return null;\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n },\n};\n\n/**\n * 获取类型对应的转换器\n */\nexport function getConverterByType(\n type: WCPropertyDefinition['type'],\n): AttributeReflectionConfig['converter'] {\n switch (type) {\n case 'string':\n return StringConverter;\n case 'number':\n return NumberConverter;\n case 'boolean':\n return BooleanConverter;\n case 'object':\n case 'array':\n return ObjectConverter;\n default:\n return StringConverter;\n }\n}\n\n// ============================================================\n// 属性反射工具函数\n// ============================================================\n\n// FIX: P2-18 直接使用从 @lytjs/shared 导入的 camelToKebab/kebabToCamel\n// 局部别名已删除,函数已在顶部直接导入\n\n/**\n * 属性反射管理器\n * 处理属性与 attribute 之间的双向同步\n */\nexport class AttributeReflector {\n private configs = new Map<string, AttributeReflectionConfig>();\n\n /**\n * 注册属性反射配置\n */\n register(config: AttributeReflectionConfig): void {\n const attrName = config.attr ?? camelToKebab(config.prop);\n this.configs.set(config.prop, { ...config, attr: attrName });\n }\n\n /**\n * 批量注册属性反射配置\n */\n registerAll(configs: AttributeReflectionConfig[]): void {\n configs.forEach((config) => this.register(config));\n }\n\n /**\n * 属性值变更时同步到 attribute\n */\n reflectToAttribute(element: HTMLElement, prop: string, value: unknown): void {\n const config = this.configs.get(prop);\n if (!config) return;\n\n const converter = config.converter ?? StringConverter;\n const attrValue = converter.toAttribute?.(value);\n\n if (attrValue === null) {\n element.removeAttribute(config.attr!);\n } else {\n // FIX: DTS build error - attrValue 需要是 string\n element.setAttribute(config.attr!, attrValue as string);\n }\n }\n\n /**\n * 从 attribute 同步到属性值\n */\n reflectFromAttribute(\n element: HTMLElement,\n attr: string,\n ): { prop: string; value: unknown } | null {\n for (const [prop, config] of this.configs) {\n if (config.attr === attr || camelToKebab(prop) === attr) {\n const converter = config.converter ?? StringConverter;\n const attrValue = element.getAttribute(attr);\n const value = converter.fromAttribute?.(attrValue ?? null);\n return { prop, value };\n }\n }\n return null;\n }\n\n /**\n * 获取所有观察的 attribute 名称\n */\n getObservedAttributes(): string[] {\n return Array.from(this.configs.values()).map((c) => c.attr!);\n }\n\n /**\n * 获取属性名对应的 attribute 名\n */\n getAttributeName(prop: string): string | undefined {\n return this.configs.get(prop)?.attr;\n }\n\n /**\n * 获取 attribute 名对应的属性名\n */\n getPropertyName(attr: string): string | undefined {\n for (const [prop, config] of this.configs) {\n if (config.attr === attr) return prop;\n }\n return kebabToCamel(attr);\n }\n}\n\n// ============================================================\n// Web Component 基类增强\n// ============================================================\n\n/**\n * 创建增强的 Web Component 基类\n * 提供属性反射、变更观察等能力\n * FIX: P2-v11-25 定义精确的返回类型 EnhancedElementClass,\n * 包含 getProperty/setProperty/onConnected 等增强方法的类型信息\n */\n// FIX: P2-v11-25 定义精确的增强元素类型接口\nexport interface EnhancedElementClass extends HTMLElement {\n getProperty<T = unknown>(name: string): T | undefined;\n setProperty<T = unknown>(name: string, value: T): void;\n isConnectedToDOM: boolean;\n onConnected?(): void;\n onDisconnected?(): void;\n onPropertyChanged?(name: string, newValue: unknown, oldValue: unknown): void;\n onAttributeChanged?(name: string, oldValue: string | null, newValue: string | null): void;\n}\n\nexport function createEnhancedElementClass(\n options: WebComponentOptions = {},\n): new () => EnhancedElementClass {\n const reflector = new AttributeReflector();\n\n // 注册属性反射\n if (options.properties) {\n options.properties.forEach((prop) => {\n if (prop.reflect !== false) {\n reflector.register({\n prop: prop.name,\n converter: getConverterByType(prop.type),\n });\n }\n });\n }\n\n class EnhancedElement extends HTMLElement {\n static get observedAttributes(): string[] {\n return [...(options.observedAttributes ?? []), ...reflector.getObservedAttributes()];\n }\n\n private _propertyValues = new Map<string, unknown>();\n private _isConnected = false;\n\n constructor() {\n super();\n\n // 初始化 Shadow DOM\n if (options.shadow) {\n const shadowInit: ShadowRootInit =\n typeof options.shadow === 'object' ? options.shadow : { mode: 'open' };\n this.attachShadow(shadowInit);\n\n // 注入样式\n if (options.styles && this.shadowRoot) {\n const style = document.createElement('style');\n style.textContent = options.styles;\n this.shadowRoot.appendChild(style);\n }\n }\n\n // 初始化属性默认值\n options.properties?.forEach((prop) => {\n if (hasOwn(prop, 'default')) {\n this._propertyValues.set(prop.name, prop.default);\n }\n });\n }\n\n connectedCallback(): void {\n this._isConnected = true;\n this.onConnected?.();\n }\n\n disconnectedCallback(): void {\n this._isConnected = false;\n this.onDisconnected?.();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const reflection = reflector.reflectFromAttribute(this, name);\n if (reflection) {\n const oldPropValue = this._propertyValues.get(reflection.prop);\n this._propertyValues.set(reflection.prop, reflection.value);\n\n // 触发属性变更回调\n const propDef = options.properties?.find((p) => p.name === reflection.prop);\n if (propDef?.onChange) {\n propDef.onChange(reflection.value, oldPropValue);\n }\n\n this.onPropertyChanged?.(reflection.prop, reflection.value, oldPropValue);\n }\n\n this.onAttributeChanged?.(name, oldValue, newValue);\n }\n\n /**\n * 获取属性值\n */\n getProperty<T = unknown>(name: string): T | undefined {\n return this._propertyValues.get(name) as T | undefined;\n }\n\n /**\n * 设置属性值(自动触发反射)\n */\n setProperty<T = unknown>(name: string, value: T): void {\n const oldValue = this._propertyValues.get(name);\n // FIX: P1-17 使用 Object.is() 替代 ===,正确处理 NaN 和 +/-0 等边界情况;\n // 对对象类型使用 JSON 序列化进行深度比较,避免引用不同但内容相同导致误判\n // FIX: P2-batch2-14 添加 try-catch 防止循环引用导致 JSON.stringify 抛出异常\n if (\n typeof value === 'object' &&\n value !== null &&\n typeof oldValue === 'object' &&\n oldValue !== null\n ) {\n try {\n if (JSON.stringify(value) === JSON.stringify(oldValue)) return;\n } catch {\n // 循环引用或其他序列化错误时,跳过深度比较,继续执行属性更新\n }\n } else if (Object.is(oldValue, value)) {\n return;\n }\n\n this._propertyValues.set(name, value);\n\n // 反射到 attribute\n const propDef = options.properties?.find((p) => p.name === name);\n if (propDef?.reflect !== false) {\n reflector.reflectToAttribute(this, name, value);\n }\n\n // 触发变更回调\n if (propDef?.onChange) {\n propDef.onChange(value, oldValue);\n }\n\n this.onPropertyChanged?.(name, value, oldValue);\n }\n\n /**\n * 检查组件是否已连接\n */\n get isConnectedToDOM(): boolean {\n return this._isConnected;\n }\n\n /**\n * 生命周期钩子:已连接\n */\n protected onConnected?(): void;\n\n /**\n * 生命周期钩子:已断开\n */\n protected onDisconnected?(): void;\n\n /**\n * 生命周期钩子:属性变更\n */\n protected onPropertyChanged?(name: string, newValue: unknown, oldValue: unknown): void;\n\n /**\n * 生命周期钩子:attribute 变更\n */\n protected onAttributeChanged?(\n name: string,\n oldValue: string | null,\n newValue: string | null,\n ): void;\n }\n\n return EnhancedElement as unknown as new () => EnhancedElementClass;\n}\n\n// ============================================================\n// 与 LytJS 组件系统的桥接\n// ============================================================\n\n/**\n * LytJS 组件与 Web Component 桥接选项\n */\nexport interface LytJSBridgeOptions {\n /** LytJS 组件定义 */\n component: unknown;\n /** 属性映射 */\n propMapping?: Record<string, string>;\n /** 事件映射 */\n eventMapping?: Record<string, string>;\n /** 插槽映射 */\n slotMapping?: Record<string, string>;\n}\n\n/**\n * 创建 LytJS 组件的 Web Component 包装器\n *\n * 将 LytJS 组件的属性、事件、插槽映射到 Web Component,\n * 实现两个组件系统之间的互操作。\n */\nexport function defineLytJSWebComponent(\n name: string,\n bridgeOptions: LytJSBridgeOptions,\n options?: WebComponentOptions,\n): void {\n const { component, propMapping, eventMapping, slotMapping } = bridgeOptions;\n\n // 合并属性定义:将 propMapping 中的属性名转换为 WCPropertyDefinition\n const mergedProperties: WCPropertyDefinition[] = [...(options?.properties ?? [])];\n\n if (propMapping) {\n for (const [_wcAttr, componentProp] of Object.entries(propMapping)) {\n // 避免重复定义\n if (!mergedProperties.some((p) => p.name === componentProp)) {\n mergedProperties.push({\n name: componentProp,\n type: 'string',\n reflect: true,\n });\n }\n }\n }\n\n // 创建增强元素类(使用合并后的属性定义)\n const ElementClass = createEnhancedElementClass({\n ...options,\n properties: mergedProperties,\n });\n\n // 存储桥接元数据到元素类上(供运行时使用)\n const bridgeMeta = {\n component,\n propMapping: propMapping ?? {},\n eventMapping: eventMapping ?? {},\n slotMapping: slotMapping ?? {},\n };\n (ElementClass as unknown as Record<symbol, unknown>)[Symbol.for('lytjs.bridge')] = bridgeMeta;\n\n customElements.define(name, ElementClass);\n}\n\n/**\n * 获取 Web Component 上的 LytJS 桥接元数据\n *\n * @param element - Web Component 元素实例\n * @returns 桥接元数据,如果不存在则返回 null\n */\nexport function getBridgeMeta(element: Element): {\n component: unknown;\n propMapping: Record<string, string>;\n eventMapping: Record<string, string>;\n slotMapping: Record<string, string>;\n} | null {\n const constructor = element.constructor as unknown as Record<symbol, unknown>;\n return (constructor[Symbol.for('lytjs.bridge')] ?? null) as ReturnType<typeof getBridgeMeta>;\n}\n\n// ============================================================\n// 工具函数\n// ============================================================\n\n/**\n * 检查浏览器是否支持 Web Components\n */\nexport function supportsWebComponents(): boolean {\n return typeof window !== 'undefined' && 'customElements' in window && 'HTMLElement' in window;\n}\n\n/**\n * 等待自定义元素定义完成\n */\n// FIX: DTS build error - whenDefined 返回 Promise<CustomElementConstructor>\nexport function whenDefined(name: string): Promise<CustomElementConstructor> {\n if (!supportsWebComponents()) {\n return Promise.reject(new Error('Web Components not supported'));\n }\n return customElements.whenDefined(name);\n}\n\n/**\n * 检查自定义元素是否已定义\n */\nexport function isDefined(name: string): boolean {\n if (!supportsWebComponents()) return false;\n return !!customElements.get(name);\n}\n\n/**\n * 升级页面中所有未升级的自定义元素\n */\nexport function upgradeAll(root: HTMLElement = document.body): void {\n if (!supportsWebComponents()) return;\n customElements.upgrade(root);\n}\n\n// ============================================================\n// 导出\n// ============================================================\n\nexport { camelToKebab, kebabToCamel };\n"]}
|
package/dist/index.js
CHANGED
|
@@ -152,10 +152,7 @@ function createEnhancedElementClass(options = {}) {
|
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
static get observedAttributes() {
|
|
155
|
-
return [
|
|
156
|
-
...options.observedAttributes ?? [],
|
|
157
|
-
...reflector.getObservedAttributes()
|
|
158
|
-
];
|
|
155
|
+
return [...options.observedAttributes ?? [], ...reflector.getObservedAttributes()];
|
|
159
156
|
}
|
|
160
157
|
connectedCallback() {
|
|
161
158
|
this._isConnected = true;
|
|
@@ -171,9 +168,7 @@ function createEnhancedElementClass(options = {}) {
|
|
|
171
168
|
if (reflection) {
|
|
172
169
|
const oldPropValue = this._propertyValues.get(reflection.prop);
|
|
173
170
|
this._propertyValues.set(reflection.prop, reflection.value);
|
|
174
|
-
const propDef = options.properties?.find(
|
|
175
|
-
(p) => p.name === reflection.prop
|
|
176
|
-
);
|
|
171
|
+
const propDef = options.properties?.find((p) => p.name === reflection.prop);
|
|
177
172
|
if (propDef?.onChange) {
|
|
178
173
|
propDef.onChange(reflection.value, oldPropValue);
|
|
179
174
|
}
|
|
@@ -221,9 +216,7 @@ function createEnhancedElementClass(options = {}) {
|
|
|
221
216
|
}
|
|
222
217
|
function defineLytJSWebComponent(name, bridgeOptions, options) {
|
|
223
218
|
const { component, propMapping, eventMapping, slotMapping } = bridgeOptions;
|
|
224
|
-
const mergedProperties = [
|
|
225
|
-
...options?.properties ?? []
|
|
226
|
-
];
|
|
219
|
+
const mergedProperties = [...options?.properties ?? []];
|
|
227
220
|
if (propMapping) {
|
|
228
221
|
for (const [_wcAttr, componentProp] of Object.entries(propMapping)) {
|
|
229
222
|
if (!mergedProperties.some((p) => p.name === componentProp)) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web-components.ts"],"names":[],"mappings":";;;;;AA4EO,IAAM,eAAA,GAAkB;AAAA,EAC7B,aAAa,CAAC,KAAA,KACZ,SAAS,IAAA,GAAO,IAAA,GAAO,OAAO,KAAK,CAAA;AAAA,EACrC,aAAA,EAAe,CAAC,KAAA,KACd,KAAA,IAAS;AACb;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,WAAA,EAAa,CAAC,KAAA,KACZ,KAAA,IAAS,QAAQ,KAAA,KAAU,EAAA,GAAK,IAAA,GAAO,MAAA,CAAO,KAAK,CAAA;AAAA,EACrD,aAAA,EAAe,CAAC,KAAA,KAAwC;AACtD,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,IAAA,MAAM,GAAA,GAAM,OAAO,KAAK,CAAA;AACxB,IAAA,OAAO,KAAA,CAAM,GAAG,CAAA,GAAI,IAAA,GAAO,GAAA;AAAA,EAC7B;AACF;AAKO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,WAAA,EAAa,CAAC,KAAA,KACZ,KAAA,GAAQ,EAAA,GAAK,IAAA;AAAA,EACf,aAAA,EAAe,CAAC,KAAA,KACd,KAAA,KAAU;AACd;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,WAAA,EAAa,CAAC,KAAA,KAAkC;AAC9C,IAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAC1B,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,aAAA,EAAe,CAAC,KAAA,KAAkC;AAChD,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IACzB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,mBACd,IAAA,EACwC;AACxC,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,QAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,gBAAA;AAAA,IACT,KAAK,QAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT;AACE,MAAA,OAAO,eAAA;AAAA;AAEb;AAaO,IAAM,qBAAN,MAAyB;AAAA,EAAzB,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,OAAA,uBAAc,GAAA,EAAuC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAK7D,SAAS,MAAA,EAAyC;AAChD,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,IAAQ,YAAA,CAAa,OAAO,IAAI,CAAA;AACxD,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,MAAA,CAAO,IAAA,EAAM,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAA,EAA4C;AACtD,IAAA,OAAA,CAAQ,QAAQ,CAAC,MAAA,KAAW,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAA,CACE,OAAA,EACA,IAAA,EACA,KAAA,EACM;AACN,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AACpC,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,eAAA;AACtC,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,WAAA,GAAc,KAAK,CAAA;AAE/C,IAAA,IAAI,cAAc,IAAA,EAAM;AACtB,MAAA,OAAA,CAAQ,eAAA,CAAgB,OAAO,IAAK,CAAA;AAAA,IACtC,CAAA,MAAO;AAEL,MAAA,OAAA,CAAQ,YAAA,CAAa,MAAA,CAAO,IAAA,EAAO,SAAmB,CAAA;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAA,CACE,SACA,IAAA,EACyC;AACzC,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,KAAK,OAAA,EAAS;AACzC,MAAA,IAAI,OAAO,IAAA,KAAS,IAAA,IAAQ,YAAA,CAAa,IAAI,MAAM,IAAA,EAAM;AACvD,QAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,eAAA;AACtC,QAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA;AAC3C,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,aAAA,GAAgB,SAAA,IAAa,IAAI,CAAA;AACzD,QAAA,OAAO,EAAE,MAAM,KAAA,EAAM;AAAA,MACvB;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAA,GAAkC;AAChC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAK,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,IAAA,EAAkC;AACjD,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,EAAG,IAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,IAAA,EAAkC;AAChD,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,KAAK,OAAA,EAAS;AACzC,MAAA,IAAI,MAAA,CAAO,IAAA,KAAS,IAAA,EAAM,OAAO,IAAA;AAAA,IACnC;AACA,IAAA,OAAO,aAAa,IAAI,CAAA;AAAA,EAC1B;AACF;AAuBO,SAAS,0BAAA,CACd,OAAA,GAA+B,EAAC,EACA;AAChC,EAAA,MAAM,SAAA,GAAY,IAAI,kBAAA,EAAmB;AAGzC,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ,CAAC,IAAA,KAAS;AACnC,MAAA,IAAI,IAAA,CAAK,YAAY,KAAA,EAAO;AAC1B,QAAA,SAAA,CAAU,QAAA,CAAS;AAAA,UACjB,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,SAAA,EAAW,kBAAA,CAAmB,IAAA,CAAK,IAAI;AAAA,SACxC,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,wBAAwB,WAAA,CAAY;AAAA,IAWxC,WAAA,GAAc;AACZ,MAAA,KAAA,EAAM;AAJR,MAAA,IAAA,CAAQ,eAAA,uBAAsB,GAAA,EAAqB;AACnD,MAAA,IAAA,CAAQ,YAAA,GAAe,KAAA;AAMrB,MAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,QAAA,MAAM,UAAA,GACJ,OAAO,OAAA,CAAQ,MAAA,KAAW,WACtB,OAAA,CAAQ,MAAA,GACR,EAAE,IAAA,EAAM,MAAA,EAAO;AACrB,QAAA,IAAA,CAAK,aAAa,UAAU,CAAA;AAG5B,QAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,IAAA,CAAK,UAAA,EAAY;AACrC,UAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,UAAA,KAAA,CAAM,cAAc,OAAA,CAAQ,MAAA;AAC5B,UAAA,IAAA,CAAK,UAAA,CAAW,YAAY,KAAK,CAAA;AAAA,QACnC;AAAA,MACF;AAGA,MAAA,OAAA,CAAQ,UAAA,EAAY,OAAA,CAAQ,CAAC,IAAA,KAAS;AACpC,QAAA,IAAI,MAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG;AAC3B,UAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA,QAClD;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,IAnCA,WAAW,kBAAA,GAA+B;AACxC,MAAA,OAAO;AAAA,QACL,GAAI,OAAA,CAAQ,kBAAA,IAAsB,EAAC;AAAA,QACnC,GAAG,UAAU,qBAAA;AAAsB,OACrC;AAAA,IACF;AAAA,IAgCA,iBAAA,GAA0B;AACxB,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,MAAA,IAAA,CAAK,WAAA,IAAc;AAAA,IACrB;AAAA,IAEA,oBAAA,GAA6B;AAC3B,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,MAAA,IAAA,CAAK,cAAA,IAAiB;AAAA,IACxB;AAAA,IAEA,wBAAA,CACE,IAAA,EACA,QAAA,EACA,QAAA,EACM;AACN,MAAA,IAAI,aAAa,QAAA,EAAU;AAE3B,MAAA,MAAM,UAAA,GAAa,SAAA,CAAU,oBAAA,CAAqB,IAAA,EAAM,IAAI,CAAA;AAC5D,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,MAAM,YAAA,GAAe,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAW,IAAI,CAAA;AAC7D,QAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAA,CAAW,IAAA,EAAM,WAAW,KAAK,CAAA;AAG1D,QAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,EAAY,IAAA;AAAA,UAClC,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,UAAA,CAAW;AAAA,SAC/B;AACA,QAAA,IAAI,SAAS,QAAA,EAAU;AACrB,UAAA,OAAA,CAAQ,QAAA,CAAS,UAAA,CAAW,KAAA,EAAO,YAAY,CAAA;AAAA,QACjD;AAEA,QAAA,IAAA,CAAK,iBAAA,GAAoB,UAAA,CAAW,IAAA,EAAM,UAAA,CAAW,OAAO,YAAY,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA,EAAM,QAAA,EAAU,QAAQ,CAAA;AAAA,IACpD;AAAA;AAAA;AAAA;AAAA,IAKA,YAAyB,IAAA,EAA6B;AACpD,MAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAAA,IACtC;AAAA;AAAA;AAAA;AAAA,IAKA,WAAA,CAAyB,MAAc,KAAA,EAAgB;AACrD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAI9C,MAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,KAAa,IAAA,EAAM;AACpG,QAAA,IAAI;AACF,UAAA,IAAI,KAAK,SAAA,CAAU,KAAK,MAAM,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,EAAG;AAAA,QAC1D,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF,CAAA,MAAA,IAAW,MAAA,CAAO,EAAA,CAAG,QAAA,EAAU,KAAK,CAAA,EAAG;AACrC,QAAA;AAAA,MACF;AAEA,MAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAGpC,MAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAC/D,MAAA,IAAI,OAAA,EAAS,YAAY,KAAA,EAAO;AAC9B,QAAA,SAAA,CAAU,kBAAA,CAAmB,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAAA,MAChD;AAGA,MAAA,IAAI,SAAS,QAAA,EAAU;AACrB,QAAA,OAAA,CAAQ,QAAA,CAAS,OAAO,QAAQ,CAAA;AAAA,MAClC;AAEA,MAAA,IAAA,CAAK,iBAAA,GAAoB,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,gBAAA,GAA4B;AAC9B,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd;AAAA;AA+BF,EAAA,OAAO,eAAA;AACT;AA0BO,SAAS,uBAAA,CACd,IAAA,EACA,aAAA,EACA,OAAA,EACM;AACN,EAAA,MAAM,EAAE,SAAA,EAAW,WAAA,EAAa,YAAA,EAAc,aAAY,GAAI,aAAA;AAG9D,EAAA,MAAM,gBAAA,GAA2C;AAAA,IAC/C,GAAI,OAAA,EAAS,UAAA,IAAc;AAAC,GAC9B;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,aAAa,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AAElE,MAAA,IAAI,CAAC,iBAAiB,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,aAAa,CAAA,EAAG;AAC3D,QAAA,gBAAA,CAAiB,IAAA,CAAK;AAAA,UACpB,IAAA,EAAM,aAAA;AAAA,UACN,IAAA,EAAM,QAAA;AAAA,UACN,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,eAAe,0BAAA,CAA2B;AAAA,IAC9C,GAAG,OAAA;AAAA,IACH,UAAA,EAAY;AAAA,GACb,CAAA;AAGD,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,SAAA;AAAA,IACA,WAAA,EAAa,eAAe,EAAC;AAAA,IAC7B,YAAA,EAAc,gBAAgB,EAAC;AAAA,IAC/B,WAAA,EAAa,eAAe;AAAC,GAC/B;AACA,EAAC,YAAA,iBAAoD,MAAA,CAAO,GAAA,CAAI,cAAc,CAAC,CAAA,GAAI,UAAA;AAEnF,EAAA,cAAA,CAAe,MAAA,CAAO,MAAM,YAAY,CAAA;AAC1C;AAsBO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,OACE,OAAO,MAAA,KAAW,WAAA,IAClB,gBAAA,IAAoB,UACpB,aAAA,IAAiB,MAAA;AAErB;AAMO,SAAS,YAAY,IAAA,EAAiD;AAC3E,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC5B,IAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,8BAA8B,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,cAAA,CAAe,YAAY,IAAI,CAAA;AACxC;AAKO,SAAS,UAAU,IAAA,EAAuB;AAC/C,EAAA,IAAI,CAAC,qBAAA,EAAsB,EAAG,OAAO,KAAA;AACrC,EAAA,OAAO,CAAC,CAAC,cAAA,CAAe,GAAA,CAAI,IAAI,CAAA;AAClC;AAKO,SAAS,UAAA,CAAW,IAAA,GAAoB,QAAA,CAAS,IAAA,EAAY;AAClE,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC9B,EAAA,cAAA,CAAe,QAAQ,IAAI,CAAA;AAC7B","file":"index.js","sourcesContent":["/**\r\n * @lytjs/dom - Web Components 集成模块\r\n *\r\n * 提供与原生 Web Components 的互操作性支持,包括:\r\n * - 自定义元素注册与管理\r\n * - 属性反射(Attribute Reflection)\r\n * - 属性变更观察\r\n * - 与 LytJS 组件系统的桥接\r\n *\r\n * @module @lytjs/dom/web-components\r\n * @version 6.0.0\r\n */\r\n\r\n// FIX: DTS build error - 删除未使用的导入\r\nimport { hasOwn } from '@lytjs/common-is';\r\n// FIX: P2-18 直接使用 shared 导入的函数,删除局部别名\r\nimport { camelToKebab, kebabToCamel } from '@lytjs/common-string';\r\n\r\n// ============================================================\r\n// 类型定义\r\n// ============================================================\r\n\r\n/**\r\n * Web Component 属性定义\r\n */\r\nexport interface WCPropertyDefinition {\r\n /** 属性名 */\r\n name: string;\r\n /** 属性类型 */\r\n type?: 'string' | 'number' | 'boolean' | 'object' | 'array';\r\n /** 默认值 */\r\n default?: unknown;\r\n /** 是否反射到 attribute */\r\n reflect?: boolean;\r\n /** 属性变更回调 */\r\n onChange?: (newValue: unknown, oldValue: unknown) => void;\r\n}\r\n\r\n/**\r\n * Web Component 配置选项\r\n */\r\nexport interface WebComponentOptions {\r\n /** 组件属性定义 */\r\n properties?: WCPropertyDefinition[];\r\n /** 是否使用 Shadow DOM */\r\n shadow?: boolean | ShadowRootInit;\r\n /** 样式内容(用于 Shadow DOM) */\r\n styles?: string;\r\n /** 观察的属性列表(attributeChangedCallback) */\r\n observedAttributes?: string[];\r\n /** 是否扩展内置元素 */\r\n extends?: string;\r\n}\r\n\r\n/**\r\n * 属性反射配置\r\n */\r\nexport interface AttributeReflectionConfig {\r\n /** 属性名 */\r\n prop: string;\r\n /** 对应的 attribute 名(可选,默认使用 kebab-case) */\r\n attr?: string;\r\n /** 类型转换器 */\r\n converter?: {\r\n toAttribute?: (value: unknown) => string | null;\r\n fromAttribute?: (value: string | null) => unknown;\r\n };\r\n}\r\n\r\n// ============================================================\r\n// 内置类型转换器\r\n// ============================================================\r\n\r\n/**\r\n * 字符串类型转换器\r\n */\r\nexport const StringConverter = {\r\n toAttribute: (value: unknown): string | null =>\r\n value == null ? null : String(value),\r\n fromAttribute: (value: string | null): string =>\r\n value ?? '',\r\n};\r\n\r\n/**\r\n * 数字类型转换器\r\n */\r\nexport const NumberConverter = {\r\n toAttribute: (value: unknown): string | null =>\r\n value == null || value === '' ? null : String(value),\r\n fromAttribute: (value: string | null): number | null => {\r\n if (value === null) return null;\r\n const num = Number(value);\r\n return isNaN(num) ? null : num;\r\n },\r\n};\r\n\r\n/**\r\n * 布尔类型转换器\r\n */\r\nexport const BooleanConverter = {\r\n toAttribute: (value: unknown): string | null =>\r\n value ? '' : null,\r\n fromAttribute: (value: string | null): boolean =>\r\n value !== null,\r\n};\r\n\r\n/**\r\n * 对象类型转换器(使用 JSON)\r\n */\r\nexport const ObjectConverter = {\r\n toAttribute: (value: unknown): string | null => {\r\n if (value == null) return null;\r\n try {\r\n return JSON.stringify(value);\r\n } catch {\r\n return null;\r\n }\r\n },\r\n fromAttribute: (value: string | null): unknown => {\r\n if (value === null) return null;\r\n try {\r\n return JSON.parse(value);\r\n } catch {\r\n return null;\r\n }\r\n },\r\n};\r\n\r\n/**\r\n * 获取类型对应的转换器\r\n */\r\nexport function getConverterByType(\r\n type: WCPropertyDefinition['type'],\r\n): AttributeReflectionConfig['converter'] {\r\n switch (type) {\r\n case 'string':\r\n return StringConverter;\r\n case 'number':\r\n return NumberConverter;\r\n case 'boolean':\r\n return BooleanConverter;\r\n case 'object':\r\n case 'array':\r\n return ObjectConverter;\r\n default:\r\n return StringConverter;\r\n }\r\n}\r\n\r\n// ============================================================\r\n// 属性反射工具函数\r\n// ============================================================\r\n\r\n// FIX: P2-18 直接使用从 @lytjs/shared 导入的 camelToKebab/kebabToCamel\r\n// 局部别名已删除,函数已在顶部直接导入\r\n\r\n/**\r\n * 属性反射管理器\r\n * 处理属性与 attribute 之间的双向同步\r\n */\r\nexport class AttributeReflector {\r\n private configs = new Map<string, AttributeReflectionConfig>();\r\n\r\n /**\r\n * 注册属性反射配置\r\n */\r\n register(config: AttributeReflectionConfig): void {\r\n const attrName = config.attr ?? camelToKebab(config.prop);\r\n this.configs.set(config.prop, { ...config, attr: attrName });\r\n }\r\n\r\n /**\r\n * 批量注册属性反射配置\r\n */\r\n registerAll(configs: AttributeReflectionConfig[]): void {\r\n configs.forEach((config) => this.register(config));\r\n }\r\n\r\n /**\r\n * 属性值变更时同步到 attribute\r\n */\r\n reflectToAttribute(\r\n element: HTMLElement,\r\n prop: string,\r\n value: unknown,\r\n ): void {\r\n const config = this.configs.get(prop);\r\n if (!config) return;\r\n\r\n const converter = config.converter ?? StringConverter;\r\n const attrValue = converter.toAttribute?.(value);\r\n\r\n if (attrValue === null) {\r\n element.removeAttribute(config.attr!);\r\n } else {\r\n // FIX: DTS build error - attrValue 需要是 string\r\n element.setAttribute(config.attr!, attrValue as string);\r\n }\r\n }\r\n\r\n /**\r\n * 从 attribute 同步到属性值\r\n */\r\n reflectFromAttribute(\r\n element: HTMLElement,\r\n attr: string,\r\n ): { prop: string; value: unknown } | null {\r\n for (const [prop, config] of this.configs) {\r\n if (config.attr === attr || camelToKebab(prop) === attr) {\r\n const converter = config.converter ?? StringConverter;\r\n const attrValue = element.getAttribute(attr);\r\n const value = converter.fromAttribute?.(attrValue ?? null);\r\n return { prop, value };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * 获取所有观察的 attribute 名称\r\n */\r\n getObservedAttributes(): string[] {\r\n return Array.from(this.configs.values()).map((c) => c.attr!);\r\n }\r\n\r\n /**\r\n * 获取属性名对应的 attribute 名\r\n */\r\n getAttributeName(prop: string): string | undefined {\r\n return this.configs.get(prop)?.attr;\r\n }\r\n\r\n /**\r\n * 获取 attribute 名对应的属性名\r\n */\r\n getPropertyName(attr: string): string | undefined {\r\n for (const [prop, config] of this.configs) {\r\n if (config.attr === attr) return prop;\r\n }\r\n return kebabToCamel(attr);\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Web Component 基类增强\r\n// ============================================================\r\n\r\n/**\r\n * 创建增强的 Web Component 基类\r\n * 提供属性反射、变更观察等能力\r\n * FIX: P2-v11-25 定义精确的返回类型 EnhancedElementClass,\r\n * 包含 getProperty/setProperty/onConnected 等增强方法的类型信息\r\n */\r\n// FIX: P2-v11-25 定义精确的增强元素类型接口\r\nexport interface EnhancedElementClass extends HTMLElement {\r\n getProperty<T = unknown>(name: string): T | undefined;\r\n setProperty<T = unknown>(name: string, value: T): void;\r\n isConnectedToDOM: boolean;\r\n onConnected?(): void;\r\n onDisconnected?(): void;\r\n onPropertyChanged?(name: string, newValue: unknown, oldValue: unknown): void;\r\n onAttributeChanged?(name: string, oldValue: string | null, newValue: string | null): void;\r\n}\r\n\r\nexport function createEnhancedElementClass(\r\n options: WebComponentOptions = {},\r\n): new () => EnhancedElementClass {\r\n const reflector = new AttributeReflector();\r\n\r\n // 注册属性反射\r\n if (options.properties) {\r\n options.properties.forEach((prop) => {\r\n if (prop.reflect !== false) {\r\n reflector.register({\r\n prop: prop.name,\r\n converter: getConverterByType(prop.type),\r\n });\r\n }\r\n });\r\n }\r\n\r\n class EnhancedElement extends HTMLElement {\r\n static get observedAttributes(): string[] {\r\n return [\r\n ...(options.observedAttributes ?? []),\r\n ...reflector.getObservedAttributes(),\r\n ];\r\n }\r\n\r\n private _propertyValues = new Map<string, unknown>();\r\n private _isConnected = false;\r\n\r\n constructor() {\r\n super();\r\n\r\n // 初始化 Shadow DOM\r\n if (options.shadow) {\r\n const shadowInit: ShadowRootInit =\r\n typeof options.shadow === 'object'\r\n ? options.shadow\r\n : { mode: 'open' };\r\n this.attachShadow(shadowInit);\r\n\r\n // 注入样式\r\n if (options.styles && this.shadowRoot) {\r\n const style = document.createElement('style');\r\n style.textContent = options.styles;\r\n this.shadowRoot.appendChild(style);\r\n }\r\n }\r\n\r\n // 初始化属性默认值\r\n options.properties?.forEach((prop) => {\r\n if (hasOwn(prop, 'default')) {\r\n this._propertyValues.set(prop.name, prop.default);\r\n }\r\n });\r\n }\r\n\r\n connectedCallback(): void {\r\n this._isConnected = true;\r\n this.onConnected?.();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n this._isConnected = false;\r\n this.onDisconnected?.();\r\n }\r\n\r\n attributeChangedCallback(\r\n name: string,\r\n oldValue: string | null,\r\n newValue: string | null,\r\n ): void {\r\n if (oldValue === newValue) return;\r\n\r\n const reflection = reflector.reflectFromAttribute(this, name);\r\n if (reflection) {\r\n const oldPropValue = this._propertyValues.get(reflection.prop);\r\n this._propertyValues.set(reflection.prop, reflection.value);\r\n\r\n // 触发属性变更回调\r\n const propDef = options.properties?.find(\r\n (p) => p.name === reflection.prop,\r\n );\r\n if (propDef?.onChange) {\r\n propDef.onChange(reflection.value, oldPropValue);\r\n }\r\n\r\n this.onPropertyChanged?.(reflection.prop, reflection.value, oldPropValue);\r\n }\r\n\r\n this.onAttributeChanged?.(name, oldValue, newValue);\r\n }\r\n\r\n /**\r\n * 获取属性值\r\n */\r\n getProperty<T = unknown>(name: string): T | undefined {\r\n return this._propertyValues.get(name) as T | undefined;\r\n }\r\n\r\n /**\r\n * 设置属性值(自动触发反射)\r\n */\r\n setProperty<T = unknown>(name: string, value: T): void {\r\n const oldValue = this._propertyValues.get(name);\r\n // FIX: P1-17 使用 Object.is() 替代 ===,正确处理 NaN 和 +/-0 等边界情况;\r\n // 对对象类型使用 JSON 序列化进行深度比较,避免引用不同但内容相同导致误判\r\n // FIX: P2-batch2-14 添加 try-catch 防止循环引用导致 JSON.stringify 抛出异常\r\n if (typeof value === 'object' && value !== null && typeof oldValue === 'object' && oldValue !== null) {\r\n try {\r\n if (JSON.stringify(value) === JSON.stringify(oldValue)) return;\r\n } catch {\r\n // 循环引用或其他序列化错误时,跳过深度比较,继续执行属性更新\r\n }\r\n } else if (Object.is(oldValue, value)) {\r\n return;\r\n }\r\n\r\n this._propertyValues.set(name, value);\r\n\r\n // 反射到 attribute\r\n const propDef = options.properties?.find((p) => p.name === name);\r\n if (propDef?.reflect !== false) {\r\n reflector.reflectToAttribute(this, name, value);\r\n }\r\n\r\n // 触发变更回调\r\n if (propDef?.onChange) {\r\n propDef.onChange(value, oldValue);\r\n }\r\n\r\n this.onPropertyChanged?.(name, value, oldValue);\r\n }\r\n\r\n /**\r\n * 检查组件是否已连接\r\n */\r\n get isConnectedToDOM(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n /**\r\n * 生命周期钩子:已连接\r\n */\r\n protected onConnected?(): void;\r\n\r\n /**\r\n * 生命周期钩子:已断开\r\n */\r\n protected onDisconnected?(): void;\r\n\r\n /**\r\n * 生命周期钩子:属性变更\r\n */\r\n protected onPropertyChanged?(\r\n name: string,\r\n newValue: unknown,\r\n oldValue: unknown,\r\n ): void;\r\n\r\n /**\r\n * 生命周期钩子:attribute 变更\r\n */\r\n protected onAttributeChanged?(\r\n name: string,\r\n oldValue: string | null,\r\n newValue: string | null,\r\n ): void;\r\n }\r\n\r\n return EnhancedElement as unknown as new () => EnhancedElementClass;\r\n}\r\n\r\n// ============================================================\r\n// 与 LytJS 组件系统的桥接\r\n// ============================================================\r\n\r\n/**\r\n * LytJS 组件与 Web Component 桥接选项\r\n */\r\nexport interface LytJSBridgeOptions {\r\n /** LytJS 组件定义 */\r\n component: unknown;\r\n /** 属性映射 */\r\n propMapping?: Record<string, string>;\r\n /** 事件映射 */\r\n eventMapping?: Record<string, string>;\r\n /** 插槽映射 */\r\n slotMapping?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * 创建 LytJS 组件的 Web Component 包装器\r\n *\r\n * 将 LytJS 组件的属性、事件、插槽映射到 Web Component,\r\n * 实现两个组件系统之间的互操作。\r\n */\r\nexport function defineLytJSWebComponent(\r\n name: string,\r\n bridgeOptions: LytJSBridgeOptions,\r\n options?: WebComponentOptions,\r\n): void {\r\n const { component, propMapping, eventMapping, slotMapping } = bridgeOptions;\r\n\r\n // 合并属性定义:将 propMapping 中的属性名转换为 WCPropertyDefinition\r\n const mergedProperties: WCPropertyDefinition[] = [\r\n ...(options?.properties ?? []),\r\n ];\r\n\r\n if (propMapping) {\r\n for (const [_wcAttr, componentProp] of Object.entries(propMapping)) {\r\n // 避免重复定义\r\n if (!mergedProperties.some((p) => p.name === componentProp)) {\r\n mergedProperties.push({\r\n name: componentProp,\r\n type: 'string',\r\n reflect: true,\r\n });\r\n }\r\n }\r\n }\r\n\r\n // 创建增强元素类(使用合并后的属性定义)\r\n const ElementClass = createEnhancedElementClass({\r\n ...options,\r\n properties: mergedProperties,\r\n });\r\n\r\n // 存储桥接元数据到元素类上(供运行时使用)\r\n const bridgeMeta = {\r\n component,\r\n propMapping: propMapping ?? {},\r\n eventMapping: eventMapping ?? {},\r\n slotMapping: slotMapping ?? {},\r\n };\r\n (ElementClass as unknown as Record<symbol, unknown>)[Symbol.for('lytjs.bridge')] = bridgeMeta;\r\n\r\n customElements.define(name, ElementClass);\r\n}\r\n\r\n/**\r\n * 获取 Web Component 上的 LytJS 桥接元数据\r\n *\r\n * @param element - Web Component 元素实例\r\n * @returns 桥接元数据,如果不存在则返回 null\r\n */\r\nexport function getBridgeMeta(\r\n element: Element,\r\n): { component: unknown; propMapping: Record<string, string>; eventMapping: Record<string, string>; slotMapping: Record<string, string> } | null {\r\n const constructor = element.constructor as unknown as Record<symbol, unknown>;\r\n return (constructor[Symbol.for('lytjs.bridge')] ?? null) as ReturnType<typeof getBridgeMeta>;\r\n}\r\n\r\n// ============================================================\r\n// 工具函数\r\n// ============================================================\r\n\r\n/**\r\n * 检查浏览器是否支持 Web Components\r\n */\r\nexport function supportsWebComponents(): boolean {\r\n return (\r\n typeof window !== 'undefined' &&\r\n 'customElements' in window &&\r\n 'HTMLElement' in window\r\n );\r\n}\r\n\r\n/**\r\n * 等待自定义元素定义完成\r\n */\r\n// FIX: DTS build error - whenDefined 返回 Promise<CustomElementConstructor>\r\nexport function whenDefined(name: string): Promise<CustomElementConstructor> {\r\n if (!supportsWebComponents()) {\r\n return Promise.reject(new Error('Web Components not supported'));\r\n }\r\n return customElements.whenDefined(name);\r\n}\r\n\r\n/**\r\n * 检查自定义元素是否已定义\r\n */\r\nexport function isDefined(name: string): boolean {\r\n if (!supportsWebComponents()) return false;\r\n return !!customElements.get(name);\r\n}\r\n\r\n/**\r\n * 升级页面中所有未升级的自定义元素\r\n */\r\nexport function upgradeAll(root: HTMLElement = document.body): void {\r\n if (!supportsWebComponents()) return;\r\n customElements.upgrade(root);\r\n}\r\n\r\n// ============================================================\r\n// 导出\r\n// ============================================================\r\n\r\nexport {\r\n camelToKebab,\r\n kebabToCamel,\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/web-components.ts"],"names":[],"mappings":";;;;;AA4EO,IAAM,eAAA,GAAkB;AAAA,EAC7B,aAAa,CAAC,KAAA,KAAmC,SAAS,IAAA,GAAO,IAAA,GAAO,OAAO,KAAK,CAAA;AAAA,EACpF,aAAA,EAAe,CAAC,KAAA,KAAiC,KAAA,IAAS;AAC5D;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,WAAA,EAAa,CAAC,KAAA,KACZ,KAAA,IAAS,QAAQ,KAAA,KAAU,EAAA,GAAK,IAAA,GAAO,MAAA,CAAO,KAAK,CAAA;AAAA,EACrD,aAAA,EAAe,CAAC,KAAA,KAAwC;AACtD,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,IAAA,MAAM,GAAA,GAAM,OAAO,KAAK,CAAA;AACxB,IAAA,OAAO,KAAA,CAAM,GAAG,CAAA,GAAI,IAAA,GAAO,GAAA;AAAA,EAC7B;AACF;AAKO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,WAAA,EAAa,CAAC,KAAA,KAAmC,KAAA,GAAQ,EAAA,GAAK,IAAA;AAAA,EAC9D,aAAA,EAAe,CAAC,KAAA,KAAkC,KAAA,KAAU;AAC9D;AAKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,WAAA,EAAa,CAAC,KAAA,KAAkC;AAC9C,IAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAC1B,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAAA,EACA,aAAA,EAAe,CAAC,KAAA,KAAkC;AAChD,IAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IACzB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,mBACd,IAAA,EACwC;AACxC,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,QAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,gBAAA;AAAA,IACT,KAAK,QAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT;AACE,MAAA,OAAO,eAAA;AAAA;AAEb;AAaO,IAAM,qBAAN,MAAyB;AAAA,EAAzB,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,OAAA,uBAAc,GAAA,EAAuC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAK7D,SAAS,MAAA,EAAyC;AAChD,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,IAAQ,YAAA,CAAa,OAAO,IAAI,CAAA;AACxD,IAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,MAAA,CAAO,IAAA,EAAM,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAA,EAA4C;AACtD,IAAA,OAAA,CAAQ,QAAQ,CAAC,MAAA,KAAW,IAAA,CAAK,QAAA,CAAS,MAAM,CAAC,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAA,CAAmB,OAAA,EAAsB,IAAA,EAAc,KAAA,EAAsB;AAC3E,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AACpC,IAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,IAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,eAAA;AACtC,IAAA,MAAM,SAAA,GAAY,SAAA,CAAU,WAAA,GAAc,KAAK,CAAA;AAE/C,IAAA,IAAI,cAAc,IAAA,EAAM;AACtB,MAAA,OAAA,CAAQ,eAAA,CAAgB,OAAO,IAAK,CAAA;AAAA,IACtC,CAAA,MAAO;AAEL,MAAA,OAAA,CAAQ,YAAA,CAAa,MAAA,CAAO,IAAA,EAAO,SAAmB,CAAA;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAA,CACE,SACA,IAAA,EACyC;AACzC,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,KAAK,OAAA,EAAS;AACzC,MAAA,IAAI,OAAO,IAAA,KAAS,IAAA,IAAQ,YAAA,CAAa,IAAI,MAAM,IAAA,EAAM;AACvD,QAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,eAAA;AACtC,QAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA;AAC3C,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,aAAA,GAAgB,SAAA,IAAa,IAAI,CAAA;AACzD,QAAA,OAAO,EAAE,MAAM,KAAA,EAAM;AAAA,MACvB;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAA,GAAkC;AAChC,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAK,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,IAAA,EAAkC;AACjD,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,EAAG,IAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,IAAA,EAAkC;AAChD,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,KAAK,OAAA,EAAS;AACzC,MAAA,IAAI,MAAA,CAAO,IAAA,KAAS,IAAA,EAAM,OAAO,IAAA;AAAA,IACnC;AACA,IAAA,OAAO,aAAa,IAAI,CAAA;AAAA,EAC1B;AACF;AAuBO,SAAS,0BAAA,CACd,OAAA,GAA+B,EAAC,EACA;AAChC,EAAA,MAAM,SAAA,GAAY,IAAI,kBAAA,EAAmB;AAGzC,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ,CAAC,IAAA,KAAS;AACnC,MAAA,IAAI,IAAA,CAAK,YAAY,KAAA,EAAO;AAC1B,QAAA,SAAA,CAAU,QAAA,CAAS;AAAA,UACjB,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,SAAA,EAAW,kBAAA,CAAmB,IAAA,CAAK,IAAI;AAAA,SACxC,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,wBAAwB,WAAA,CAAY;AAAA,IAQxC,WAAA,GAAc;AACZ,MAAA,KAAA,EAAM;AAJR,MAAA,IAAA,CAAQ,eAAA,uBAAsB,GAAA,EAAqB;AACnD,MAAA,IAAA,CAAQ,YAAA,GAAe,KAAA;AAMrB,MAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,QAAA,MAAM,UAAA,GACJ,OAAO,OAAA,CAAQ,MAAA,KAAW,WAAW,OAAA,CAAQ,MAAA,GAAS,EAAE,IAAA,EAAM,MAAA,EAAO;AACvE,QAAA,IAAA,CAAK,aAAa,UAAU,CAAA;AAG5B,QAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,IAAA,CAAK,UAAA,EAAY;AACrC,UAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,UAAA,KAAA,CAAM,cAAc,OAAA,CAAQ,MAAA;AAC5B,UAAA,IAAA,CAAK,UAAA,CAAW,YAAY,KAAK,CAAA;AAAA,QACnC;AAAA,MACF;AAGA,MAAA,OAAA,CAAQ,UAAA,EAAY,OAAA,CAAQ,CAAC,IAAA,KAAS;AACpC,QAAA,IAAI,MAAA,CAAO,IAAA,EAAM,SAAS,CAAA,EAAG;AAC3B,UAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA,QAClD;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,IA9BA,WAAW,kBAAA,GAA+B;AACxC,MAAA,OAAO,CAAC,GAAI,OAAA,CAAQ,kBAAA,IAAsB,EAAC,EAAI,GAAG,SAAA,CAAU,qBAAA,EAAuB,CAAA;AAAA,IACrF;AAAA,IA8BA,iBAAA,GAA0B;AACxB,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,MAAA,IAAA,CAAK,WAAA,IAAc;AAAA,IACrB;AAAA,IAEA,oBAAA,GAA6B;AAC3B,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,MAAA,IAAA,CAAK,cAAA,IAAiB;AAAA,IACxB;AAAA,IAEA,wBAAA,CAAyB,IAAA,EAAc,QAAA,EAAyB,QAAA,EAA+B;AAC7F,MAAA,IAAI,aAAa,QAAA,EAAU;AAE3B,MAAA,MAAM,UAAA,GAAa,SAAA,CAAU,oBAAA,CAAqB,IAAA,EAAM,IAAI,CAAA;AAC5D,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,MAAM,YAAA,GAAe,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,WAAW,IAAI,CAAA;AAC7D,QAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAA,CAAW,IAAA,EAAM,WAAW,KAAK,CAAA;AAG1D,QAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,UAAA,CAAW,IAAI,CAAA;AAC1E,QAAA,IAAI,SAAS,QAAA,EAAU;AACrB,UAAA,OAAA,CAAQ,QAAA,CAAS,UAAA,CAAW,KAAA,EAAO,YAAY,CAAA;AAAA,QACjD;AAEA,QAAA,IAAA,CAAK,iBAAA,GAAoB,UAAA,CAAW,IAAA,EAAM,UAAA,CAAW,OAAO,YAAY,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA,EAAM,QAAA,EAAU,QAAQ,CAAA;AAAA,IACpD;AAAA;AAAA;AAAA;AAAA,IAKA,YAAyB,IAAA,EAA6B;AACpD,MAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAAA,IACtC;AAAA;AAAA;AAAA;AAAA,IAKA,WAAA,CAAyB,MAAc,KAAA,EAAgB;AACrD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AAI9C,MAAA,IACE,OAAO,UAAU,QAAA,IACjB,KAAA,KAAU,QACV,OAAO,QAAA,KAAa,QAAA,IACpB,QAAA,KAAa,IAAA,EACb;AACA,QAAA,IAAI;AACF,UAAA,IAAI,KAAK,SAAA,CAAU,KAAK,MAAM,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,EAAG;AAAA,QAC1D,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF,CAAA,MAAA,IAAW,MAAA,CAAO,EAAA,CAAG,QAAA,EAAU,KAAK,CAAA,EAAG;AACrC,QAAA;AAAA,MACF;AAEA,MAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAGpC,MAAA,MAAM,OAAA,GAAU,QAAQ,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAC/D,MAAA,IAAI,OAAA,EAAS,YAAY,KAAA,EAAO;AAC9B,QAAA,SAAA,CAAU,kBAAA,CAAmB,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAAA,MAChD;AAGA,MAAA,IAAI,SAAS,QAAA,EAAU;AACrB,QAAA,OAAA,CAAQ,QAAA,CAAS,OAAO,QAAQ,CAAA;AAAA,MAClC;AAEA,MAAA,IAAA,CAAK,iBAAA,GAAoB,IAAA,EAAM,KAAA,EAAO,QAAQ,CAAA;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,gBAAA,GAA4B;AAC9B,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd;AAAA;AA2BF,EAAA,OAAO,eAAA;AACT;AA0BO,SAAS,uBAAA,CACd,IAAA,EACA,aAAA,EACA,OAAA,EACM;AACN,EAAA,MAAM,EAAE,SAAA,EAAW,WAAA,EAAa,YAAA,EAAc,aAAY,GAAI,aAAA;AAG9D,EAAA,MAAM,mBAA2C,CAAC,GAAI,OAAA,EAAS,UAAA,IAAc,EAAG,CAAA;AAEhF,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,aAAa,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AAElE,MAAA,IAAI,CAAC,iBAAiB,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,aAAa,CAAA,EAAG;AAC3D,QAAA,gBAAA,CAAiB,IAAA,CAAK;AAAA,UACpB,IAAA,EAAM,aAAA;AAAA,UACN,IAAA,EAAM,QAAA;AAAA,UACN,OAAA,EAAS;AAAA,SACV,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,eAAe,0BAAA,CAA2B;AAAA,IAC9C,GAAG,OAAA;AAAA,IACH,UAAA,EAAY;AAAA,GACb,CAAA;AAGD,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,SAAA;AAAA,IACA,WAAA,EAAa,eAAe,EAAC;AAAA,IAC7B,YAAA,EAAc,gBAAgB,EAAC;AAAA,IAC/B,WAAA,EAAa,eAAe;AAAC,GAC/B;AACA,EAAC,YAAA,iBAAoD,MAAA,CAAO,GAAA,CAAI,cAAc,CAAC,CAAA,GAAI,UAAA;AAEnF,EAAA,cAAA,CAAe,MAAA,CAAO,MAAM,YAAY,CAAA;AAC1C;AAyBO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAAe,gBAAA,IAAoB,UAAU,aAAA,IAAiB,MAAA;AACzF;AAMO,SAAS,YAAY,IAAA,EAAiD;AAC3E,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC5B,IAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,8BAA8B,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,cAAA,CAAe,YAAY,IAAI,CAAA;AACxC;AAKO,SAAS,UAAU,IAAA,EAAuB;AAC/C,EAAA,IAAI,CAAC,qBAAA,EAAsB,EAAG,OAAO,KAAA;AACrC,EAAA,OAAO,CAAC,CAAC,cAAA,CAAe,GAAA,CAAI,IAAI,CAAA;AAClC;AAKO,SAAS,UAAA,CAAW,IAAA,GAAoB,QAAA,CAAS,IAAA,EAAY;AAClE,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC9B,EAAA,cAAA,CAAe,QAAQ,IAAI,CAAA;AAC7B","file":"index.js","sourcesContent":["/**\n * @lytjs/dom - Web Components 集成模块\n *\n * 提供与原生 Web Components 的互操作性支持,包括:\n * - 自定义元素注册与管理\n * - 属性反射(Attribute Reflection)\n * - 属性变更观察\n * - 与 LytJS 组件系统的桥接\n *\n * @module @lytjs/dom/web-components\n * @version 6.0.0\n */\n\n// FIX: DTS build error - 删除未使用的导入\nimport { hasOwn } from '@lytjs/common-is';\n// FIX: P2-18 直接使用 shared 导入的函数,删除局部别名\nimport { camelToKebab, kebabToCamel } from '@lytjs/common-string';\n\n// ============================================================\n// 类型定义\n// ============================================================\n\n/**\n * Web Component 属性定义\n */\nexport interface WCPropertyDefinition {\n /** 属性名 */\n name: string;\n /** 属性类型 */\n type?: 'string' | 'number' | 'boolean' | 'object' | 'array';\n /** 默认值 */\n default?: unknown;\n /** 是否反射到 attribute */\n reflect?: boolean;\n /** 属性变更回调 */\n onChange?: (newValue: unknown, oldValue: unknown) => void;\n}\n\n/**\n * Web Component 配置选项\n */\nexport interface WebComponentOptions {\n /** 组件属性定义 */\n properties?: WCPropertyDefinition[];\n /** 是否使用 Shadow DOM */\n shadow?: boolean | ShadowRootInit;\n /** 样式内容(用于 Shadow DOM) */\n styles?: string;\n /** 观察的属性列表(attributeChangedCallback) */\n observedAttributes?: string[];\n /** 是否扩展内置元素 */\n extends?: string;\n}\n\n/**\n * 属性反射配置\n */\nexport interface AttributeReflectionConfig {\n /** 属性名 */\n prop: string;\n /** 对应的 attribute 名(可选,默认使用 kebab-case) */\n attr?: string;\n /** 类型转换器 */\n converter?: {\n toAttribute?: (value: unknown) => string | null;\n fromAttribute?: (value: string | null) => unknown;\n };\n}\n\n// ============================================================\n// 内置类型转换器\n// ============================================================\n\n/**\n * 字符串类型转换器\n */\nexport const StringConverter = {\n toAttribute: (value: unknown): string | null => (value == null ? null : String(value)),\n fromAttribute: (value: string | null): string => value ?? '',\n};\n\n/**\n * 数字类型转换器\n */\nexport const NumberConverter = {\n toAttribute: (value: unknown): string | null =>\n value == null || value === '' ? null : String(value),\n fromAttribute: (value: string | null): number | null => {\n if (value === null) return null;\n const num = Number(value);\n return isNaN(num) ? null : num;\n },\n};\n\n/**\n * 布尔类型转换器\n */\nexport const BooleanConverter = {\n toAttribute: (value: unknown): string | null => (value ? '' : null),\n fromAttribute: (value: string | null): boolean => value !== null,\n};\n\n/**\n * 对象类型转换器(使用 JSON)\n */\nexport const ObjectConverter = {\n toAttribute: (value: unknown): string | null => {\n if (value == null) return null;\n try {\n return JSON.stringify(value);\n } catch {\n return null;\n }\n },\n fromAttribute: (value: string | null): unknown => {\n if (value === null) return null;\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n },\n};\n\n/**\n * 获取类型对应的转换器\n */\nexport function getConverterByType(\n type: WCPropertyDefinition['type'],\n): AttributeReflectionConfig['converter'] {\n switch (type) {\n case 'string':\n return StringConverter;\n case 'number':\n return NumberConverter;\n case 'boolean':\n return BooleanConverter;\n case 'object':\n case 'array':\n return ObjectConverter;\n default:\n return StringConverter;\n }\n}\n\n// ============================================================\n// 属性反射工具函数\n// ============================================================\n\n// FIX: P2-18 直接使用从 @lytjs/shared 导入的 camelToKebab/kebabToCamel\n// 局部别名已删除,函数已在顶部直接导入\n\n/**\n * 属性反射管理器\n * 处理属性与 attribute 之间的双向同步\n */\nexport class AttributeReflector {\n private configs = new Map<string, AttributeReflectionConfig>();\n\n /**\n * 注册属性反射配置\n */\n register(config: AttributeReflectionConfig): void {\n const attrName = config.attr ?? camelToKebab(config.prop);\n this.configs.set(config.prop, { ...config, attr: attrName });\n }\n\n /**\n * 批量注册属性反射配置\n */\n registerAll(configs: AttributeReflectionConfig[]): void {\n configs.forEach((config) => this.register(config));\n }\n\n /**\n * 属性值变更时同步到 attribute\n */\n reflectToAttribute(element: HTMLElement, prop: string, value: unknown): void {\n const config = this.configs.get(prop);\n if (!config) return;\n\n const converter = config.converter ?? StringConverter;\n const attrValue = converter.toAttribute?.(value);\n\n if (attrValue === null) {\n element.removeAttribute(config.attr!);\n } else {\n // FIX: DTS build error - attrValue 需要是 string\n element.setAttribute(config.attr!, attrValue as string);\n }\n }\n\n /**\n * 从 attribute 同步到属性值\n */\n reflectFromAttribute(\n element: HTMLElement,\n attr: string,\n ): { prop: string; value: unknown } | null {\n for (const [prop, config] of this.configs) {\n if (config.attr === attr || camelToKebab(prop) === attr) {\n const converter = config.converter ?? StringConverter;\n const attrValue = element.getAttribute(attr);\n const value = converter.fromAttribute?.(attrValue ?? null);\n return { prop, value };\n }\n }\n return null;\n }\n\n /**\n * 获取所有观察的 attribute 名称\n */\n getObservedAttributes(): string[] {\n return Array.from(this.configs.values()).map((c) => c.attr!);\n }\n\n /**\n * 获取属性名对应的 attribute 名\n */\n getAttributeName(prop: string): string | undefined {\n return this.configs.get(prop)?.attr;\n }\n\n /**\n * 获取 attribute 名对应的属性名\n */\n getPropertyName(attr: string): string | undefined {\n for (const [prop, config] of this.configs) {\n if (config.attr === attr) return prop;\n }\n return kebabToCamel(attr);\n }\n}\n\n// ============================================================\n// Web Component 基类增强\n// ============================================================\n\n/**\n * 创建增强的 Web Component 基类\n * 提供属性反射、变更观察等能力\n * FIX: P2-v11-25 定义精确的返回类型 EnhancedElementClass,\n * 包含 getProperty/setProperty/onConnected 等增强方法的类型信息\n */\n// FIX: P2-v11-25 定义精确的增强元素类型接口\nexport interface EnhancedElementClass extends HTMLElement {\n getProperty<T = unknown>(name: string): T | undefined;\n setProperty<T = unknown>(name: string, value: T): void;\n isConnectedToDOM: boolean;\n onConnected?(): void;\n onDisconnected?(): void;\n onPropertyChanged?(name: string, newValue: unknown, oldValue: unknown): void;\n onAttributeChanged?(name: string, oldValue: string | null, newValue: string | null): void;\n}\n\nexport function createEnhancedElementClass(\n options: WebComponentOptions = {},\n): new () => EnhancedElementClass {\n const reflector = new AttributeReflector();\n\n // 注册属性反射\n if (options.properties) {\n options.properties.forEach((prop) => {\n if (prop.reflect !== false) {\n reflector.register({\n prop: prop.name,\n converter: getConverterByType(prop.type),\n });\n }\n });\n }\n\n class EnhancedElement extends HTMLElement {\n static get observedAttributes(): string[] {\n return [...(options.observedAttributes ?? []), ...reflector.getObservedAttributes()];\n }\n\n private _propertyValues = new Map<string, unknown>();\n private _isConnected = false;\n\n constructor() {\n super();\n\n // 初始化 Shadow DOM\n if (options.shadow) {\n const shadowInit: ShadowRootInit =\n typeof options.shadow === 'object' ? options.shadow : { mode: 'open' };\n this.attachShadow(shadowInit);\n\n // 注入样式\n if (options.styles && this.shadowRoot) {\n const style = document.createElement('style');\n style.textContent = options.styles;\n this.shadowRoot.appendChild(style);\n }\n }\n\n // 初始化属性默认值\n options.properties?.forEach((prop) => {\n if (hasOwn(prop, 'default')) {\n this._propertyValues.set(prop.name, prop.default);\n }\n });\n }\n\n connectedCallback(): void {\n this._isConnected = true;\n this.onConnected?.();\n }\n\n disconnectedCallback(): void {\n this._isConnected = false;\n this.onDisconnected?.();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const reflection = reflector.reflectFromAttribute(this, name);\n if (reflection) {\n const oldPropValue = this._propertyValues.get(reflection.prop);\n this._propertyValues.set(reflection.prop, reflection.value);\n\n // 触发属性变更回调\n const propDef = options.properties?.find((p) => p.name === reflection.prop);\n if (propDef?.onChange) {\n propDef.onChange(reflection.value, oldPropValue);\n }\n\n this.onPropertyChanged?.(reflection.prop, reflection.value, oldPropValue);\n }\n\n this.onAttributeChanged?.(name, oldValue, newValue);\n }\n\n /**\n * 获取属性值\n */\n getProperty<T = unknown>(name: string): T | undefined {\n return this._propertyValues.get(name) as T | undefined;\n }\n\n /**\n * 设置属性值(自动触发反射)\n */\n setProperty<T = unknown>(name: string, value: T): void {\n const oldValue = this._propertyValues.get(name);\n // FIX: P1-17 使用 Object.is() 替代 ===,正确处理 NaN 和 +/-0 等边界情况;\n // 对对象类型使用 JSON 序列化进行深度比较,避免引用不同但内容相同导致误判\n // FIX: P2-batch2-14 添加 try-catch 防止循环引用导致 JSON.stringify 抛出异常\n if (\n typeof value === 'object' &&\n value !== null &&\n typeof oldValue === 'object' &&\n oldValue !== null\n ) {\n try {\n if (JSON.stringify(value) === JSON.stringify(oldValue)) return;\n } catch {\n // 循环引用或其他序列化错误时,跳过深度比较,继续执行属性更新\n }\n } else if (Object.is(oldValue, value)) {\n return;\n }\n\n this._propertyValues.set(name, value);\n\n // 反射到 attribute\n const propDef = options.properties?.find((p) => p.name === name);\n if (propDef?.reflect !== false) {\n reflector.reflectToAttribute(this, name, value);\n }\n\n // 触发变更回调\n if (propDef?.onChange) {\n propDef.onChange(value, oldValue);\n }\n\n this.onPropertyChanged?.(name, value, oldValue);\n }\n\n /**\n * 检查组件是否已连接\n */\n get isConnectedToDOM(): boolean {\n return this._isConnected;\n }\n\n /**\n * 生命周期钩子:已连接\n */\n protected onConnected?(): void;\n\n /**\n * 生命周期钩子:已断开\n */\n protected onDisconnected?(): void;\n\n /**\n * 生命周期钩子:属性变更\n */\n protected onPropertyChanged?(name: string, newValue: unknown, oldValue: unknown): void;\n\n /**\n * 生命周期钩子:attribute 变更\n */\n protected onAttributeChanged?(\n name: string,\n oldValue: string | null,\n newValue: string | null,\n ): void;\n }\n\n return EnhancedElement as unknown as new () => EnhancedElementClass;\n}\n\n// ============================================================\n// 与 LytJS 组件系统的桥接\n// ============================================================\n\n/**\n * LytJS 组件与 Web Component 桥接选项\n */\nexport interface LytJSBridgeOptions {\n /** LytJS 组件定义 */\n component: unknown;\n /** 属性映射 */\n propMapping?: Record<string, string>;\n /** 事件映射 */\n eventMapping?: Record<string, string>;\n /** 插槽映射 */\n slotMapping?: Record<string, string>;\n}\n\n/**\n * 创建 LytJS 组件的 Web Component 包装器\n *\n * 将 LytJS 组件的属性、事件、插槽映射到 Web Component,\n * 实现两个组件系统之间的互操作。\n */\nexport function defineLytJSWebComponent(\n name: string,\n bridgeOptions: LytJSBridgeOptions,\n options?: WebComponentOptions,\n): void {\n const { component, propMapping, eventMapping, slotMapping } = bridgeOptions;\n\n // 合并属性定义:将 propMapping 中的属性名转换为 WCPropertyDefinition\n const mergedProperties: WCPropertyDefinition[] = [...(options?.properties ?? [])];\n\n if (propMapping) {\n for (const [_wcAttr, componentProp] of Object.entries(propMapping)) {\n // 避免重复定义\n if (!mergedProperties.some((p) => p.name === componentProp)) {\n mergedProperties.push({\n name: componentProp,\n type: 'string',\n reflect: true,\n });\n }\n }\n }\n\n // 创建增强元素类(使用合并后的属性定义)\n const ElementClass = createEnhancedElementClass({\n ...options,\n properties: mergedProperties,\n });\n\n // 存储桥接元数据到元素类上(供运行时使用)\n const bridgeMeta = {\n component,\n propMapping: propMapping ?? {},\n eventMapping: eventMapping ?? {},\n slotMapping: slotMapping ?? {},\n };\n (ElementClass as unknown as Record<symbol, unknown>)[Symbol.for('lytjs.bridge')] = bridgeMeta;\n\n customElements.define(name, ElementClass);\n}\n\n/**\n * 获取 Web Component 上的 LytJS 桥接元数据\n *\n * @param element - Web Component 元素实例\n * @returns 桥接元数据,如果不存在则返回 null\n */\nexport function getBridgeMeta(element: Element): {\n component: unknown;\n propMapping: Record<string, string>;\n eventMapping: Record<string, string>;\n slotMapping: Record<string, string>;\n} | null {\n const constructor = element.constructor as unknown as Record<symbol, unknown>;\n return (constructor[Symbol.for('lytjs.bridge')] ?? null) as ReturnType<typeof getBridgeMeta>;\n}\n\n// ============================================================\n// 工具函数\n// ============================================================\n\n/**\n * 检查浏览器是否支持 Web Components\n */\nexport function supportsWebComponents(): boolean {\n return typeof window !== 'undefined' && 'customElements' in window && 'HTMLElement' in window;\n}\n\n/**\n * 等待自定义元素定义完成\n */\n// FIX: DTS build error - whenDefined 返回 Promise<CustomElementConstructor>\nexport function whenDefined(name: string): Promise<CustomElementConstructor> {\n if (!supportsWebComponents()) {\n return Promise.reject(new Error('Web Components not supported'));\n }\n return customElements.whenDefined(name);\n}\n\n/**\n * 检查自定义元素是否已定义\n */\nexport function isDefined(name: string): boolean {\n if (!supportsWebComponents()) return false;\n return !!customElements.get(name);\n}\n\n/**\n * 升级页面中所有未升级的自定义元素\n */\nexport function upgradeAll(root: HTMLElement = document.body): void {\n if (!supportsWebComponents()) return;\n customElements.upgrade(root);\n}\n\n// ============================================================\n// 导出\n// ============================================================\n\nexport { camelToKebab, kebabToCamel };\n"]}
|
package/package.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"name": "@lytjs/dom",
|
|
4
|
-
"version": "6.
|
|
5
|
-
"description": "LytJS DOM utilities - Web Components integration and DOM enhancements",
|
|
6
|
-
"author": "lytjs",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"type": "module",
|
|
9
|
-
"main": "./dist/index.cjs",
|
|
10
|
-
"module": "./dist/index.mjs",
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"exports": {
|
|
13
|
-
".": {
|
|
14
|
-
"types": "./dist/index.d.ts",
|
|
15
|
-
"import": "./dist/index.mjs",
|
|
16
|
-
"require": "./dist/index.cjs"
|
|
17
|
-
},
|
|
18
|
-
"./package.json": "./package.json"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist",
|
|
22
|
-
"README.md"
|
|
23
|
-
],
|
|
24
|
-
"sideEffects": false,
|
|
25
|
-
"scripts": {
|
|
26
|
-
"dev": "tsup --watch",
|
|
27
|
-
"build": "tsup",
|
|
28
|
-
"test": "vitest run",
|
|
29
|
-
"test:watch": "vitest",
|
|
30
|
-
"test:coverage": "vitest run --coverage",
|
|
31
|
-
"type-check": "tsc --noEmit",
|
|
32
|
-
"clean": "rm -rf dist node_modules .turbo"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"@lytjs/common-is": "
|
|
36
|
-
"@lytjs/common-string": "
|
|
37
|
-
},
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"tsup": "^8.3.6",
|
|
40
|
-
"typescript": "^5.7.3",
|
|
41
|
-
"vitest": "^3.0.0"
|
|
42
|
-
},
|
|
43
|
-
"peerDependencies": {},
|
|
44
|
-
"publishConfig": {
|
|
45
|
-
"access": "public",
|
|
46
|
-
"registry": "https://registry.npmjs.org/"
|
|
47
|
-
},
|
|
48
|
-
"repository": {
|
|
49
|
-
"type": "git",
|
|
50
|
-
"url": "https://gitee.com/lytjs/lytjs.git",
|
|
51
|
-
"directory": "packages/dom"
|
|
52
|
-
},
|
|
53
|
-
"keywords": [
|
|
54
|
-
"lytjs",
|
|
55
|
-
"dom",
|
|
56
|
-
"web-components"
|
|
57
|
-
],
|
|
58
|
-
"homepage": "https://gitee.com/lytjs/lytjs/tree/develop/packages/dom#readme",
|
|
59
|
-
"bugs": {
|
|
60
|
-
"url": "https://gitee.com/lytjs/lytjs/issues"
|
|
61
|
-
}
|
|
62
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"name": "@lytjs/dom",
|
|
4
|
+
"version": "6.6.0",
|
|
5
|
+
"description": "LytJS DOM utilities - Web Components integration and DOM enhancements",
|
|
6
|
+
"author": "lytjs",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.mjs",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"scripts": {
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"test:coverage": "vitest run --coverage",
|
|
31
|
+
"type-check": "tsc --noEmit",
|
|
32
|
+
"clean": "rm -rf dist node_modules .turbo"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@lytjs/common-is": "workspace:*",
|
|
36
|
+
"@lytjs/common-string": "workspace:*"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"tsup": "^8.3.6",
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"vitest": "^3.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"registry": "https://registry.npmjs.org/"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://gitee.com/lytjs/lytjs.git",
|
|
51
|
+
"directory": "packages/dom"
|
|
52
|
+
},
|
|
53
|
+
"keywords": [
|
|
54
|
+
"lytjs",
|
|
55
|
+
"dom",
|
|
56
|
+
"web-components"
|
|
57
|
+
],
|
|
58
|
+
"homepage": "https://gitee.com/lytjs/lytjs/tree/develop/packages/dom#readme",
|
|
59
|
+
"bugs": {
|
|
60
|
+
"url": "https://gitee.com/lytjs/lytjs/issues"
|
|
61
|
+
}
|
|
62
|
+
}
|