@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.
Files changed (46) hide show
  1. package/dist/component.d.ts +50 -0
  2. package/dist/component.js +139 -0
  3. package/dist/dom.d.ts +10 -0
  4. package/dist/dom.js +70 -0
  5. package/dist/index.d.ts +9 -0
  6. package/dist/index.js +9 -0
  7. package/dist/input.d.ts +117 -0
  8. package/dist/input.js +699 -0
  9. package/dist/native_component_wrapper_shared.d.ts +74 -0
  10. package/dist/native_component_wrapper_shared.js +193 -0
  11. package/dist/nativecomponent.d.ts +6 -0
  12. package/dist/nativecomponent.js +82 -0
  13. package/dist/navigator.d.ts +83 -0
  14. package/dist/navigator.js +388 -0
  15. package/dist/picker-web.d.ts +2 -0
  16. package/dist/picker-web.js +727 -0
  17. package/dist/picker.d.ts +77 -0
  18. package/dist/picker.js +342 -0
  19. package/dist/platform.d.ts +6 -0
  20. package/dist/platform.js +24 -0
  21. package/dist/text_component_native_attrs.d.ts +53 -0
  22. package/dist/text_component_native_attrs.js +111 -0
  23. package/dist/text_component_shared.d.ts +7 -0
  24. package/dist/text_component_shared.js +148 -0
  25. package/dist/textarea.d.ts +129 -0
  26. package/dist/textarea.js +841 -0
  27. package/dist/types.d.ts +21 -0
  28. package/dist/types.js +1 -0
  29. package/dist/video.d.ts +134 -0
  30. package/dist/video.js +741 -0
  31. package/package.json +39 -0
  32. package/src/component.ts +164 -0
  33. package/src/dom.ts +83 -0
  34. package/src/index.ts +69 -0
  35. package/src/input.ts +799 -0
  36. package/src/native_component_wrapper_shared.ts +243 -0
  37. package/src/nativecomponent.ts +97 -0
  38. package/src/navigator.ts +533 -0
  39. package/src/picker-web.ts +719 -0
  40. package/src/picker.ts +418 -0
  41. package/src/platform.ts +25 -0
  42. package/src/text_component_native_attrs.ts +137 -0
  43. package/src/text_component_shared.ts +147 -0
  44. package/src/textarea.ts +959 -0
  45. package/src/types.ts +20 -0
  46. 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
+ }
@@ -0,0 +1,2 @@
1
+ import type { LxPickerEventDetail } from './picker.js';
2
+ export declare function renderWebPicker(host: HTMLElement, props: Record<string, any>, onChange: (d: LxPickerEventDetail) => void): () => void;