@lingxia/elements 0.5.1 → 0.6.3
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/index.d.ts +1 -1
- package/dist/native_component_wrapper_shared.d.ts +6 -1
- package/dist/native_component_wrapper_shared.js +8 -0
- package/dist/navigator.d.ts +12 -2
- package/dist/navigator.js +70 -64
- package/package.json +1 -1
- package/src/index.ts +3 -0
- package/src/native_component_wrapper_shared.ts +10 -1
- package/src/navigator.ts +102 -84
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { registerVideoComponent, LxVideoElement, type LxVideoAttributes, } from
|
|
|
2
2
|
export { registerPickerComponent, LxPickerElement, type LxPickerAttributes, type LxPickerColumn, type LxPickerCascadingColumns, type LxPickerEvent, type LxPickerEventDetail, } from "./picker.js";
|
|
3
3
|
export { registerInputComponent, LxInputElement, type LxInputAttributes, type LxInputEvent, type LxInputEventDetail, } from "./input.js";
|
|
4
4
|
export { registerTextareaComponent, LxTextareaElement, type LxTextareaAttributes, type LxTextareaEvent, type LxTextareaEventDetail, } from "./textarea.js";
|
|
5
|
-
export { LxNavigatorElement, type LxNavigatorAttributes, type LxNavigatorEvent, type NavigatorOpenType, type NavigatorTarget, } from "./navigator.js";
|
|
5
|
+
export { LxNavigatorElement, type LxNavigatorAttributes, type LxNavigatorEvent, type NavigatorEnvVersion, type NavigatorOpenType, type NavigatorQuery, type NavigatorQueryValue, type NavigatorTarget, } from "./navigator.js";
|
|
6
6
|
export { buildVideoNativeAttrs, buildNavigatorNativeAttrs, buildPickerNativeAttrs, getPickerDisplayText, getPickerValueFromIndex, VIDEO_DOM_EVENT_MAP, } from "./native_component_wrapper_shared.js";
|
|
7
7
|
export { buildInputNativeAttrs, buildTextareaNativeAttrs, } from "./text_component_native_attrs.js";
|
|
8
8
|
export { isHarmony, isIOS, isAndroid, isMacOS, isDesktop, getOS, } from "./platform.js";
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import type { NavigatorOpenType, NavigatorTarget } from "./navigator.js";
|
|
1
|
+
import type { NavigatorEnvVersion, NavigatorOpenType, NavigatorTarget } from "./navigator.js";
|
|
2
|
+
import type { NavigatorQuery } from "./navigator.js";
|
|
2
3
|
import type { LxVideoQuality } from "./video.js";
|
|
3
4
|
export declare function appendDataAttrs(attrs: Record<string, unknown>, target: Record<string, string>): void;
|
|
4
5
|
export declare function appendPassthroughAttrs(attrs: Record<string, unknown>, target: Record<string, string>): void;
|
|
5
6
|
export interface NavigatorNativeAttrOptions {
|
|
6
7
|
url?: string;
|
|
8
|
+
page?: string;
|
|
7
9
|
openType?: NavigatorOpenType;
|
|
8
10
|
target?: NavigatorTarget;
|
|
9
11
|
delta?: number;
|
|
10
12
|
appId?: string;
|
|
11
13
|
path?: string;
|
|
14
|
+
query?: NavigatorQuery;
|
|
15
|
+
envVersion?: NavigatorEnvVersion;
|
|
16
|
+
targetVersion?: string;
|
|
12
17
|
phoneNumber?: string;
|
|
13
18
|
hoverClass?: string;
|
|
14
19
|
hoverStopPropagation?: boolean;
|
|
@@ -35,12 +35,20 @@ export function buildNavigatorNativeAttrs(options, extraAttrs = {}) {
|
|
|
35
35
|
};
|
|
36
36
|
if (options.url)
|
|
37
37
|
result.url = options.url;
|
|
38
|
+
if (options.page)
|
|
39
|
+
result.page = options.page;
|
|
38
40
|
if (options.target)
|
|
39
41
|
result.target = options.target;
|
|
40
42
|
if (options.appId)
|
|
41
43
|
result["app-id"] = options.appId;
|
|
42
44
|
if (options.path)
|
|
43
45
|
result.path = options.path;
|
|
46
|
+
if (options.query)
|
|
47
|
+
result.query = JSON.stringify(options.query);
|
|
48
|
+
if (options.envVersion)
|
|
49
|
+
result["env-version"] = options.envVersion;
|
|
50
|
+
if (options.targetVersion)
|
|
51
|
+
result["target-version"] = options.targetVersion;
|
|
44
52
|
if (options.phoneNumber)
|
|
45
53
|
result["phone-number"] = options.phoneNumber;
|
|
46
54
|
appendPassthroughAttrs(extraAttrs, result);
|
package/dist/navigator.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export type NavigatorOpenType = 'navigate' | 'redirect' | 'navigateBack' | 'reLaunch' | 'switchTab' | 'exit' | 'openUrl' | 'tel';
|
|
2
2
|
export type NavigatorTarget = 'self' | 'lxapp' | 'browser';
|
|
3
|
+
export type NavigatorQueryValue = string | number | boolean | null | undefined;
|
|
4
|
+
export type NavigatorQuery = Record<string, NavigatorQueryValue>;
|
|
5
|
+
export type NavigatorEnvVersion = 'release' | 'preview' | 'develop';
|
|
3
6
|
export interface LxNavigatorEventDetail {
|
|
4
7
|
success?: boolean;
|
|
5
8
|
errMsg?: string;
|
|
@@ -9,11 +12,15 @@ export interface LxNavigatorEvent extends CustomEvent<LxNavigatorEventDetail> {
|
|
|
9
12
|
}
|
|
10
13
|
export type LxNavigatorAttributes = {
|
|
11
14
|
url?: string;
|
|
15
|
+
page?: string;
|
|
16
|
+
path?: string;
|
|
17
|
+
query?: string;
|
|
12
18
|
'open-type'?: NavigatorOpenType;
|
|
13
19
|
target?: NavigatorTarget;
|
|
14
20
|
delta?: number;
|
|
15
21
|
'app-id'?: string;
|
|
16
|
-
|
|
22
|
+
'env-version'?: NavigatorEnvVersion;
|
|
23
|
+
'target-version'?: string;
|
|
17
24
|
'phone-number'?: string;
|
|
18
25
|
'hover-class'?: string;
|
|
19
26
|
'hover-stop-propagation'?: boolean;
|
|
@@ -78,6 +85,9 @@ export declare class LxNavigatorElement extends HTMLElement {
|
|
|
78
85
|
private dispatchSuccess;
|
|
79
86
|
private resolveErrorMessage;
|
|
80
87
|
private dispatchFail;
|
|
81
|
-
private
|
|
88
|
+
private callHost;
|
|
82
89
|
private performNavigation;
|
|
90
|
+
private readQuery;
|
|
91
|
+
private buildPageTarget;
|
|
92
|
+
private buildLxAppTarget;
|
|
83
93
|
}
|
package/dist/navigator.js
CHANGED
|
@@ -38,11 +38,15 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
38
38
|
static get observedAttributes() {
|
|
39
39
|
return [
|
|
40
40
|
"url",
|
|
41
|
+
"page",
|
|
42
|
+
"path",
|
|
43
|
+
"query",
|
|
41
44
|
"open-type",
|
|
42
45
|
"target",
|
|
43
46
|
"delta",
|
|
44
47
|
"app-id",
|
|
45
|
-
"
|
|
48
|
+
"env-version",
|
|
49
|
+
"target-version",
|
|
46
50
|
"phone-number",
|
|
47
51
|
"hover-class",
|
|
48
52
|
"hover-stop-propagation",
|
|
@@ -157,21 +161,29 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
157
161
|
handleClick(e) {
|
|
158
162
|
e.preventDefault();
|
|
159
163
|
const url = this.getAttribute('url') || '';
|
|
164
|
+
const page = this.getAttribute('page');
|
|
165
|
+
const path = this.getAttribute('path');
|
|
166
|
+
const query = this.getAttribute('query');
|
|
160
167
|
const openType = (this.getAttribute('open-type') || 'navigate');
|
|
161
168
|
const explicitTarget = this.getAttribute('target');
|
|
162
169
|
const delta = parseInt(this.getAttribute('delta') || '1', 10);
|
|
163
170
|
const appId = this.getAttribute('app-id');
|
|
164
|
-
const
|
|
171
|
+
const envVersion = this.getAttribute('env-version');
|
|
172
|
+
const targetVersion = this.getAttribute('target-version');
|
|
165
173
|
const phoneNumber = this.getAttribute('phone-number');
|
|
166
174
|
// Auto-infer target if not explicitly specified
|
|
167
175
|
const target = this.inferTarget(explicitTarget, url, appId);
|
|
168
176
|
void this.navigate({
|
|
169
177
|
url,
|
|
178
|
+
page,
|
|
179
|
+
path,
|
|
180
|
+
query,
|
|
170
181
|
openType,
|
|
171
182
|
target,
|
|
172
183
|
delta,
|
|
173
184
|
appId,
|
|
174
|
-
|
|
185
|
+
envVersion,
|
|
186
|
+
targetVersion,
|
|
175
187
|
phoneNumber
|
|
176
188
|
});
|
|
177
189
|
}
|
|
@@ -260,119 +272,78 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
260
272
|
});
|
|
261
273
|
this.dispatchEvent(completeEvent);
|
|
262
274
|
}
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
if (!
|
|
266
|
-
return
|
|
275
|
+
callHost(route, params) {
|
|
276
|
+
const bridge = window.LingXiaBridge;
|
|
277
|
+
if (!bridge || typeof bridge.invoke !== 'function') {
|
|
278
|
+
return Promise.reject(new Error('LingXiaBridge is not available'));
|
|
267
279
|
}
|
|
268
|
-
return
|
|
280
|
+
return bridge.invoke(route, params).then(() => undefined);
|
|
269
281
|
}
|
|
270
282
|
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
283
|
const url = options.url || '';
|
|
277
284
|
const delta = Number.isFinite(options.delta) && options.delta > 0 ? options.delta : 1;
|
|
278
285
|
if (options.openType === 'tel') {
|
|
279
286
|
if (!options.phoneNumber) {
|
|
280
287
|
throw new Error('tel requires phone-number attribute');
|
|
281
288
|
}
|
|
282
|
-
|
|
283
|
-
throw new Error('host.device.makePhoneCall is not available');
|
|
284
|
-
}
|
|
285
|
-
await host.device.makePhoneCall({ phoneNumber: options.phoneNumber });
|
|
289
|
+
await this.callHost('device.makePhoneCall', { phoneNumber: options.phoneNumber });
|
|
286
290
|
return;
|
|
287
291
|
}
|
|
288
292
|
if (options.openType === 'exit') {
|
|
289
|
-
|
|
290
|
-
throw new Error('host.navigator.navigateBackLxApp is not available');
|
|
291
|
-
}
|
|
292
|
-
await host.navigator.navigateBackLxApp();
|
|
293
|
+
await this.callHost('navigator.navigateBackLxApp');
|
|
293
294
|
return;
|
|
294
295
|
}
|
|
295
296
|
if (options.openType === 'navigateBack') {
|
|
296
297
|
if (options.target === 'lxapp') {
|
|
297
|
-
|
|
298
|
-
throw new Error('host.navigator.navigateBackLxApp is not available');
|
|
299
|
-
}
|
|
300
|
-
await host.navigator.navigateBackLxApp();
|
|
298
|
+
await this.callHost('navigator.navigateBackLxApp');
|
|
301
299
|
return;
|
|
302
300
|
}
|
|
303
301
|
if (options.target === 'browser') {
|
|
304
302
|
throw new Error('navigateBack is not supported for browser target');
|
|
305
303
|
}
|
|
306
|
-
|
|
307
|
-
throw new Error('host.navigation.navigateBack is not available');
|
|
308
|
-
}
|
|
309
|
-
await host.navigation.navigateBack({ delta });
|
|
304
|
+
await this.callHost('navigation.navigateBack', { delta });
|
|
310
305
|
return;
|
|
311
306
|
}
|
|
312
307
|
if (options.target === 'browser') {
|
|
313
308
|
if (!url) {
|
|
314
309
|
throw new Error('openUrl requires url');
|
|
315
310
|
}
|
|
316
|
-
|
|
317
|
-
throw new Error('host.device.openUrl is not available');
|
|
318
|
-
}
|
|
319
|
-
await host.device.openUrl({ url, target: 'external' });
|
|
311
|
+
await this.callHost('device.openUrl', { url, target: 'external' });
|
|
320
312
|
return;
|
|
321
313
|
}
|
|
322
314
|
if (options.target === 'lxapp') {
|
|
323
315
|
if (!options.appId) {
|
|
324
316
|
throw new Error('navigateToLxApp requires app-id');
|
|
325
317
|
}
|
|
326
|
-
|
|
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 });
|
|
318
|
+
await this.callHost('navigator.navigateToLxApp', this.buildLxAppTarget(options));
|
|
331
319
|
return;
|
|
332
320
|
}
|
|
333
321
|
if (options.target === 'self' && /^https?:\/\//i.test(url)) {
|
|
334
322
|
if (!url) {
|
|
335
323
|
throw new Error('openUrl requires url');
|
|
336
324
|
}
|
|
337
|
-
|
|
338
|
-
throw new Error('host.device.openUrl is not available');
|
|
339
|
-
}
|
|
340
|
-
await host.device.openUrl({ url, target: 'self' });
|
|
325
|
+
await this.callHost('device.openUrl', { url, target: 'self' });
|
|
341
326
|
return;
|
|
342
327
|
}
|
|
343
|
-
|
|
344
|
-
|
|
328
|
+
const target = this.buildPageTarget(options);
|
|
329
|
+
if (!target) {
|
|
330
|
+
throw new Error(`${options.openType} requires page or path`);
|
|
345
331
|
}
|
|
346
332
|
switch (options.openType) {
|
|
347
333
|
case 'navigate':
|
|
348
|
-
|
|
349
|
-
throw new Error('host.navigation.navigateTo is not available');
|
|
350
|
-
}
|
|
351
|
-
await host.navigation.navigateTo({ url });
|
|
334
|
+
await this.callHost('navigation.navigateTo', target);
|
|
352
335
|
break;
|
|
353
336
|
case 'redirect':
|
|
354
|
-
|
|
355
|
-
throw new Error('host.navigation.redirectTo is not available');
|
|
356
|
-
}
|
|
357
|
-
await host.navigation.redirectTo({ url });
|
|
337
|
+
await this.callHost('navigation.redirectTo', target);
|
|
358
338
|
break;
|
|
359
339
|
case 'switchTab':
|
|
360
|
-
|
|
361
|
-
throw new Error('host.navigation.switchTab is not available');
|
|
362
|
-
}
|
|
363
|
-
await host.navigation.switchTab({ url });
|
|
340
|
+
await this.callHost('navigation.switchTab', target);
|
|
364
341
|
break;
|
|
365
342
|
case 'reLaunch':
|
|
366
|
-
|
|
367
|
-
throw new Error('host.navigation.reLaunch is not available');
|
|
368
|
-
}
|
|
369
|
-
await host.navigation.reLaunch({ url });
|
|
343
|
+
await this.callHost('navigation.reLaunch', target);
|
|
370
344
|
break;
|
|
371
345
|
case 'openUrl':
|
|
372
|
-
|
|
373
|
-
throw new Error('host.device.openUrl is not available');
|
|
374
|
-
}
|
|
375
|
-
await host.device.openUrl({
|
|
346
|
+
await this.callHost('device.openUrl', {
|
|
376
347
|
url,
|
|
377
348
|
target: options.target === 'self' ? 'self' : 'external'
|
|
378
349
|
});
|
|
@@ -381,6 +352,41 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
381
352
|
throw new Error(`Unsupported openType: ${options.openType}`);
|
|
382
353
|
}
|
|
383
354
|
}
|
|
355
|
+
readQuery(raw) {
|
|
356
|
+
if (!raw)
|
|
357
|
+
return undefined;
|
|
358
|
+
const parsed = JSON.parse(raw);
|
|
359
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
360
|
+
throw new Error('query must be an object');
|
|
361
|
+
}
|
|
362
|
+
return parsed;
|
|
363
|
+
}
|
|
364
|
+
buildPageTarget(options) {
|
|
365
|
+
var _a, _b;
|
|
366
|
+
const page = (_a = options.page) === null || _a === void 0 ? void 0 : _a.trim();
|
|
367
|
+
const path = (_b = options.path) === null || _b === void 0 ? void 0 : _b.trim();
|
|
368
|
+
if (page && path) {
|
|
369
|
+
throw new Error('pass either page or path, not both');
|
|
370
|
+
}
|
|
371
|
+
if (!page && !path)
|
|
372
|
+
return null;
|
|
373
|
+
const query = this.readQuery(options.query);
|
|
374
|
+
return {
|
|
375
|
+
...(page ? { page } : { path: path }),
|
|
376
|
+
...(query ? { query } : {}),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
buildLxAppTarget(options) {
|
|
380
|
+
const target = { appId: options.appId };
|
|
381
|
+
const pageTarget = this.buildPageTarget(options);
|
|
382
|
+
if (pageTarget)
|
|
383
|
+
Object.assign(target, pageTarget);
|
|
384
|
+
if (options.envVersion)
|
|
385
|
+
target.envVersion = options.envVersion;
|
|
386
|
+
if (options.targetVersion)
|
|
387
|
+
target.targetVersion = options.targetVersion;
|
|
388
|
+
return target;
|
|
389
|
+
}
|
|
384
390
|
}
|
|
385
391
|
// Register custom element
|
|
386
392
|
if (typeof customElements !== 'undefined' && !customElements.get('lx-navigator')) {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { NavigatorOpenType, NavigatorTarget } from "./navigator.js";
|
|
1
|
+
import type { NavigatorEnvVersion, NavigatorOpenType, NavigatorTarget } from "./navigator.js";
|
|
2
|
+
import type { NavigatorQuery } from "./navigator.js";
|
|
2
3
|
import type { LxVideoQuality } from "./video.js";
|
|
3
4
|
|
|
4
5
|
export function appendDataAttrs(
|
|
@@ -31,11 +32,15 @@ export function appendPassthroughAttrs(
|
|
|
31
32
|
|
|
32
33
|
export interface NavigatorNativeAttrOptions {
|
|
33
34
|
url?: string;
|
|
35
|
+
page?: string;
|
|
34
36
|
openType?: NavigatorOpenType;
|
|
35
37
|
target?: NavigatorTarget;
|
|
36
38
|
delta?: number;
|
|
37
39
|
appId?: string;
|
|
38
40
|
path?: string;
|
|
41
|
+
query?: NavigatorQuery;
|
|
42
|
+
envVersion?: NavigatorEnvVersion;
|
|
43
|
+
targetVersion?: string;
|
|
39
44
|
phoneNumber?: string;
|
|
40
45
|
hoverClass?: string;
|
|
41
46
|
hoverStopPropagation?: boolean;
|
|
@@ -57,9 +62,13 @@ export function buildNavigatorNativeAttrs(
|
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
if (options.url) result.url = options.url;
|
|
65
|
+
if (options.page) result.page = options.page;
|
|
60
66
|
if (options.target) result.target = options.target;
|
|
61
67
|
if (options.appId) result["app-id"] = options.appId;
|
|
62
68
|
if (options.path) result.path = options.path;
|
|
69
|
+
if (options.query) result.query = JSON.stringify(options.query);
|
|
70
|
+
if (options.envVersion) result["env-version"] = options.envVersion;
|
|
71
|
+
if (options.targetVersion) result["target-version"] = options.targetVersion;
|
|
63
72
|
if (options.phoneNumber) result["phone-number"] = options.phoneNumber;
|
|
64
73
|
|
|
65
74
|
appendPassthroughAttrs(extraAttrs, result);
|
package/src/navigator.ts
CHANGED
|
@@ -16,6 +16,10 @@ export type NavigatorTarget =
|
|
|
16
16
|
| 'lxapp' // Open another lxapp
|
|
17
17
|
| 'browser'; // Open in external browser
|
|
18
18
|
|
|
19
|
+
export type NavigatorQueryValue = string | number | boolean | null | undefined;
|
|
20
|
+
export type NavigatorQuery = Record<string, NavigatorQueryValue>;
|
|
21
|
+
export type NavigatorEnvVersion = 'release' | 'preview' | 'develop';
|
|
22
|
+
|
|
19
23
|
export interface LxNavigatorEventDetail {
|
|
20
24
|
success?: boolean;
|
|
21
25
|
errMsg?: string;
|
|
@@ -25,16 +29,24 @@ export interface LxNavigatorEvent extends CustomEvent<LxNavigatorEventDetail> {
|
|
|
25
29
|
detail: LxNavigatorEventDetail;
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
type LingXiaBridgeCall = {
|
|
33
|
+
invoke(route: string, params?: unknown): Promise<unknown>;
|
|
34
|
+
};
|
|
35
|
+
|
|
28
36
|
export type LxNavigatorAttributes = {
|
|
29
37
|
// Navigation
|
|
30
|
-
url?: string; //
|
|
38
|
+
url?: string; // Browser URL for openUrl/browser target
|
|
39
|
+
page?: string; // Named page in lxapp.json
|
|
40
|
+
path?: string; // Raw page path, supports query string
|
|
41
|
+
query?: string; // JSON-encoded page query params
|
|
31
42
|
'open-type'?: NavigatorOpenType; // Navigation type
|
|
32
43
|
target?: NavigatorTarget; // Navigation target (auto-inferred if not specified)
|
|
33
44
|
delta?: number; // Pages to go back (for navigateBack)
|
|
34
45
|
|
|
35
46
|
// Open external lxapp
|
|
36
47
|
'app-id'?: string; // Target lxapp ID
|
|
37
|
-
|
|
48
|
+
'env-version'?: NavigatorEnvVersion; // Target lxapp envVersion
|
|
49
|
+
'target-version'?: string; // Exact target lxapp version
|
|
38
50
|
|
|
39
51
|
// Phone call
|
|
40
52
|
'phone-number'?: string; // Phone number for tel open-type
|
|
@@ -72,11 +84,15 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
72
84
|
static get observedAttributes() {
|
|
73
85
|
return [
|
|
74
86
|
"url",
|
|
87
|
+
"page",
|
|
88
|
+
"path",
|
|
89
|
+
"query",
|
|
75
90
|
"open-type",
|
|
76
91
|
"target",
|
|
77
92
|
"delta",
|
|
78
93
|
"app-id",
|
|
79
|
-
"
|
|
94
|
+
"env-version",
|
|
95
|
+
"target-version",
|
|
80
96
|
"phone-number",
|
|
81
97
|
"hover-class",
|
|
82
98
|
"hover-stop-propagation",
|
|
@@ -240,11 +256,15 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
240
256
|
e.preventDefault();
|
|
241
257
|
|
|
242
258
|
const url = this.getAttribute('url') || '';
|
|
259
|
+
const page = this.getAttribute('page');
|
|
260
|
+
const path = this.getAttribute('path');
|
|
261
|
+
const query = this.getAttribute('query');
|
|
243
262
|
const openType = (this.getAttribute('open-type') || 'navigate') as NavigatorOpenType;
|
|
244
263
|
const explicitTarget = this.getAttribute('target') as NavigatorTarget | null;
|
|
245
264
|
const delta = parseInt(this.getAttribute('delta') || '1', 10);
|
|
246
265
|
const appId = this.getAttribute('app-id');
|
|
247
|
-
const
|
|
266
|
+
const envVersion = this.getAttribute('env-version') as NavigatorEnvVersion | null;
|
|
267
|
+
const targetVersion = this.getAttribute('target-version');
|
|
248
268
|
const phoneNumber = this.getAttribute('phone-number');
|
|
249
269
|
|
|
250
270
|
// Auto-infer target if not explicitly specified
|
|
@@ -252,11 +272,15 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
252
272
|
|
|
253
273
|
void this.navigate({
|
|
254
274
|
url,
|
|
275
|
+
page,
|
|
276
|
+
path,
|
|
277
|
+
query,
|
|
255
278
|
openType,
|
|
256
279
|
target,
|
|
257
280
|
delta,
|
|
258
281
|
appId,
|
|
259
|
-
|
|
282
|
+
envVersion,
|
|
283
|
+
targetVersion,
|
|
260
284
|
phoneNumber
|
|
261
285
|
});
|
|
262
286
|
}
|
|
@@ -291,11 +315,15 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
291
315
|
|
|
292
316
|
private async navigate(options: {
|
|
293
317
|
url: string;
|
|
318
|
+
page?: string | null;
|
|
319
|
+
path?: string | null;
|
|
320
|
+
query?: string | null;
|
|
294
321
|
openType: NavigatorOpenType;
|
|
295
322
|
target: NavigatorTarget;
|
|
296
323
|
delta: number;
|
|
297
324
|
appId?: string | null;
|
|
298
|
-
|
|
325
|
+
envVersion?: NavigatorEnvVersion | null;
|
|
326
|
+
targetVersion?: string | null;
|
|
299
327
|
phoneNumber?: string | null;
|
|
300
328
|
}) {
|
|
301
329
|
try {
|
|
@@ -370,44 +398,27 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
370
398
|
this.dispatchEvent(completeEvent);
|
|
371
399
|
}
|
|
372
400
|
|
|
373
|
-
private
|
|
374
|
-
const
|
|
375
|
-
if (!
|
|
376
|
-
return
|
|
401
|
+
private callHost(route: string, params?: unknown): Promise<void> {
|
|
402
|
+
const bridge = (window as unknown as { LingXiaBridge?: LingXiaBridgeCall }).LingXiaBridge;
|
|
403
|
+
if (!bridge || typeof bridge.invoke !== 'function') {
|
|
404
|
+
return Promise.reject(new Error('LingXiaBridge is not available'));
|
|
377
405
|
}
|
|
378
|
-
return
|
|
379
|
-
navigation?: {
|
|
380
|
-
navigateTo?: (params: { url: string }) => Promise<void>;
|
|
381
|
-
navigateBack?: (params: { delta: number }) => Promise<void>;
|
|
382
|
-
redirectTo?: (params: { url: string }) => Promise<void>;
|
|
383
|
-
switchTab?: (params: { url: string }) => Promise<void>;
|
|
384
|
-
reLaunch?: (params: { url: string }) => Promise<void>;
|
|
385
|
-
};
|
|
386
|
-
navigator?: {
|
|
387
|
-
navigateToLxApp?: (params: { appId: string; path?: string }) => Promise<void>;
|
|
388
|
-
navigateBackLxApp?: () => Promise<void>;
|
|
389
|
-
};
|
|
390
|
-
device?: {
|
|
391
|
-
makePhoneCall?: (params: { phoneNumber: string }) => Promise<void>;
|
|
392
|
-
openUrl?: (params: { url: string; target?: 'external' | 'self' | 'new_browser_tab' }) => Promise<void>;
|
|
393
|
-
};
|
|
394
|
-
};
|
|
406
|
+
return bridge.invoke(route, params).then(() => undefined);
|
|
395
407
|
}
|
|
396
408
|
|
|
397
409
|
private async performNavigation(options: {
|
|
398
410
|
url: string;
|
|
411
|
+
page?: string | null;
|
|
412
|
+
path?: string | null;
|
|
413
|
+
query?: string | null;
|
|
399
414
|
openType: NavigatorOpenType;
|
|
400
415
|
target: NavigatorTarget;
|
|
401
416
|
delta: number;
|
|
402
417
|
appId?: string | null;
|
|
403
|
-
|
|
418
|
+
envVersion?: NavigatorEnvVersion | null;
|
|
419
|
+
targetVersion?: string | null;
|
|
404
420
|
phoneNumber?: string | null;
|
|
405
421
|
}) {
|
|
406
|
-
const host = this.getHostApi();
|
|
407
|
-
if (!host) {
|
|
408
|
-
throw new Error('LingXia bridge not available');
|
|
409
|
-
}
|
|
410
|
-
|
|
411
422
|
const url = options.url || '';
|
|
412
423
|
const delta = Number.isFinite(options.delta) && options.delta > 0 ? options.delta : 1;
|
|
413
424
|
|
|
@@ -415,36 +426,24 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
415
426
|
if (!options.phoneNumber) {
|
|
416
427
|
throw new Error('tel requires phone-number attribute');
|
|
417
428
|
}
|
|
418
|
-
|
|
419
|
-
throw new Error('host.device.makePhoneCall is not available');
|
|
420
|
-
}
|
|
421
|
-
await host.device.makePhoneCall({ phoneNumber: options.phoneNumber });
|
|
429
|
+
await this.callHost('device.makePhoneCall', { phoneNumber: options.phoneNumber });
|
|
422
430
|
return;
|
|
423
431
|
}
|
|
424
432
|
|
|
425
433
|
if (options.openType === 'exit') {
|
|
426
|
-
|
|
427
|
-
throw new Error('host.navigator.navigateBackLxApp is not available');
|
|
428
|
-
}
|
|
429
|
-
await host.navigator.navigateBackLxApp();
|
|
434
|
+
await this.callHost('navigator.navigateBackLxApp');
|
|
430
435
|
return;
|
|
431
436
|
}
|
|
432
437
|
|
|
433
438
|
if (options.openType === 'navigateBack') {
|
|
434
439
|
if (options.target === 'lxapp') {
|
|
435
|
-
|
|
436
|
-
throw new Error('host.navigator.navigateBackLxApp is not available');
|
|
437
|
-
}
|
|
438
|
-
await host.navigator.navigateBackLxApp();
|
|
440
|
+
await this.callHost('navigator.navigateBackLxApp');
|
|
439
441
|
return;
|
|
440
442
|
}
|
|
441
443
|
if (options.target === 'browser') {
|
|
442
444
|
throw new Error('navigateBack is not supported for browser target');
|
|
443
445
|
}
|
|
444
|
-
|
|
445
|
-
throw new Error('host.navigation.navigateBack is not available');
|
|
446
|
-
}
|
|
447
|
-
await host.navigation.navigateBack({ delta });
|
|
446
|
+
await this.callHost('navigation.navigateBack', { delta });
|
|
448
447
|
return;
|
|
449
448
|
}
|
|
450
449
|
|
|
@@ -452,10 +451,7 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
452
451
|
if (!url) {
|
|
453
452
|
throw new Error('openUrl requires url');
|
|
454
453
|
}
|
|
455
|
-
|
|
456
|
-
throw new Error('host.device.openUrl is not available');
|
|
457
|
-
}
|
|
458
|
-
await host.device.openUrl({ url, target: 'external' });
|
|
454
|
+
await this.callHost('device.openUrl', { url, target: 'external' });
|
|
459
455
|
return;
|
|
460
456
|
}
|
|
461
457
|
|
|
@@ -463,11 +459,7 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
463
459
|
if (!options.appId) {
|
|
464
460
|
throw new Error('navigateToLxApp requires app-id');
|
|
465
461
|
}
|
|
466
|
-
|
|
467
|
-
if (typeof host.navigator?.navigateToLxApp !== 'function') {
|
|
468
|
-
throw new Error('host.navigator.navigateToLxApp is not available');
|
|
469
|
-
}
|
|
470
|
-
await host.navigator.navigateToLxApp({ appId: options.appId, path: lxappPath });
|
|
462
|
+
await this.callHost('navigator.navigateToLxApp', this.buildLxAppTarget(options));
|
|
471
463
|
return;
|
|
472
464
|
}
|
|
473
465
|
|
|
@@ -475,47 +467,30 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
475
467
|
if (!url) {
|
|
476
468
|
throw new Error('openUrl requires url');
|
|
477
469
|
}
|
|
478
|
-
|
|
479
|
-
throw new Error('host.device.openUrl is not available');
|
|
480
|
-
}
|
|
481
|
-
await host.device.openUrl({ url, target: 'self' });
|
|
470
|
+
await this.callHost('device.openUrl', { url, target: 'self' });
|
|
482
471
|
return;
|
|
483
472
|
}
|
|
484
473
|
|
|
485
|
-
|
|
486
|
-
|
|
474
|
+
const target = this.buildPageTarget(options);
|
|
475
|
+
if (!target) {
|
|
476
|
+
throw new Error(`${options.openType} requires page or path`);
|
|
487
477
|
}
|
|
488
478
|
|
|
489
479
|
switch (options.openType) {
|
|
490
480
|
case 'navigate':
|
|
491
|
-
|
|
492
|
-
throw new Error('host.navigation.navigateTo is not available');
|
|
493
|
-
}
|
|
494
|
-
await host.navigation.navigateTo({ url });
|
|
481
|
+
await this.callHost('navigation.navigateTo', target);
|
|
495
482
|
break;
|
|
496
483
|
case 'redirect':
|
|
497
|
-
|
|
498
|
-
throw new Error('host.navigation.redirectTo is not available');
|
|
499
|
-
}
|
|
500
|
-
await host.navigation.redirectTo({ url });
|
|
484
|
+
await this.callHost('navigation.redirectTo', target);
|
|
501
485
|
break;
|
|
502
486
|
case 'switchTab':
|
|
503
|
-
|
|
504
|
-
throw new Error('host.navigation.switchTab is not available');
|
|
505
|
-
}
|
|
506
|
-
await host.navigation.switchTab({ url });
|
|
487
|
+
await this.callHost('navigation.switchTab', target);
|
|
507
488
|
break;
|
|
508
489
|
case 'reLaunch':
|
|
509
|
-
|
|
510
|
-
throw new Error('host.navigation.reLaunch is not available');
|
|
511
|
-
}
|
|
512
|
-
await host.navigation.reLaunch({ url });
|
|
490
|
+
await this.callHost('navigation.reLaunch', target);
|
|
513
491
|
break;
|
|
514
492
|
case 'openUrl':
|
|
515
|
-
|
|
516
|
-
throw new Error('host.device.openUrl is not available');
|
|
517
|
-
}
|
|
518
|
-
await host.device.openUrl({
|
|
493
|
+
await this.callHost('device.openUrl', {
|
|
519
494
|
url,
|
|
520
495
|
target: options.target === 'self' ? 'self' : 'external'
|
|
521
496
|
});
|
|
@@ -525,6 +500,49 @@ export class LxNavigatorElement extends HTMLElement {
|
|
|
525
500
|
}
|
|
526
501
|
}
|
|
527
502
|
|
|
503
|
+
private readQuery(raw?: string | null): NavigatorQuery | undefined {
|
|
504
|
+
if (!raw) return undefined;
|
|
505
|
+
const parsed = JSON.parse(raw) as unknown;
|
|
506
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
507
|
+
throw new Error('query must be an object');
|
|
508
|
+
}
|
|
509
|
+
return parsed as NavigatorQuery;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
private buildPageTarget(options: {
|
|
513
|
+
page?: string | null;
|
|
514
|
+
path?: string | null;
|
|
515
|
+
query?: string | null;
|
|
516
|
+
}): { page?: string; path?: string; query?: NavigatorQuery } | null {
|
|
517
|
+
const page = options.page?.trim();
|
|
518
|
+
const path = options.path?.trim();
|
|
519
|
+
if (page && path) {
|
|
520
|
+
throw new Error('pass either page or path, not both');
|
|
521
|
+
}
|
|
522
|
+
if (!page && !path) return null;
|
|
523
|
+
const query = this.readQuery(options.query);
|
|
524
|
+
return {
|
|
525
|
+
...(page ? { page } : { path: path! }),
|
|
526
|
+
...(query ? { query } : {}),
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
private buildLxAppTarget(options: {
|
|
531
|
+
appId?: string | null;
|
|
532
|
+
page?: string | null;
|
|
533
|
+
path?: string | null;
|
|
534
|
+
query?: string | null;
|
|
535
|
+
envVersion?: NavigatorEnvVersion | null;
|
|
536
|
+
targetVersion?: string | null;
|
|
537
|
+
}): Record<string, unknown> {
|
|
538
|
+
const target: Record<string, unknown> = { appId: options.appId };
|
|
539
|
+
const pageTarget = this.buildPageTarget(options);
|
|
540
|
+
if (pageTarget) Object.assign(target, pageTarget);
|
|
541
|
+
if (options.envVersion) target.envVersion = options.envVersion;
|
|
542
|
+
if (options.targetVersion) target.targetVersion = options.targetVersion;
|
|
543
|
+
return target;
|
|
544
|
+
}
|
|
545
|
+
|
|
528
546
|
}
|
|
529
547
|
|
|
530
548
|
// Register custom element
|