@hybridly/core 0.0.1-alpha.20 → 0.0.1-alpha.21
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.cjs +38 -21
- package/dist/index.d.ts +35 -10
- package/dist/index.mjs +38 -21
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -16,6 +16,8 @@ const HYBRIDLY_HEADER = "x-hybrid";
|
|
|
16
16
|
const EXTERNAL_NAVIGATION_HEADER = `${HYBRIDLY_HEADER}-external`;
|
|
17
17
|
const PARTIAL_COMPONENT_HEADER = `${HYBRIDLY_HEADER}-partial-component`;
|
|
18
18
|
const ONLY_DATA_HEADER = `${HYBRIDLY_HEADER}-only-data`;
|
|
19
|
+
const DIALOG_KEY_HEADER = `${HYBRIDLY_HEADER}-dialog-key`;
|
|
20
|
+
const DIALOG_REDIRECT_HEADER = `${HYBRIDLY_HEADER}-dialog-redirect`;
|
|
19
21
|
const EXCEPT_DATA_HEADER = `${HYBRIDLY_HEADER}-except-data`;
|
|
20
22
|
const CONTEXT_HEADER = `${HYBRIDLY_HEADER}-context`;
|
|
21
23
|
const VERSION_HEADER = `${HYBRIDLY_HEADER}-version`;
|
|
@@ -29,6 +31,8 @@ const constants = {
|
|
|
29
31
|
EXTERNAL_NAVIGATION_HEADER: EXTERNAL_NAVIGATION_HEADER,
|
|
30
32
|
PARTIAL_COMPONENT_HEADER: PARTIAL_COMPONENT_HEADER,
|
|
31
33
|
ONLY_DATA_HEADER: ONLY_DATA_HEADER,
|
|
34
|
+
DIALOG_KEY_HEADER: DIALOG_KEY_HEADER,
|
|
35
|
+
DIALOG_REDIRECT_HEADER: DIALOG_REDIRECT_HEADER,
|
|
32
36
|
EXCEPT_DATA_HEADER: EXCEPT_DATA_HEADER,
|
|
33
37
|
CONTEXT_HEADER: CONTEXT_HEADER,
|
|
34
38
|
VERSION_HEADER: VERSION_HEADER,
|
|
@@ -270,7 +274,7 @@ async function registerEventListeners() {
|
|
|
270
274
|
await navigate({
|
|
271
275
|
payload: event.state,
|
|
272
276
|
preserveScroll: true,
|
|
273
|
-
preserveState:
|
|
277
|
+
preserveState: !!getInternalRouterContext().dialog || !!event.state.dialog,
|
|
274
278
|
updateHistoryState: false,
|
|
275
279
|
isBackForward: true
|
|
276
280
|
});
|
|
@@ -478,7 +482,7 @@ function setContext(merge = {}, options = {}) {
|
|
|
478
482
|
Reflect.set(state.context, key, merge[key]);
|
|
479
483
|
});
|
|
480
484
|
if (options.propagate !== false) {
|
|
481
|
-
state.context.adapter.
|
|
485
|
+
state.context.adapter.onContextUpdate?.(state.context);
|
|
482
486
|
}
|
|
483
487
|
utils.debug.context("Updated context:", { context: state.context, added: merge });
|
|
484
488
|
}
|
|
@@ -532,6 +536,21 @@ function isExternalNavigation() {
|
|
|
532
536
|
return false;
|
|
533
537
|
}
|
|
534
538
|
|
|
539
|
+
async function closeDialog(options) {
|
|
540
|
+
const context = getInternalRouterContext();
|
|
541
|
+
const url = context.dialog?.redirectUrl ?? context.dialog?.baseUrl;
|
|
542
|
+
if (!url) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
context.adapter.onDialogClose?.(context);
|
|
546
|
+
return await performHybridNavigation({
|
|
547
|
+
url,
|
|
548
|
+
preserveScroll: true,
|
|
549
|
+
preserveState: true,
|
|
550
|
+
...options
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
535
554
|
const router = {
|
|
536
555
|
abort: async () => getRouterContext().pendingNavigation?.controller.abort(),
|
|
537
556
|
active: () => !!getRouterContext().pendingNavigation,
|
|
@@ -549,6 +568,9 @@ const router = {
|
|
|
549
568
|
const method = getRouteDefinition(name).method.at(0);
|
|
550
569
|
return await performHybridNavigation({ url, ...options, method });
|
|
551
570
|
},
|
|
571
|
+
dialog: {
|
|
572
|
+
close: (options) => closeDialog(options)
|
|
573
|
+
},
|
|
552
574
|
history: {
|
|
553
575
|
get: (key) => getKeyFromHistory(key),
|
|
554
576
|
remember: (key, value) => remember(key, value)
|
|
@@ -590,7 +612,7 @@ async function performHybridNavigation(options) {
|
|
|
590
612
|
}
|
|
591
613
|
if (context.pendingNavigation) {
|
|
592
614
|
utils.debug.router("Aborting current navigation.", context.pendingNavigation);
|
|
593
|
-
context.pendingNavigation?.controller
|
|
615
|
+
context.pendingNavigation?.controller?.abort();
|
|
594
616
|
}
|
|
595
617
|
saveScrollPositions();
|
|
596
618
|
if (options.url && options.transformUrl) {
|
|
@@ -603,6 +625,7 @@ async function performHybridNavigation(options) {
|
|
|
603
625
|
id: navigationId,
|
|
604
626
|
url: targetUrl,
|
|
605
627
|
controller: abortController,
|
|
628
|
+
status: "pending",
|
|
606
629
|
options
|
|
607
630
|
}
|
|
608
631
|
});
|
|
@@ -616,8 +639,10 @@ async function performHybridNavigation(options) {
|
|
|
616
639
|
signal: abortController.signal,
|
|
617
640
|
headers: {
|
|
618
641
|
...options.headers,
|
|
642
|
+
...context.dialog ? { [DIALOG_KEY_HEADER]: context.dialog.key } : {},
|
|
643
|
+
...context.dialog ? { [DIALOG_REDIRECT_HEADER]: context.dialog.redirectUrl ?? "" } : {},
|
|
619
644
|
...utils.when(options.only !== void 0 || options.except !== void 0, {
|
|
620
|
-
[PARTIAL_COMPONENT_HEADER]: context.view.
|
|
645
|
+
[PARTIAL_COMPONENT_HEADER]: context.view.component,
|
|
621
646
|
...utils.when(options.only, { [ONLY_DATA_HEADER]: JSON.stringify(options.only) }, {}),
|
|
622
647
|
...utils.when(options.except, { [EXCEPT_DATA_HEADER]: JSON.stringify(options.except) }, {})
|
|
623
648
|
}, {}),
|
|
@@ -649,7 +674,7 @@ async function performHybridNavigation(options) {
|
|
|
649
674
|
}
|
|
650
675
|
utils.debug.router("The response respects the Hybridly protocol.");
|
|
651
676
|
const payload = response.data;
|
|
652
|
-
if ((options.only?.length ?? options.except?.length) && payload.view.
|
|
677
|
+
if ((options.only?.length ?? options.except?.length) && payload.view.component === context.view.component) {
|
|
653
678
|
utils.debug.router(`Merging ${options.only ? '"only"' : '"except"'} properties.`, payload.view.properties);
|
|
654
679
|
payload.view.properties = utils.merge(context.view.properties, payload.view.properties);
|
|
655
680
|
utils.debug.router("Merged properties:", payload.view.properties);
|
|
@@ -672,21 +697,21 @@ async function performHybridNavigation(options) {
|
|
|
672
697
|
return context.view.properties.errors;
|
|
673
698
|
})();
|
|
674
699
|
utils.debug.router("The request returned validation errors.", errors);
|
|
675
|
-
await runHooks("error", options.hooks, errors, context);
|
|
676
700
|
setContext({
|
|
677
701
|
pendingNavigation: {
|
|
678
702
|
...context.pendingNavigation,
|
|
679
703
|
status: "error"
|
|
680
704
|
}
|
|
681
705
|
});
|
|
706
|
+
await runHooks("error", options.hooks, errors, context);
|
|
682
707
|
} else {
|
|
683
|
-
await runHooks("success", options.hooks, payload, context);
|
|
684
708
|
setContext({
|
|
685
709
|
pendingNavigation: {
|
|
686
710
|
...context.pendingNavigation,
|
|
687
711
|
status: "success"
|
|
688
712
|
}
|
|
689
713
|
});
|
|
714
|
+
await runHooks("success", options.hooks, payload, context);
|
|
690
715
|
}
|
|
691
716
|
return { response };
|
|
692
717
|
} catch (error) {
|
|
@@ -739,7 +764,7 @@ async function navigate(options) {
|
|
|
739
764
|
const shouldPreserveScroll = evaluateConditionalOption(options.preserveScroll);
|
|
740
765
|
const shouldReplaceHistory = evaluateConditionalOption(options.replace);
|
|
741
766
|
const shouldReplaceUrl = evaluateConditionalOption(options.preserveUrl);
|
|
742
|
-
if (shouldPreserveState && getHistoryState() && options.payload.view.
|
|
767
|
+
if (shouldPreserveState && getHistoryState() && options.payload.view.component === context.view.component) {
|
|
743
768
|
utils.debug.history("Setting the history from this entry into the context.");
|
|
744
769
|
setContext({ state: getHistoryState() });
|
|
745
770
|
}
|
|
@@ -755,22 +780,14 @@ async function navigate(options) {
|
|
|
755
780
|
utils.debug.router(`Target URL is ${context.url}, current window URL is ${window.location.href}.`, { shouldReplaceHistory });
|
|
756
781
|
setHistoryState({ replace: shouldReplaceHistory });
|
|
757
782
|
}
|
|
758
|
-
const viewComponent = await context.adapter.resolveComponent(context.view.
|
|
759
|
-
utils.debug.router(`Component [${context.view.
|
|
760
|
-
await context.adapter.
|
|
783
|
+
const viewComponent = await context.adapter.resolveComponent(context.view.component);
|
|
784
|
+
utils.debug.router(`Component [${context.view.component}] resolved to:`, viewComponent);
|
|
785
|
+
await context.adapter.onViewSwap({
|
|
761
786
|
component: viewComponent,
|
|
787
|
+
dialog: context.dialog,
|
|
762
788
|
properties: options.payload?.view.properties,
|
|
763
789
|
preserveState: shouldPreserveState
|
|
764
790
|
});
|
|
765
|
-
if (context.dialog) {
|
|
766
|
-
const dialogComponent = await context.adapter.resolveComponent(context.dialog.name);
|
|
767
|
-
utils.debug.router(`Dialog [${context.view.name}] resolved to:`, dialogComponent);
|
|
768
|
-
await context.adapter.swapDialog({
|
|
769
|
-
component: dialogComponent,
|
|
770
|
-
properties: options.payload?.dialog?.properties,
|
|
771
|
-
preserveState: shouldPreserveState
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
791
|
if (!shouldPreserveScroll) {
|
|
775
792
|
resetScrollPositions();
|
|
776
793
|
} else {
|
|
@@ -808,7 +825,7 @@ async function performLocalNavigation(targetUrl, options) {
|
|
|
808
825
|
dialog: context.dialog,
|
|
809
826
|
url,
|
|
810
827
|
view: {
|
|
811
|
-
|
|
828
|
+
component: options.component ?? context.view.component,
|
|
812
829
|
properties: options.properties ?? {}
|
|
813
830
|
}
|
|
814
831
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,9 @@ interface Plugin extends Partial<Hooks> {
|
|
|
86
86
|
}
|
|
87
87
|
declare function definePlugin(plugin: Plugin): Plugin;
|
|
88
88
|
|
|
89
|
+
interface CloseDialogOptions extends HybridRequestOptions {
|
|
90
|
+
}
|
|
91
|
+
|
|
89
92
|
type UrlResolvable = string | URL | Location;
|
|
90
93
|
type UrlTransformable = BaseUrlTransformable | ((string: URL) => BaseUrlTransformable);
|
|
91
94
|
type BaseUrlTransformable = Partial<Omit<URL, 'searchParams' | 'toJSON' | 'toString'>> & {
|
|
@@ -189,6 +192,10 @@ interface NavigationResponse {
|
|
|
189
192
|
actual: Error;
|
|
190
193
|
};
|
|
191
194
|
}
|
|
195
|
+
interface DialogRouter {
|
|
196
|
+
/** Closes the current dialog. */
|
|
197
|
+
close: (options?: CloseDialogOptions) => void;
|
|
198
|
+
}
|
|
192
199
|
interface Router {
|
|
193
200
|
/** Aborts the currently pending navigate, if any. */
|
|
194
201
|
abort: () => Promise<void>;
|
|
@@ -214,6 +221,8 @@ interface Router {
|
|
|
214
221
|
external: (url: UrlResolvable, data?: HybridRequestOptions['data']) => void;
|
|
215
222
|
/** Navigates to the given URL without a server round-trip. */
|
|
216
223
|
local: (url: UrlResolvable, options: ComponentNavigationOptions) => Promise<void>;
|
|
224
|
+
/** Access the dialog router. */
|
|
225
|
+
dialog: DialogRouter;
|
|
217
226
|
/** Access the history state. */
|
|
218
227
|
history: {
|
|
219
228
|
/** Remembers a value for the given route. */
|
|
@@ -232,14 +241,24 @@ interface PendingNavigation {
|
|
|
232
241
|
options: HybridRequestOptions;
|
|
233
242
|
/** Navigation identifier. */
|
|
234
243
|
id: string;
|
|
244
|
+
/** Current status. */
|
|
245
|
+
status: 'pending' | 'success' | 'error';
|
|
235
246
|
}
|
|
236
247
|
/** A page or dialog component. */
|
|
237
248
|
interface View {
|
|
238
249
|
/** Name of the component to use. */
|
|
239
|
-
|
|
250
|
+
component: string;
|
|
240
251
|
/** Properties to apply to the component. */
|
|
241
252
|
properties: Properties;
|
|
242
253
|
}
|
|
254
|
+
interface Dialog extends View {
|
|
255
|
+
/** URL that is the base background page when navigating to the dialog directly. */
|
|
256
|
+
baseUrl: string;
|
|
257
|
+
/** URL to which the dialog should redirect when closed. */
|
|
258
|
+
redirectUrl: string;
|
|
259
|
+
/** Unique identifier for this modal's lifecycle. */
|
|
260
|
+
key: string;
|
|
261
|
+
}
|
|
243
262
|
type Property = null | string | number | boolean | Property[] | {
|
|
244
263
|
[name: string]: Property;
|
|
245
264
|
};
|
|
@@ -251,18 +270,18 @@ interface SwapOptions<T> {
|
|
|
251
270
|
properties?: any;
|
|
252
271
|
/** Whether to preserve the state of the component. */
|
|
253
272
|
preserveState?: boolean;
|
|
273
|
+
/** Current dialog. */
|
|
274
|
+
dialog?: Dialog;
|
|
254
275
|
}
|
|
255
276
|
type ViewComponent = any;
|
|
256
|
-
type DialogComponent = any;
|
|
257
277
|
type ResolveComponent = (name: string) => Promise<ViewComponent>;
|
|
258
278
|
type SwapView = (options: SwapOptions<ViewComponent>) => Promise<void>;
|
|
259
|
-
type SwapDialog = (options: SwapOptions<DialogComponent>) => Promise<void>;
|
|
260
279
|
/** The payload of a navigation request from the server. */
|
|
261
280
|
interface HybridPayload {
|
|
262
281
|
/** The view to use in this request. */
|
|
263
282
|
view: View;
|
|
264
283
|
/** An optional dialog. */
|
|
265
|
-
dialog?:
|
|
284
|
+
dialog?: Dialog;
|
|
266
285
|
/** The current page URL. */
|
|
267
286
|
url: string;
|
|
268
287
|
/** The current asset version. */
|
|
@@ -319,7 +338,7 @@ interface InternalRouterContext {
|
|
|
319
338
|
/** The current view. */
|
|
320
339
|
view: View;
|
|
321
340
|
/** The current, optional dialog. */
|
|
322
|
-
dialog?:
|
|
341
|
+
dialog?: Dialog;
|
|
323
342
|
/** The current local asset version. */
|
|
324
343
|
version: string;
|
|
325
344
|
/** The current adapter's functions. */
|
|
@@ -347,12 +366,12 @@ type RouterContext = Readonly<InternalRouterContext>;
|
|
|
347
366
|
interface Adapter {
|
|
348
367
|
/** Resolves a component from the given name. */
|
|
349
368
|
resolveComponent: ResolveComponent;
|
|
350
|
-
/**
|
|
351
|
-
|
|
352
|
-
/** Swaps to the given dialog. */
|
|
353
|
-
swapDialog: SwapDialog;
|
|
369
|
+
/** Called when the view is swapped. */
|
|
370
|
+
onViewSwap: SwapView;
|
|
354
371
|
/** Called when the context is updated. */
|
|
355
|
-
|
|
372
|
+
onContextUpdate?: (context: InternalRouterContext) => void;
|
|
373
|
+
/** Called when a dialog is closed. */
|
|
374
|
+
onDialogClose?: (context: InternalRouterContext) => void;
|
|
356
375
|
}
|
|
357
376
|
interface ResolvedAdapter extends Adapter {
|
|
358
377
|
updateRoutingConfiguration: (routing?: RoutingConfiguration) => void;
|
|
@@ -406,6 +425,8 @@ declare const HYBRIDLY_HEADER = "x-hybrid";
|
|
|
406
425
|
declare const EXTERNAL_NAVIGATION_HEADER: string;
|
|
407
426
|
declare const PARTIAL_COMPONENT_HEADER: string;
|
|
408
427
|
declare const ONLY_DATA_HEADER: string;
|
|
428
|
+
declare const DIALOG_KEY_HEADER: string;
|
|
429
|
+
declare const DIALOG_REDIRECT_HEADER: string;
|
|
409
430
|
declare const EXCEPT_DATA_HEADER: string;
|
|
410
431
|
declare const CONTEXT_HEADER: string;
|
|
411
432
|
declare const VERSION_HEADER: string;
|
|
@@ -417,6 +438,8 @@ declare const constants_HYBRIDLY_HEADER: typeof HYBRIDLY_HEADER;
|
|
|
417
438
|
declare const constants_EXTERNAL_NAVIGATION_HEADER: typeof EXTERNAL_NAVIGATION_HEADER;
|
|
418
439
|
declare const constants_PARTIAL_COMPONENT_HEADER: typeof PARTIAL_COMPONENT_HEADER;
|
|
419
440
|
declare const constants_ONLY_DATA_HEADER: typeof ONLY_DATA_HEADER;
|
|
441
|
+
declare const constants_DIALOG_KEY_HEADER: typeof DIALOG_KEY_HEADER;
|
|
442
|
+
declare const constants_DIALOG_REDIRECT_HEADER: typeof DIALOG_REDIRECT_HEADER;
|
|
420
443
|
declare const constants_EXCEPT_DATA_HEADER: typeof EXCEPT_DATA_HEADER;
|
|
421
444
|
declare const constants_CONTEXT_HEADER: typeof CONTEXT_HEADER;
|
|
422
445
|
declare const constants_VERSION_HEADER: typeof VERSION_HEADER;
|
|
@@ -429,6 +452,8 @@ declare namespace constants {
|
|
|
429
452
|
constants_EXTERNAL_NAVIGATION_HEADER as EXTERNAL_NAVIGATION_HEADER,
|
|
430
453
|
constants_PARTIAL_COMPONENT_HEADER as PARTIAL_COMPONENT_HEADER,
|
|
431
454
|
constants_ONLY_DATA_HEADER as ONLY_DATA_HEADER,
|
|
455
|
+
constants_DIALOG_KEY_HEADER as DIALOG_KEY_HEADER,
|
|
456
|
+
constants_DIALOG_REDIRECT_HEADER as DIALOG_REDIRECT_HEADER,
|
|
432
457
|
constants_EXCEPT_DATA_HEADER as EXCEPT_DATA_HEADER,
|
|
433
458
|
constants_CONTEXT_HEADER as CONTEXT_HEADER,
|
|
434
459
|
constants_VERSION_HEADER as VERSION_HEADER,
|
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,8 @@ const HYBRIDLY_HEADER = "x-hybrid";
|
|
|
7
7
|
const EXTERNAL_NAVIGATION_HEADER = `${HYBRIDLY_HEADER}-external`;
|
|
8
8
|
const PARTIAL_COMPONENT_HEADER = `${HYBRIDLY_HEADER}-partial-component`;
|
|
9
9
|
const ONLY_DATA_HEADER = `${HYBRIDLY_HEADER}-only-data`;
|
|
10
|
+
const DIALOG_KEY_HEADER = `${HYBRIDLY_HEADER}-dialog-key`;
|
|
11
|
+
const DIALOG_REDIRECT_HEADER = `${HYBRIDLY_HEADER}-dialog-redirect`;
|
|
10
12
|
const EXCEPT_DATA_HEADER = `${HYBRIDLY_HEADER}-except-data`;
|
|
11
13
|
const CONTEXT_HEADER = `${HYBRIDLY_HEADER}-context`;
|
|
12
14
|
const VERSION_HEADER = `${HYBRIDLY_HEADER}-version`;
|
|
@@ -20,6 +22,8 @@ const constants = {
|
|
|
20
22
|
EXTERNAL_NAVIGATION_HEADER: EXTERNAL_NAVIGATION_HEADER,
|
|
21
23
|
PARTIAL_COMPONENT_HEADER: PARTIAL_COMPONENT_HEADER,
|
|
22
24
|
ONLY_DATA_HEADER: ONLY_DATA_HEADER,
|
|
25
|
+
DIALOG_KEY_HEADER: DIALOG_KEY_HEADER,
|
|
26
|
+
DIALOG_REDIRECT_HEADER: DIALOG_REDIRECT_HEADER,
|
|
23
27
|
EXCEPT_DATA_HEADER: EXCEPT_DATA_HEADER,
|
|
24
28
|
CONTEXT_HEADER: CONTEXT_HEADER,
|
|
25
29
|
VERSION_HEADER: VERSION_HEADER,
|
|
@@ -261,7 +265,7 @@ async function registerEventListeners() {
|
|
|
261
265
|
await navigate({
|
|
262
266
|
payload: event.state,
|
|
263
267
|
preserveScroll: true,
|
|
264
|
-
preserveState:
|
|
268
|
+
preserveState: !!getInternalRouterContext().dialog || !!event.state.dialog,
|
|
265
269
|
updateHistoryState: false,
|
|
266
270
|
isBackForward: true
|
|
267
271
|
});
|
|
@@ -469,7 +473,7 @@ function setContext(merge = {}, options = {}) {
|
|
|
469
473
|
Reflect.set(state.context, key, merge[key]);
|
|
470
474
|
});
|
|
471
475
|
if (options.propagate !== false) {
|
|
472
|
-
state.context.adapter.
|
|
476
|
+
state.context.adapter.onContextUpdate?.(state.context);
|
|
473
477
|
}
|
|
474
478
|
debug.context("Updated context:", { context: state.context, added: merge });
|
|
475
479
|
}
|
|
@@ -523,6 +527,21 @@ function isExternalNavigation() {
|
|
|
523
527
|
return false;
|
|
524
528
|
}
|
|
525
529
|
|
|
530
|
+
async function closeDialog(options) {
|
|
531
|
+
const context = getInternalRouterContext();
|
|
532
|
+
const url = context.dialog?.redirectUrl ?? context.dialog?.baseUrl;
|
|
533
|
+
if (!url) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
context.adapter.onDialogClose?.(context);
|
|
537
|
+
return await performHybridNavigation({
|
|
538
|
+
url,
|
|
539
|
+
preserveScroll: true,
|
|
540
|
+
preserveState: true,
|
|
541
|
+
...options
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
526
545
|
const router = {
|
|
527
546
|
abort: async () => getRouterContext().pendingNavigation?.controller.abort(),
|
|
528
547
|
active: () => !!getRouterContext().pendingNavigation,
|
|
@@ -540,6 +559,9 @@ const router = {
|
|
|
540
559
|
const method = getRouteDefinition(name).method.at(0);
|
|
541
560
|
return await performHybridNavigation({ url, ...options, method });
|
|
542
561
|
},
|
|
562
|
+
dialog: {
|
|
563
|
+
close: (options) => closeDialog(options)
|
|
564
|
+
},
|
|
543
565
|
history: {
|
|
544
566
|
get: (key) => getKeyFromHistory(key),
|
|
545
567
|
remember: (key, value) => remember(key, value)
|
|
@@ -581,7 +603,7 @@ async function performHybridNavigation(options) {
|
|
|
581
603
|
}
|
|
582
604
|
if (context.pendingNavigation) {
|
|
583
605
|
debug.router("Aborting current navigation.", context.pendingNavigation);
|
|
584
|
-
context.pendingNavigation?.controller
|
|
606
|
+
context.pendingNavigation?.controller?.abort();
|
|
585
607
|
}
|
|
586
608
|
saveScrollPositions();
|
|
587
609
|
if (options.url && options.transformUrl) {
|
|
@@ -594,6 +616,7 @@ async function performHybridNavigation(options) {
|
|
|
594
616
|
id: navigationId,
|
|
595
617
|
url: targetUrl,
|
|
596
618
|
controller: abortController,
|
|
619
|
+
status: "pending",
|
|
597
620
|
options
|
|
598
621
|
}
|
|
599
622
|
});
|
|
@@ -607,8 +630,10 @@ async function performHybridNavigation(options) {
|
|
|
607
630
|
signal: abortController.signal,
|
|
608
631
|
headers: {
|
|
609
632
|
...options.headers,
|
|
633
|
+
...context.dialog ? { [DIALOG_KEY_HEADER]: context.dialog.key } : {},
|
|
634
|
+
...context.dialog ? { [DIALOG_REDIRECT_HEADER]: context.dialog.redirectUrl ?? "" } : {},
|
|
610
635
|
...when(options.only !== void 0 || options.except !== void 0, {
|
|
611
|
-
[PARTIAL_COMPONENT_HEADER]: context.view.
|
|
636
|
+
[PARTIAL_COMPONENT_HEADER]: context.view.component,
|
|
612
637
|
...when(options.only, { [ONLY_DATA_HEADER]: JSON.stringify(options.only) }, {}),
|
|
613
638
|
...when(options.except, { [EXCEPT_DATA_HEADER]: JSON.stringify(options.except) }, {})
|
|
614
639
|
}, {}),
|
|
@@ -640,7 +665,7 @@ async function performHybridNavigation(options) {
|
|
|
640
665
|
}
|
|
641
666
|
debug.router("The response respects the Hybridly protocol.");
|
|
642
667
|
const payload = response.data;
|
|
643
|
-
if ((options.only?.length ?? options.except?.length) && payload.view.
|
|
668
|
+
if ((options.only?.length ?? options.except?.length) && payload.view.component === context.view.component) {
|
|
644
669
|
debug.router(`Merging ${options.only ? '"only"' : '"except"'} properties.`, payload.view.properties);
|
|
645
670
|
payload.view.properties = merge(context.view.properties, payload.view.properties);
|
|
646
671
|
debug.router("Merged properties:", payload.view.properties);
|
|
@@ -663,21 +688,21 @@ async function performHybridNavigation(options) {
|
|
|
663
688
|
return context.view.properties.errors;
|
|
664
689
|
})();
|
|
665
690
|
debug.router("The request returned validation errors.", errors);
|
|
666
|
-
await runHooks("error", options.hooks, errors, context);
|
|
667
691
|
setContext({
|
|
668
692
|
pendingNavigation: {
|
|
669
693
|
...context.pendingNavigation,
|
|
670
694
|
status: "error"
|
|
671
695
|
}
|
|
672
696
|
});
|
|
697
|
+
await runHooks("error", options.hooks, errors, context);
|
|
673
698
|
} else {
|
|
674
|
-
await runHooks("success", options.hooks, payload, context);
|
|
675
699
|
setContext({
|
|
676
700
|
pendingNavigation: {
|
|
677
701
|
...context.pendingNavigation,
|
|
678
702
|
status: "success"
|
|
679
703
|
}
|
|
680
704
|
});
|
|
705
|
+
await runHooks("success", options.hooks, payload, context);
|
|
681
706
|
}
|
|
682
707
|
return { response };
|
|
683
708
|
} catch (error) {
|
|
@@ -730,7 +755,7 @@ async function navigate(options) {
|
|
|
730
755
|
const shouldPreserveScroll = evaluateConditionalOption(options.preserveScroll);
|
|
731
756
|
const shouldReplaceHistory = evaluateConditionalOption(options.replace);
|
|
732
757
|
const shouldReplaceUrl = evaluateConditionalOption(options.preserveUrl);
|
|
733
|
-
if (shouldPreserveState && getHistoryState() && options.payload.view.
|
|
758
|
+
if (shouldPreserveState && getHistoryState() && options.payload.view.component === context.view.component) {
|
|
734
759
|
debug.history("Setting the history from this entry into the context.");
|
|
735
760
|
setContext({ state: getHistoryState() });
|
|
736
761
|
}
|
|
@@ -746,22 +771,14 @@ async function navigate(options) {
|
|
|
746
771
|
debug.router(`Target URL is ${context.url}, current window URL is ${window.location.href}.`, { shouldReplaceHistory });
|
|
747
772
|
setHistoryState({ replace: shouldReplaceHistory });
|
|
748
773
|
}
|
|
749
|
-
const viewComponent = await context.adapter.resolveComponent(context.view.
|
|
750
|
-
debug.router(`Component [${context.view.
|
|
751
|
-
await context.adapter.
|
|
774
|
+
const viewComponent = await context.adapter.resolveComponent(context.view.component);
|
|
775
|
+
debug.router(`Component [${context.view.component}] resolved to:`, viewComponent);
|
|
776
|
+
await context.adapter.onViewSwap({
|
|
752
777
|
component: viewComponent,
|
|
778
|
+
dialog: context.dialog,
|
|
753
779
|
properties: options.payload?.view.properties,
|
|
754
780
|
preserveState: shouldPreserveState
|
|
755
781
|
});
|
|
756
|
-
if (context.dialog) {
|
|
757
|
-
const dialogComponent = await context.adapter.resolveComponent(context.dialog.name);
|
|
758
|
-
debug.router(`Dialog [${context.view.name}] resolved to:`, dialogComponent);
|
|
759
|
-
await context.adapter.swapDialog({
|
|
760
|
-
component: dialogComponent,
|
|
761
|
-
properties: options.payload?.dialog?.properties,
|
|
762
|
-
preserveState: shouldPreserveState
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
782
|
if (!shouldPreserveScroll) {
|
|
766
783
|
resetScrollPositions();
|
|
767
784
|
} else {
|
|
@@ -799,7 +816,7 @@ async function performLocalNavigation(targetUrl, options) {
|
|
|
799
816
|
dialog: context.dialog,
|
|
800
817
|
url,
|
|
801
818
|
view: {
|
|
802
|
-
|
|
819
|
+
component: options.component ?? context.view.component,
|
|
803
820
|
properties: options.properties ?? {}
|
|
804
821
|
}
|
|
805
822
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridly/core",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.21",
|
|
4
4
|
"description": "A solution to develop server-driven, client-rendered applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hybridly",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"qs": "^6.11.0",
|
|
40
|
-
"@hybridly/utils": "0.0.1-alpha.
|
|
40
|
+
"@hybridly/utils": "0.0.1-alpha.21"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"defu": "^6.1.1"
|