@lingxia/elements 0.5.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/dist/component.d.ts +50 -0
- package/dist/component.js +139 -0
- package/dist/dom.d.ts +10 -0
- package/dist/dom.js +70 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/input.d.ts +117 -0
- package/dist/input.js +699 -0
- package/dist/native_component_wrapper_shared.d.ts +74 -0
- package/dist/native_component_wrapper_shared.js +193 -0
- package/dist/nativecomponent.d.ts +6 -0
- package/dist/nativecomponent.js +82 -0
- package/dist/navigator.d.ts +83 -0
- package/dist/navigator.js +388 -0
- package/dist/picker-web.d.ts +2 -0
- package/dist/picker-web.js +727 -0
- package/dist/picker.d.ts +77 -0
- package/dist/picker.js +342 -0
- package/dist/platform.d.ts +6 -0
- package/dist/platform.js +24 -0
- package/dist/text_component_native_attrs.d.ts +53 -0
- package/dist/text_component_native_attrs.js +111 -0
- package/dist/text_component_shared.d.ts +7 -0
- package/dist/text_component_shared.js +148 -0
- package/dist/textarea.d.ts +129 -0
- package/dist/textarea.js +841 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.js +1 -0
- package/dist/video.d.ts +134 -0
- package/dist/video.js +741 -0
- package/package.json +39 -0
- package/src/component.ts +164 -0
- package/src/dom.ts +83 -0
- package/src/index.ts +69 -0
- package/src/input.ts +799 -0
- package/src/native_component_wrapper_shared.ts +243 -0
- package/src/nativecomponent.ts +97 -0
- package/src/navigator.ts +533 -0
- package/src/picker-web.ts +719 -0
- package/src/picker.ts +418 -0
- package/src/platform.ts +25 -0
- package/src/text_component_native_attrs.ts +137 -0
- package/src/text_component_shared.ts +147 -0
- package/src/textarea.ts +959 -0
- package/src/types.ts +20 -0
- package/src/video.ts +855 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
// LxNavigator - Navigation component for LingXia apps
|
|
2
|
+
// Similar to WeChat mini program navigator component
|
|
3
|
+
// Component implementation
|
|
4
|
+
export class LxNavigatorElement extends HTMLElement {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.hoverClass = 'navigator-hover';
|
|
8
|
+
this.hoverStopPropagation = false;
|
|
9
|
+
this.hoverStartTime = 20;
|
|
10
|
+
this.hoverStayTime = 70;
|
|
11
|
+
this.hoverTimer = null;
|
|
12
|
+
this.isHovering = false;
|
|
13
|
+
this.onClick = (e) => this.handleClick(e);
|
|
14
|
+
this.onTouchStart = (e) => this.handleTouchStart(e);
|
|
15
|
+
this.onTouchEnd = (e) => this.handleTouchEnd(e);
|
|
16
|
+
this.onTouchCancel = (e) => this.handleTouchCancel(e);
|
|
17
|
+
this.onMouseEnter = (e) => this.handleMouseEnter(e);
|
|
18
|
+
this.onMouseLeave = (e) => this.handleMouseLeave(e);
|
|
19
|
+
this.clickListener = {
|
|
20
|
+
handleEvent: (event) => this.onClick(event),
|
|
21
|
+
};
|
|
22
|
+
this.touchStartListener = {
|
|
23
|
+
handleEvent: (event) => this.onTouchStart(event),
|
|
24
|
+
};
|
|
25
|
+
this.touchEndListener = {
|
|
26
|
+
handleEvent: (event) => this.onTouchEnd(event),
|
|
27
|
+
};
|
|
28
|
+
this.touchCancelListener = {
|
|
29
|
+
handleEvent: (event) => this.onTouchCancel(event),
|
|
30
|
+
};
|
|
31
|
+
this.mouseEnterListener = {
|
|
32
|
+
handleEvent: (event) => this.onMouseEnter(event),
|
|
33
|
+
};
|
|
34
|
+
this.mouseLeaveListener = {
|
|
35
|
+
handleEvent: (event) => this.onMouseLeave(event),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
static get observedAttributes() {
|
|
39
|
+
return [
|
|
40
|
+
"url",
|
|
41
|
+
"open-type",
|
|
42
|
+
"target",
|
|
43
|
+
"delta",
|
|
44
|
+
"app-id",
|
|
45
|
+
"path",
|
|
46
|
+
"phone-number",
|
|
47
|
+
"hover-class",
|
|
48
|
+
"hover-stop-propagation",
|
|
49
|
+
"hover-start-time",
|
|
50
|
+
"hover-stay-time"
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
connectedCallback() {
|
|
54
|
+
this.setupHoverEffect();
|
|
55
|
+
this.setupClickHandler();
|
|
56
|
+
this.applyDefaultStyles();
|
|
57
|
+
}
|
|
58
|
+
disconnectedCallback() {
|
|
59
|
+
this.clearHoverTimer();
|
|
60
|
+
this.removeEventListener('click', this.clickListener);
|
|
61
|
+
this.removeEventListener('touchstart', this.touchStartListener);
|
|
62
|
+
this.removeEventListener('touchend', this.touchEndListener);
|
|
63
|
+
this.removeEventListener('touchcancel', this.touchCancelListener);
|
|
64
|
+
this.removeEventListener('mouseenter', this.mouseEnterListener);
|
|
65
|
+
this.removeEventListener('mouseleave', this.mouseLeaveListener);
|
|
66
|
+
}
|
|
67
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
68
|
+
if (oldValue === newValue)
|
|
69
|
+
return;
|
|
70
|
+
switch (name) {
|
|
71
|
+
case 'hover-class':
|
|
72
|
+
this.hoverClass = newValue || 'navigator-hover';
|
|
73
|
+
break;
|
|
74
|
+
case 'hover-stop-propagation':
|
|
75
|
+
this.hoverStopPropagation = newValue === 'true';
|
|
76
|
+
break;
|
|
77
|
+
case 'hover-start-time':
|
|
78
|
+
this.hoverStartTime = parseInt(newValue || '20', 10);
|
|
79
|
+
break;
|
|
80
|
+
case 'hover-stay-time':
|
|
81
|
+
this.hoverStayTime = parseInt(newValue || '70', 10);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
applyDefaultStyles() {
|
|
86
|
+
if (!this.hasAttribute('style') && !this.className) {
|
|
87
|
+
this.style.display = 'inline-block';
|
|
88
|
+
this.style.cursor = 'pointer';
|
|
89
|
+
this.style.userSelect = 'none';
|
|
90
|
+
this.style.webkitTapHighlightColor = 'transparent';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
setupHoverEffect() {
|
|
94
|
+
this.addEventListener('touchstart', this.touchStartListener, { passive: true });
|
|
95
|
+
this.addEventListener('touchend', this.touchEndListener, { passive: true });
|
|
96
|
+
this.addEventListener('touchcancel', this.touchCancelListener, { passive: true });
|
|
97
|
+
// Desktop hover
|
|
98
|
+
this.addEventListener('mouseenter', this.mouseEnterListener);
|
|
99
|
+
this.addEventListener('mouseleave', this.mouseLeaveListener);
|
|
100
|
+
}
|
|
101
|
+
setupClickHandler() {
|
|
102
|
+
this.addEventListener('click', this.clickListener);
|
|
103
|
+
}
|
|
104
|
+
handleTouchStart(e) {
|
|
105
|
+
if (this.hoverStopPropagation) {
|
|
106
|
+
e.stopPropagation();
|
|
107
|
+
}
|
|
108
|
+
this.clearHoverTimer();
|
|
109
|
+
this.hoverTimer = window.setTimeout(() => {
|
|
110
|
+
this.addHoverClass();
|
|
111
|
+
}, this.hoverStartTime);
|
|
112
|
+
}
|
|
113
|
+
handleTouchEnd(_e) {
|
|
114
|
+
this.clearHoverTimer();
|
|
115
|
+
if (this.isHovering) {
|
|
116
|
+
window.setTimeout(() => {
|
|
117
|
+
this.removeHoverClass();
|
|
118
|
+
}, this.hoverStayTime);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
handleTouchCancel(_e) {
|
|
122
|
+
this.clearHoverTimer();
|
|
123
|
+
this.removeHoverClass();
|
|
124
|
+
}
|
|
125
|
+
handleMouseEnter(_e) {
|
|
126
|
+
this.clearHoverTimer();
|
|
127
|
+
this.hoverTimer = window.setTimeout(() => {
|
|
128
|
+
this.addHoverClass();
|
|
129
|
+
}, this.hoverStartTime);
|
|
130
|
+
}
|
|
131
|
+
handleMouseLeave(_e) {
|
|
132
|
+
this.clearHoverTimer();
|
|
133
|
+
if (this.isHovering) {
|
|
134
|
+
window.setTimeout(() => {
|
|
135
|
+
this.removeHoverClass();
|
|
136
|
+
}, this.hoverStayTime);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
addHoverClass() {
|
|
140
|
+
if (this.hoverClass && this.hoverClass !== 'none') {
|
|
141
|
+
this.classList.add(this.hoverClass);
|
|
142
|
+
this.isHovering = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
removeHoverClass() {
|
|
146
|
+
if (this.hoverClass && this.hoverClass !== 'none') {
|
|
147
|
+
this.classList.remove(this.hoverClass);
|
|
148
|
+
this.isHovering = false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
clearHoverTimer() {
|
|
152
|
+
if (this.hoverTimer !== null) {
|
|
153
|
+
window.clearTimeout(this.hoverTimer);
|
|
154
|
+
this.hoverTimer = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
handleClick(e) {
|
|
158
|
+
e.preventDefault();
|
|
159
|
+
const url = this.getAttribute('url') || '';
|
|
160
|
+
const openType = (this.getAttribute('open-type') || 'navigate');
|
|
161
|
+
const explicitTarget = this.getAttribute('target');
|
|
162
|
+
const delta = parseInt(this.getAttribute('delta') || '1', 10);
|
|
163
|
+
const appId = this.getAttribute('app-id');
|
|
164
|
+
const path = this.getAttribute('path');
|
|
165
|
+
const phoneNumber = this.getAttribute('phone-number');
|
|
166
|
+
// Auto-infer target if not explicitly specified
|
|
167
|
+
const target = this.inferTarget(explicitTarget, url, appId);
|
|
168
|
+
void this.navigate({
|
|
169
|
+
url,
|
|
170
|
+
openType,
|
|
171
|
+
target,
|
|
172
|
+
delta,
|
|
173
|
+
appId,
|
|
174
|
+
path,
|
|
175
|
+
phoneNumber
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Auto-infer navigation target based on context
|
|
180
|
+
* Priority: explicit target > appId > HTTPS URL > default (self)
|
|
181
|
+
*/
|
|
182
|
+
inferTarget(explicitTarget, url, appId) {
|
|
183
|
+
// 1. Explicit target has highest priority
|
|
184
|
+
if (explicitTarget) {
|
|
185
|
+
return explicitTarget;
|
|
186
|
+
}
|
|
187
|
+
// 2. If appId is specified, target is another lxapp
|
|
188
|
+
if (appId) {
|
|
189
|
+
return 'lxapp';
|
|
190
|
+
}
|
|
191
|
+
// 3. If URL starts with http:// or https://, open in browser
|
|
192
|
+
if (/^https?:\/\//i.test(url)) {
|
|
193
|
+
return 'browser';
|
|
194
|
+
}
|
|
195
|
+
// 4. Default: navigate within current lxapp
|
|
196
|
+
return 'self';
|
|
197
|
+
}
|
|
198
|
+
async navigate(options) {
|
|
199
|
+
try {
|
|
200
|
+
await this.performNavigation(options);
|
|
201
|
+
this.dispatchSuccess();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
this.dispatchFail(error);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
dispatchSuccess() {
|
|
208
|
+
const successEvent = new CustomEvent('success', {
|
|
209
|
+
detail: {
|
|
210
|
+
success: true
|
|
211
|
+
},
|
|
212
|
+
bubbles: true,
|
|
213
|
+
composed: true
|
|
214
|
+
});
|
|
215
|
+
this.dispatchEvent(successEvent);
|
|
216
|
+
const completeEvent = new CustomEvent('complete', {
|
|
217
|
+
detail: {
|
|
218
|
+
success: true
|
|
219
|
+
},
|
|
220
|
+
bubbles: true,
|
|
221
|
+
composed: true
|
|
222
|
+
});
|
|
223
|
+
this.dispatchEvent(completeEvent);
|
|
224
|
+
}
|
|
225
|
+
resolveErrorMessage(error) {
|
|
226
|
+
if (error instanceof Error) {
|
|
227
|
+
const message = error.message.trim();
|
|
228
|
+
return message || 'Unknown error';
|
|
229
|
+
}
|
|
230
|
+
if (typeof error === 'string') {
|
|
231
|
+
const message = error.trim();
|
|
232
|
+
return message || 'Unknown error';
|
|
233
|
+
}
|
|
234
|
+
if (error && typeof error === 'object') {
|
|
235
|
+
const message = error.message;
|
|
236
|
+
if (typeof message === 'string' && message.trim()) {
|
|
237
|
+
return message;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return 'Unknown error';
|
|
241
|
+
}
|
|
242
|
+
dispatchFail(error) {
|
|
243
|
+
const errMsg = this.resolveErrorMessage(error);
|
|
244
|
+
const failEvent = new CustomEvent('fail', {
|
|
245
|
+
detail: {
|
|
246
|
+
success: false,
|
|
247
|
+
errMsg
|
|
248
|
+
},
|
|
249
|
+
bubbles: true,
|
|
250
|
+
composed: true
|
|
251
|
+
});
|
|
252
|
+
this.dispatchEvent(failEvent);
|
|
253
|
+
const completeEvent = new CustomEvent('complete', {
|
|
254
|
+
detail: {
|
|
255
|
+
success: false,
|
|
256
|
+
errMsg
|
|
257
|
+
},
|
|
258
|
+
bubbles: true,
|
|
259
|
+
composed: true
|
|
260
|
+
});
|
|
261
|
+
this.dispatchEvent(completeEvent);
|
|
262
|
+
}
|
|
263
|
+
getHostApi() {
|
|
264
|
+
const host = window.host;
|
|
265
|
+
if (!host || typeof host !== 'object') {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
return host;
|
|
269
|
+
}
|
|
270
|
+
async performNavigation(options) {
|
|
271
|
+
var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
272
|
+
const host = this.getHostApi();
|
|
273
|
+
if (!host) {
|
|
274
|
+
throw new Error('LingXia bridge not available');
|
|
275
|
+
}
|
|
276
|
+
const url = options.url || '';
|
|
277
|
+
const delta = Number.isFinite(options.delta) && options.delta > 0 ? options.delta : 1;
|
|
278
|
+
if (options.openType === 'tel') {
|
|
279
|
+
if (!options.phoneNumber) {
|
|
280
|
+
throw new Error('tel requires phone-number attribute');
|
|
281
|
+
}
|
|
282
|
+
if (typeof ((_a = host.device) === null || _a === void 0 ? void 0 : _a.makePhoneCall) !== 'function') {
|
|
283
|
+
throw new Error('host.device.makePhoneCall is not available');
|
|
284
|
+
}
|
|
285
|
+
await host.device.makePhoneCall({ phoneNumber: options.phoneNumber });
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (options.openType === 'exit') {
|
|
289
|
+
if (typeof ((_b = host.navigator) === null || _b === void 0 ? void 0 : _b.navigateBackLxApp) !== 'function') {
|
|
290
|
+
throw new Error('host.navigator.navigateBackLxApp is not available');
|
|
291
|
+
}
|
|
292
|
+
await host.navigator.navigateBackLxApp();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (options.openType === 'navigateBack') {
|
|
296
|
+
if (options.target === 'lxapp') {
|
|
297
|
+
if (typeof ((_c = host.navigator) === null || _c === void 0 ? void 0 : _c.navigateBackLxApp) !== 'function') {
|
|
298
|
+
throw new Error('host.navigator.navigateBackLxApp is not available');
|
|
299
|
+
}
|
|
300
|
+
await host.navigator.navigateBackLxApp();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (options.target === 'browser') {
|
|
304
|
+
throw new Error('navigateBack is not supported for browser target');
|
|
305
|
+
}
|
|
306
|
+
if (typeof ((_d = host.navigation) === null || _d === void 0 ? void 0 : _d.navigateBack) !== 'function') {
|
|
307
|
+
throw new Error('host.navigation.navigateBack is not available');
|
|
308
|
+
}
|
|
309
|
+
await host.navigation.navigateBack({ delta });
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (options.target === 'browser') {
|
|
313
|
+
if (!url) {
|
|
314
|
+
throw new Error('openUrl requires url');
|
|
315
|
+
}
|
|
316
|
+
if (typeof ((_f = host.device) === null || _f === void 0 ? void 0 : _f.openUrl) !== 'function') {
|
|
317
|
+
throw new Error('host.device.openUrl is not available');
|
|
318
|
+
}
|
|
319
|
+
await host.device.openUrl({ url, target: 'external' });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (options.target === 'lxapp') {
|
|
323
|
+
if (!options.appId) {
|
|
324
|
+
throw new Error('navigateToLxApp requires app-id');
|
|
325
|
+
}
|
|
326
|
+
const lxappPath = options.path || '';
|
|
327
|
+
if (typeof ((_g = host.navigator) === null || _g === void 0 ? void 0 : _g.navigateToLxApp) !== 'function') {
|
|
328
|
+
throw new Error('host.navigator.navigateToLxApp is not available');
|
|
329
|
+
}
|
|
330
|
+
await host.navigator.navigateToLxApp({ appId: options.appId, path: lxappPath });
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (options.target === 'self' && /^https?:\/\//i.test(url)) {
|
|
334
|
+
if (!url) {
|
|
335
|
+
throw new Error('openUrl requires url');
|
|
336
|
+
}
|
|
337
|
+
if (typeof ((_h = host.device) === null || _h === void 0 ? void 0 : _h.openUrl) !== 'function') {
|
|
338
|
+
throw new Error('host.device.openUrl is not available');
|
|
339
|
+
}
|
|
340
|
+
await host.device.openUrl({ url, target: 'self' });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (!url) {
|
|
344
|
+
throw new Error(`${options.openType} requires url`);
|
|
345
|
+
}
|
|
346
|
+
switch (options.openType) {
|
|
347
|
+
case 'navigate':
|
|
348
|
+
if (typeof ((_j = host.navigation) === null || _j === void 0 ? void 0 : _j.navigateTo) !== 'function') {
|
|
349
|
+
throw new Error('host.navigation.navigateTo is not available');
|
|
350
|
+
}
|
|
351
|
+
await host.navigation.navigateTo({ url });
|
|
352
|
+
break;
|
|
353
|
+
case 'redirect':
|
|
354
|
+
if (typeof ((_k = host.navigation) === null || _k === void 0 ? void 0 : _k.redirectTo) !== 'function') {
|
|
355
|
+
throw new Error('host.navigation.redirectTo is not available');
|
|
356
|
+
}
|
|
357
|
+
await host.navigation.redirectTo({ url });
|
|
358
|
+
break;
|
|
359
|
+
case 'switchTab':
|
|
360
|
+
if (typeof ((_l = host.navigation) === null || _l === void 0 ? void 0 : _l.switchTab) !== 'function') {
|
|
361
|
+
throw new Error('host.navigation.switchTab is not available');
|
|
362
|
+
}
|
|
363
|
+
await host.navigation.switchTab({ url });
|
|
364
|
+
break;
|
|
365
|
+
case 'reLaunch':
|
|
366
|
+
if (typeof ((_m = host.navigation) === null || _m === void 0 ? void 0 : _m.reLaunch) !== 'function') {
|
|
367
|
+
throw new Error('host.navigation.reLaunch is not available');
|
|
368
|
+
}
|
|
369
|
+
await host.navigation.reLaunch({ url });
|
|
370
|
+
break;
|
|
371
|
+
case 'openUrl':
|
|
372
|
+
if (typeof ((_o = host.device) === null || _o === void 0 ? void 0 : _o.openUrl) !== 'function') {
|
|
373
|
+
throw new Error('host.device.openUrl is not available');
|
|
374
|
+
}
|
|
375
|
+
await host.device.openUrl({
|
|
376
|
+
url,
|
|
377
|
+
target: options.target === 'self' ? 'self' : 'external'
|
|
378
|
+
});
|
|
379
|
+
break;
|
|
380
|
+
default:
|
|
381
|
+
throw new Error(`Unsupported openType: ${options.openType}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// Register custom element
|
|
386
|
+
if (typeof customElements !== 'undefined' && !customElements.get('lx-navigator')) {
|
|
387
|
+
customElements.define('lx-navigator', LxNavigatorElement);
|
|
388
|
+
}
|