@hybridly/vue 0.0.1-alpha.2 → 0.0.1-alpha.20
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 +171 -226
- package/dist/index.d.ts +201 -112
- package/dist/index.mjs +170 -228
- package/package.json +10 -11
package/dist/index.cjs
CHANGED
|
@@ -9,36 +9,37 @@ const progressPlugin = require('@hybridly/progress-plugin');
|
|
|
9
9
|
const devtoolsApi = require('@vue/devtools-api');
|
|
10
10
|
const qs = require('qs');
|
|
11
11
|
const isEqual = require('lodash.isequal');
|
|
12
|
-
const clone = require('lodash.clonedeep');
|
|
13
12
|
|
|
14
13
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
15
14
|
|
|
16
15
|
const qs__default = /*#__PURE__*/_interopDefaultLegacy(qs);
|
|
17
16
|
const isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
|
|
18
|
-
const clone__default = /*#__PURE__*/_interopDefaultLegacy(clone);
|
|
19
17
|
|
|
20
18
|
const state = {
|
|
21
19
|
context: vue.ref(),
|
|
22
20
|
view: vue.shallowRef(),
|
|
21
|
+
properties: vue.ref(),
|
|
23
22
|
viewLayout: vue.shallowRef(),
|
|
23
|
+
viewLayoutProperties: vue.ref(),
|
|
24
24
|
viewKey: vue.ref(),
|
|
25
25
|
dialog: vue.shallowRef(),
|
|
26
26
|
dialogKey: vue.ref(),
|
|
27
|
-
routes: vue.ref(),
|
|
28
|
-
setRoutes(routes) {
|
|
29
|
-
utils.debug.adapter("vue:state:routes", "Setting routes:", routes);
|
|
30
|
-
if (routes) {
|
|
31
|
-
state.routes.value = vue.unref(routes);
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
27
|
setView(view) {
|
|
35
28
|
utils.debug.adapter("vue:state:view", "Setting view:", view);
|
|
36
29
|
state.view.value = view;
|
|
37
30
|
},
|
|
31
|
+
setProperties(properties) {
|
|
32
|
+
utils.debug.adapter("vue:state:view", "Setting properties:", properties);
|
|
33
|
+
state.properties.value = properties;
|
|
34
|
+
},
|
|
38
35
|
setViewLayout(layout) {
|
|
39
|
-
utils.debug.adapter("vue:state:view", "Setting layout
|
|
36
|
+
utils.debug.adapter("vue:state:view", "Setting layout", layout);
|
|
40
37
|
state.viewLayout.value = layout;
|
|
41
38
|
},
|
|
39
|
+
setViewLayoutProperties(properties) {
|
|
40
|
+
utils.debug.adapter("vue:state:view", "Setting layout properties:", properties);
|
|
41
|
+
state.viewLayoutProperties.value = properties;
|
|
42
|
+
},
|
|
42
43
|
setDialog(dialog) {
|
|
43
44
|
utils.debug.adapter("vue:state:dialog", "Setting dialog:", dialog);
|
|
44
45
|
state.dialog.value = dialog;
|
|
@@ -60,13 +61,7 @@ const state = {
|
|
|
60
61
|
|
|
61
62
|
const wrapper = vue.defineComponent({
|
|
62
63
|
name: "Hybridly",
|
|
63
|
-
setup(
|
|
64
|
-
if (typeof window !== "undefined") {
|
|
65
|
-
state.setContext(props.context);
|
|
66
|
-
if (!props.context) {
|
|
67
|
-
throw new Error("Hybridly was not properly initialized. The context is missing.");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
64
|
+
setup() {
|
|
70
65
|
function renderLayout(child) {
|
|
71
66
|
utils.debug.adapter("vue:render:layout", "Rendering layout.");
|
|
72
67
|
if (typeof state.view.value?.layout === "function") {
|
|
@@ -75,11 +70,17 @@ const wrapper = vue.defineComponent({
|
|
|
75
70
|
if (Array.isArray(state.view.value?.layout)) {
|
|
76
71
|
return state.view.value.layout.concat(child).reverse().reduce((child2, layout) => {
|
|
77
72
|
layout.inheritAttrs = !!layout.inheritAttrs;
|
|
78
|
-
return vue.h(layout, {
|
|
73
|
+
return vue.h(layout, {
|
|
74
|
+
...state.view.value?.layoutProperties ?? {},
|
|
75
|
+
...state.properties.value
|
|
76
|
+
}, () => child2);
|
|
79
77
|
});
|
|
80
78
|
}
|
|
81
79
|
return [
|
|
82
|
-
vue.h(state.view.value?.layout, {
|
|
80
|
+
vue.h(state.view.value?.layout, {
|
|
81
|
+
...state.view.value?.layoutProperties ?? {},
|
|
82
|
+
...state.properties.value
|
|
83
|
+
}, () => child),
|
|
83
84
|
renderDialog()
|
|
84
85
|
];
|
|
85
86
|
}
|
|
@@ -87,7 +88,7 @@ const wrapper = vue.defineComponent({
|
|
|
87
88
|
utils.debug.adapter("vue:render:view", "Rendering view.");
|
|
88
89
|
state.view.value.inheritAttrs = !!state.view.value.inheritAttrs;
|
|
89
90
|
return vue.h(state.view.value, {
|
|
90
|
-
...state.
|
|
91
|
+
...state.properties.value,
|
|
91
92
|
key: state.viewKey.value
|
|
92
93
|
});
|
|
93
94
|
}
|
|
@@ -100,25 +101,24 @@ const wrapper = vue.defineComponent({
|
|
|
100
101
|
});
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
|
-
return () => {
|
|
104
|
-
if (state.view.value) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
104
|
+
return (...a) => {
|
|
105
|
+
if (!state.view.value) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
utils.debug.adapter("vue:render:wrapper", "Rendering wrapper component.", a.map(vue.toRaw));
|
|
109
|
+
const view = renderView();
|
|
110
|
+
if (state.viewLayout.value) {
|
|
111
|
+
state.view.value.layout = state.viewLayout.value;
|
|
112
|
+
}
|
|
113
|
+
if (state.viewLayoutProperties.value) {
|
|
114
|
+
state.view.value.layoutProperties = state.viewLayoutProperties.value;
|
|
115
|
+
state.viewLayoutProperties.value = void 0;
|
|
116
|
+
}
|
|
117
|
+
if (state.view.value.layout) {
|
|
118
|
+
return renderLayout(view);
|
|
114
119
|
}
|
|
120
|
+
return [view, renderDialog()];
|
|
115
121
|
};
|
|
116
|
-
},
|
|
117
|
-
props: {
|
|
118
|
-
context: {
|
|
119
|
-
type: Object,
|
|
120
|
-
required: true
|
|
121
|
-
}
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
|
|
@@ -160,8 +160,8 @@ function setupDevtools(app) {
|
|
|
160
160
|
});
|
|
161
161
|
payload.instanceData.state.push({
|
|
162
162
|
type: hybridlyStateType,
|
|
163
|
-
key: "
|
|
164
|
-
value: state.
|
|
163
|
+
key: "routing",
|
|
164
|
+
value: state.context.value?.routing
|
|
165
165
|
});
|
|
166
166
|
});
|
|
167
167
|
api.on.editComponentState((payload) => {
|
|
@@ -177,7 +177,7 @@ function setupDevtools(app) {
|
|
|
177
177
|
const listen = [
|
|
178
178
|
"start",
|
|
179
179
|
"data",
|
|
180
|
-
"
|
|
180
|
+
"navigated",
|
|
181
181
|
"progress",
|
|
182
182
|
"error",
|
|
183
183
|
"abort",
|
|
@@ -198,7 +198,7 @@ function setupDevtools(app) {
|
|
|
198
198
|
data: options
|
|
199
199
|
}
|
|
200
200
|
});
|
|
201
|
-
listen.forEach((event) => core.
|
|
201
|
+
listen.forEach((event) => core.registerHook(event, (data) => {
|
|
202
202
|
api.addTimelineEvent({
|
|
203
203
|
layerId: hybridlyEventsTimelineLayerId,
|
|
204
204
|
event: {
|
|
@@ -214,11 +214,11 @@ function setupDevtools(app) {
|
|
|
214
214
|
api.notifyComponentUpdate();
|
|
215
215
|
}, 100);
|
|
216
216
|
}
|
|
217
|
-
}));
|
|
217
|
+
}, { once: true }));
|
|
218
218
|
});
|
|
219
219
|
});
|
|
220
220
|
}
|
|
221
|
-
const
|
|
221
|
+
const devtools = {
|
|
222
222
|
install(app) {
|
|
223
223
|
if (process.env.NODE_ENV === "development" || __VUE_PROD_DEVTOOLS__) {
|
|
224
224
|
setupDevtools(app);
|
|
@@ -235,6 +235,7 @@ async function initializeHybridly(options) {
|
|
|
235
235
|
throw new Error("No payload. Are you using `@hybridly` or the `payload` option?");
|
|
236
236
|
}
|
|
237
237
|
state.setContext(await core.createRouter({
|
|
238
|
+
axios: options.axios,
|
|
238
239
|
plugins: options.plugins,
|
|
239
240
|
serializer: options.serializer,
|
|
240
241
|
adapter: {
|
|
@@ -243,6 +244,7 @@ async function initializeHybridly(options) {
|
|
|
243
244
|
},
|
|
244
245
|
swapView: async (options2) => {
|
|
245
246
|
state.setView(options2.component);
|
|
247
|
+
state.setProperties(options2.properties);
|
|
246
248
|
if (!options2.preserveState) {
|
|
247
249
|
state.setViewKey(Date.now());
|
|
248
250
|
}
|
|
@@ -253,13 +255,28 @@ async function initializeHybridly(options) {
|
|
|
253
255
|
},
|
|
254
256
|
payload
|
|
255
257
|
}));
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
258
|
+
if (typeof window !== "undefined") {
|
|
259
|
+
window.addEventListener("hybridly:routing", (event) => {
|
|
260
|
+
state.context.value?.adapter.updateRoutingConfiguration(event.detail);
|
|
261
|
+
});
|
|
262
|
+
window.dispatchEvent(new CustomEvent("hybridly:routing", { detail: window?.hybridly?.routing }));
|
|
263
|
+
}
|
|
264
|
+
const render = () => vue.h(wrapper);
|
|
265
|
+
if (options.setup) {
|
|
266
|
+
return await options.setup({
|
|
267
|
+
element,
|
|
268
|
+
wrapper,
|
|
269
|
+
render,
|
|
270
|
+
hybridly: devtools,
|
|
271
|
+
props: { context: state.context.value }
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const app = vue.createApp({ render });
|
|
275
|
+
if (options.devtools !== false) {
|
|
276
|
+
app.use(devtools);
|
|
277
|
+
}
|
|
278
|
+
await options.enhanceVue?.(app);
|
|
279
|
+
return app.mount(element);
|
|
263
280
|
}
|
|
264
281
|
function prepare(options) {
|
|
265
282
|
utils.debug.adapter("vue", "Preparing Hybridly with options:", options);
|
|
@@ -283,15 +300,6 @@ function prepare(options) {
|
|
|
283
300
|
}
|
|
284
301
|
throw new Error("Either `initializeHybridly#resolve` or `initializeHybridly#pages` should be defined.");
|
|
285
302
|
};
|
|
286
|
-
if (typeof window !== "undefined") {
|
|
287
|
-
const routes = window.hybridly?.routes;
|
|
288
|
-
if (routes) {
|
|
289
|
-
state.setRoutes(window.hybridly?.routes);
|
|
290
|
-
window.addEventListener("hybridly:routes", (event) => {
|
|
291
|
-
state.setRoutes(event.detail);
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
303
|
if (options.progress !== false) {
|
|
296
304
|
options.plugins = [
|
|
297
305
|
progressPlugin.progress(typeof options.progress === "object" ? options.progress : {}),
|
|
@@ -306,6 +314,10 @@ function prepare(options) {
|
|
|
306
314
|
};
|
|
307
315
|
}
|
|
308
316
|
async function resolvePageComponent(name, pages, defaultLayout) {
|
|
317
|
+
if (name.includes(":")) {
|
|
318
|
+
const [domain, page] = name.split(":");
|
|
319
|
+
name = `domains.${domain}.pages.${page}`;
|
|
320
|
+
}
|
|
309
321
|
const path = Object.keys(pages).sort((a, b) => a.length - b.length).find((path2) => path2.endsWith(`${name.replaceAll(".", "/")}.vue`));
|
|
310
322
|
if (!path) {
|
|
311
323
|
utils.showPageComponentErrorModal(name);
|
|
@@ -324,7 +336,7 @@ const RouterLink = vue.defineComponent({
|
|
|
324
336
|
return (props) => {
|
|
325
337
|
let data = props.data ?? {};
|
|
326
338
|
const url = core.makeUrl(props.href ?? "");
|
|
327
|
-
const method = props.method ?? "GET";
|
|
339
|
+
const method = props.method?.toUpperCase() ?? "GET";
|
|
328
340
|
const as = typeof props.as === "object" ? props.as : props.as?.toLowerCase() ?? "a";
|
|
329
341
|
if (method === "GET") {
|
|
330
342
|
utils.debug.adapter("vue", "Moving data object to URL parameters.");
|
|
@@ -356,7 +368,7 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
356
368
|
if (props.disabled) {
|
|
357
369
|
return;
|
|
358
370
|
}
|
|
359
|
-
core.router.
|
|
371
|
+
core.router.navigate({
|
|
360
372
|
url,
|
|
361
373
|
data,
|
|
362
374
|
method,
|
|
@@ -364,13 +376,14 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
364
376
|
...props.options
|
|
365
377
|
});
|
|
366
378
|
}
|
|
367
|
-
}, slots);
|
|
379
|
+
}, slots.default ? slots : props.text);
|
|
368
380
|
};
|
|
369
381
|
},
|
|
370
382
|
props: {
|
|
371
383
|
href: {
|
|
372
384
|
type: String,
|
|
373
|
-
required:
|
|
385
|
+
required: false,
|
|
386
|
+
default: void 0
|
|
374
387
|
},
|
|
375
388
|
as: {
|
|
376
389
|
type: [String, Object],
|
|
@@ -395,6 +408,11 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
395
408
|
options: {
|
|
396
409
|
type: Object,
|
|
397
410
|
default: () => ({})
|
|
411
|
+
},
|
|
412
|
+
text: {
|
|
413
|
+
type: String,
|
|
414
|
+
required: false,
|
|
415
|
+
default: void 0
|
|
398
416
|
}
|
|
399
417
|
}
|
|
400
418
|
});
|
|
@@ -406,6 +424,7 @@ function shouldIntercept(event) {
|
|
|
406
424
|
const HybridlyImports = {
|
|
407
425
|
"hybridly/vue": [
|
|
408
426
|
"useProperty",
|
|
427
|
+
"useTypedProperty",
|
|
409
428
|
"useProperties",
|
|
410
429
|
"useRouter",
|
|
411
430
|
"useBackForward",
|
|
@@ -413,13 +432,14 @@ const HybridlyImports = {
|
|
|
413
432
|
"useForm",
|
|
414
433
|
"useHistoryState",
|
|
415
434
|
"usePaginator",
|
|
416
|
-
"
|
|
417
|
-
"
|
|
435
|
+
"defineLayout",
|
|
436
|
+
"defineLayoutProperties",
|
|
437
|
+
"registerHook"
|
|
418
438
|
],
|
|
419
439
|
"hybridly": [
|
|
420
|
-
"registerHook",
|
|
421
|
-
"registerHookOnce",
|
|
422
440
|
"router",
|
|
441
|
+
"route",
|
|
442
|
+
"current",
|
|
423
443
|
"can"
|
|
424
444
|
]
|
|
425
445
|
};
|
|
@@ -481,31 +501,34 @@ function toReactive(objectRef) {
|
|
|
481
501
|
function useProperties() {
|
|
482
502
|
return vue.readonly(toReactive(vue.computed(() => state.context.value?.view.properties)));
|
|
483
503
|
}
|
|
504
|
+
function useTypedProperty(path, fallback) {
|
|
505
|
+
return vue.computed(
|
|
506
|
+
() => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
|
|
507
|
+
);
|
|
508
|
+
}
|
|
484
509
|
function useProperty(path, fallback) {
|
|
485
|
-
return vue.computed(
|
|
510
|
+
return vue.computed(
|
|
511
|
+
() => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
|
|
512
|
+
);
|
|
486
513
|
}
|
|
487
514
|
|
|
488
515
|
function useContext() {
|
|
489
516
|
return vue.computed(() => state.context.value);
|
|
490
517
|
}
|
|
491
518
|
|
|
492
|
-
function useRouter() {
|
|
493
|
-
return core.router;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
519
|
function safeClone(obj) {
|
|
497
|
-
return
|
|
520
|
+
return utils.clone(vue.toRaw(obj));
|
|
498
521
|
}
|
|
499
522
|
function useForm(options) {
|
|
500
|
-
const shouldRemember = options?.key
|
|
523
|
+
const shouldRemember = !!options?.key;
|
|
501
524
|
const historyKey = options?.key ?? "form:default";
|
|
502
525
|
const historyData = shouldRemember ? core.router.history.get(historyKey) : void 0;
|
|
503
526
|
const timeoutIds = {
|
|
504
527
|
recentlyFailed: void 0,
|
|
505
528
|
recentlySuccessful: void 0
|
|
506
529
|
};
|
|
507
|
-
const initial =
|
|
508
|
-
const loaded =
|
|
530
|
+
const initial = safeClone(options.fields);
|
|
531
|
+
const loaded = safeClone(historyData?.fields ?? options.fields);
|
|
509
532
|
const fields = vue.reactive(safeClone(historyData?.fields ?? options.fields));
|
|
510
533
|
const errors = vue.ref(historyData?.errors ?? {});
|
|
511
534
|
const isDirty = vue.ref(false);
|
|
@@ -514,61 +537,85 @@ function useForm(options) {
|
|
|
514
537
|
const recentlyFailed = vue.ref(false);
|
|
515
538
|
const failed = vue.ref(false);
|
|
516
539
|
const processing = vue.ref(false);
|
|
540
|
+
const progress = vue.ref();
|
|
517
541
|
function reset(...keys) {
|
|
518
542
|
if (keys.length === 0) {
|
|
519
543
|
keys = Object.keys(fields);
|
|
520
544
|
}
|
|
521
|
-
keys.forEach((key) =>
|
|
522
|
-
|
|
545
|
+
keys.forEach((key) => {
|
|
546
|
+
Reflect.set(fields, key, safeClone(Reflect.get(initial, key)));
|
|
547
|
+
clearError(key);
|
|
548
|
+
});
|
|
523
549
|
}
|
|
524
550
|
function submit(optionsOverrides) {
|
|
525
551
|
const url = typeof options.url === "function" ? options.url() : options.url;
|
|
526
552
|
const data = typeof options.transform === "function" ? options.transform?.(fields) : fields;
|
|
527
|
-
|
|
553
|
+
const preserveState = optionsOverrides?.preserveState ?? options.preserveState;
|
|
554
|
+
return core.router.navigate({
|
|
555
|
+
...options,
|
|
528
556
|
url: url ?? state.context.value?.url,
|
|
529
557
|
method: options.method ?? "POST",
|
|
530
558
|
...optionsOverrides,
|
|
531
559
|
data: safeClone(data),
|
|
532
|
-
preserveState:
|
|
560
|
+
preserveState: preserveState === void 0 && options.method !== "GET" ? true : preserveState,
|
|
533
561
|
hooks: {
|
|
534
|
-
before: (
|
|
562
|
+
before: (navigation, context) => {
|
|
535
563
|
failed.value = false;
|
|
536
564
|
successful.value = false;
|
|
537
565
|
recentlySuccessful.value = false;
|
|
538
566
|
clearTimeout(timeoutIds.recentlySuccessful);
|
|
539
567
|
clearTimeout(timeoutIds.recentlyFailed);
|
|
540
|
-
|
|
541
|
-
return options.hooks?.before?.(visit);
|
|
568
|
+
return options.hooks?.before?.(navigation, context);
|
|
542
569
|
},
|
|
543
570
|
start: (context) => {
|
|
544
571
|
processing.value = true;
|
|
545
572
|
return options.hooks?.start?.(context);
|
|
546
573
|
},
|
|
547
|
-
|
|
574
|
+
progress: (incoming, context) => {
|
|
575
|
+
progress.value = incoming;
|
|
576
|
+
return options.hooks?.progress?.(incoming, context);
|
|
577
|
+
},
|
|
578
|
+
error: (incoming, context) => {
|
|
548
579
|
setErrors(incoming);
|
|
549
580
|
failed.value = true;
|
|
550
581
|
recentlyFailed.value = true;
|
|
551
582
|
timeoutIds.recentlyFailed = setTimeout(() => recentlyFailed.value = false, options?.timeout ?? 5e3);
|
|
552
|
-
return options.hooks?.error?.(incoming);
|
|
583
|
+
return options.hooks?.error?.(incoming, context);
|
|
553
584
|
},
|
|
554
|
-
success: (payload) => {
|
|
585
|
+
success: (payload, context) => {
|
|
586
|
+
clearErrors();
|
|
555
587
|
if (options?.reset !== false) {
|
|
556
588
|
reset();
|
|
557
589
|
}
|
|
558
590
|
successful.value = true;
|
|
559
591
|
recentlySuccessful.value = true;
|
|
560
592
|
timeoutIds.recentlySuccessful = setTimeout(() => recentlySuccessful.value = false, options?.timeout ?? 5e3);
|
|
561
|
-
return options.hooks?.success?.(payload);
|
|
593
|
+
return options.hooks?.success?.(payload, context);
|
|
562
594
|
},
|
|
563
595
|
after: (context) => {
|
|
596
|
+
progress.value = void 0;
|
|
564
597
|
processing.value = false;
|
|
565
598
|
return options.hooks?.after?.(context);
|
|
566
599
|
}
|
|
567
600
|
}
|
|
568
601
|
});
|
|
569
602
|
}
|
|
570
|
-
function clearErrors() {
|
|
571
|
-
|
|
603
|
+
function clearErrors(...keys) {
|
|
604
|
+
if (keys.length === 0) {
|
|
605
|
+
keys = Object.keys(fields);
|
|
606
|
+
}
|
|
607
|
+
keys.forEach((key) => {
|
|
608
|
+
clearError(key);
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
function hasDirty(...keys) {
|
|
612
|
+
if (keys.length === 0) {
|
|
613
|
+
return isDirty.value;
|
|
614
|
+
}
|
|
615
|
+
return keys.some((key) => !isEqual__default(vue.toRaw(fields[key]), vue.toRaw(initial[key])));
|
|
616
|
+
}
|
|
617
|
+
function clearError(key) {
|
|
618
|
+
errors.value[key] = void 0;
|
|
572
619
|
}
|
|
573
620
|
function setErrors(incoming) {
|
|
574
621
|
errors.value = incoming;
|
|
@@ -587,21 +634,25 @@ function useForm(options) {
|
|
|
587
634
|
}, { deep: true, immediate: true });
|
|
588
635
|
return vue.reactive({
|
|
589
636
|
reset,
|
|
590
|
-
initial,
|
|
591
637
|
fields,
|
|
592
|
-
loaded,
|
|
593
|
-
submit,
|
|
594
638
|
abort,
|
|
595
639
|
setErrors,
|
|
596
640
|
clearErrors,
|
|
641
|
+
clearError,
|
|
642
|
+
hasDirty,
|
|
643
|
+
submitWithOptions: submit,
|
|
644
|
+
submit: () => submit(),
|
|
597
645
|
hasErrors: vue.computed(() => Object.values(errors.value).length > 0),
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
646
|
+
initial,
|
|
647
|
+
loaded,
|
|
648
|
+
progress,
|
|
649
|
+
isDirty,
|
|
650
|
+
errors,
|
|
651
|
+
processing,
|
|
652
|
+
successful,
|
|
653
|
+
failed,
|
|
654
|
+
recentlySuccessful,
|
|
655
|
+
recentlyFailed
|
|
605
656
|
});
|
|
606
657
|
}
|
|
607
658
|
|
|
@@ -615,7 +666,7 @@ function useHistoryState(key, initial) {
|
|
|
615
666
|
|
|
616
667
|
function useBackForward() {
|
|
617
668
|
const callbacks = [];
|
|
618
|
-
core.registerHook("
|
|
669
|
+
core.registerHook("navigated", (options) => {
|
|
619
670
|
if (options.isBackForward) {
|
|
620
671
|
callbacks.forEach((fn) => fn(state.context.value));
|
|
621
672
|
callbacks.splice(0, callbacks.length);
|
|
@@ -660,146 +711,40 @@ function usePaginator(paginator) {
|
|
|
660
711
|
return { pages, items, previous, next, first, last, total, from, to };
|
|
661
712
|
}
|
|
662
713
|
|
|
663
|
-
function
|
|
664
|
-
|
|
714
|
+
function defineLayout(...args) {
|
|
715
|
+
const layouts = args[0];
|
|
716
|
+
const properties = args[1];
|
|
717
|
+
state.setViewLayout(layouts);
|
|
718
|
+
state.setViewLayoutProperties(properties);
|
|
665
719
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
constructor(name, absolute) {
|
|
669
|
-
this.name = name;
|
|
670
|
-
this.absolute = absolute;
|
|
671
|
-
this.definition = Route.getDefinition(name);
|
|
672
|
-
}
|
|
673
|
-
static getDefinition(name) {
|
|
674
|
-
if (!state.routes.value) {
|
|
675
|
-
throw new Error("Routing is not initialized. Have you enabled the Vite plugin?");
|
|
676
|
-
}
|
|
677
|
-
const routes = state.routes.value;
|
|
678
|
-
const route = routes?.routes?.[name];
|
|
679
|
-
if (!route) {
|
|
680
|
-
throw new Error(`Route ${name.toString()} does not exist.`);
|
|
681
|
-
}
|
|
682
|
-
return route;
|
|
683
|
-
}
|
|
684
|
-
get template() {
|
|
685
|
-
const origin = !this.absolute ? "" : this.definition.domain ? `${state.routes.value?.url.match(/^\w+:\/\//)?.[0]}${this.definition.domain}${state.routes.value?.port ? `:${state.routes.value?.port}` : ""}` : state.routes.value?.url;
|
|
686
|
-
return `${origin}/${this.definition.uri}`.replace(/\/+$/, "");
|
|
687
|
-
}
|
|
688
|
-
get parameterSegments() {
|
|
689
|
-
return this.template.match(/{[^}?]+\??}/g)?.map((segment) => ({
|
|
690
|
-
name: segment.replace(/{|\??}/g, ""),
|
|
691
|
-
required: !/\?}$/.test(segment)
|
|
692
|
-
})) ?? [];
|
|
693
|
-
}
|
|
694
|
-
matchesUrl(url) {
|
|
695
|
-
if (!this.definition.methods.includes("GET")) {
|
|
696
|
-
return false;
|
|
697
|
-
}
|
|
698
|
-
const pattern = this.template.replace(/(\/?){([^}?]*)(\??)}/g, (_, slash, segment, optional) => {
|
|
699
|
-
const regex = `(?<${segment}>${this.definition.wheres?.[segment]?.replace(/(^\^)|(\$$)/g, "") || "[^/?]+"})`;
|
|
700
|
-
return optional ? `(${slash}${regex})?` : `${slash}${regex}`;
|
|
701
|
-
}).replace(/^\w+:\/\//, "");
|
|
702
|
-
const [location, query] = url.replace(/^\w+:\/\//, "").split("?");
|
|
703
|
-
const matches = new RegExp(`^${pattern}/?$`).exec(location);
|
|
704
|
-
return matches ? { params: matches.groups, query: qs.parse(query) } : false;
|
|
705
|
-
}
|
|
706
|
-
compile(params) {
|
|
707
|
-
const segments = this.parameterSegments;
|
|
708
|
-
if (!segments.length) {
|
|
709
|
-
return this.template;
|
|
710
|
-
}
|
|
711
|
-
return this.template.replace(/{([^}?]+)(\??)}/g, (_, segment, optional) => {
|
|
712
|
-
if (!optional && [null, void 0].includes(params?.[segment])) {
|
|
713
|
-
throw new Error(`Router error: [${segment}] parameter is required for route [${this.name}].`);
|
|
714
|
-
}
|
|
715
|
-
if (segments[segments.length - 1].name === segment && this.definition?.wheres?.[segment] === ".*") {
|
|
716
|
-
return encodeURIComponent(params[segment] ?? "").replace(/%2F/g, "/");
|
|
717
|
-
}
|
|
718
|
-
if (this.definition?.wheres?.[segment] && !new RegExp(`^${optional ? `(${this.definition?.wheres?.[segment]})?` : this.definition?.wheres?.[segment]}$`).test(params[segment] ?? "")) {
|
|
719
|
-
throw new Error(`Router error: [${segment}] parameter does not match required format [${this.definition?.wheres?.[segment]}] for route [${this.name}].`);
|
|
720
|
-
}
|
|
721
|
-
return encodeURIComponent(params[segment] ?? "");
|
|
722
|
-
}).replace(/\/+$/, "");
|
|
723
|
-
}
|
|
720
|
+
function defineLayoutProperties(properties) {
|
|
721
|
+
state.setViewLayoutProperties(properties);
|
|
724
722
|
}
|
|
725
723
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
this.setParameters(parameters);
|
|
731
|
-
}
|
|
732
|
-
toString() {
|
|
733
|
-
const unhandled = Object.keys(this.parameters).filter((key) => !this.route.parameterSegments.some(({ name }) => name === key)).filter((key) => key !== "_query").reduce((result, current) => ({ ...result, [current]: this.parameters[current] }), {});
|
|
734
|
-
return this.route.compile(this.parameters) + qs.stringify({ ...unhandled, ...this.parameters._query }, {
|
|
735
|
-
addQueryPrefix: true,
|
|
736
|
-
arrayFormat: "indices",
|
|
737
|
-
encodeValuesOnly: true,
|
|
738
|
-
skipNulls: true,
|
|
739
|
-
encoder: (value, encoder) => typeof value === "boolean" ? Number(value).toString() : encoder(value)
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
static has(name) {
|
|
743
|
-
try {
|
|
744
|
-
Route.getDefinition(name);
|
|
745
|
-
return true;
|
|
746
|
-
} catch {
|
|
747
|
-
return false;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
setParameters(parameters) {
|
|
751
|
-
this.parameters = parameters ?? {};
|
|
752
|
-
this.parameters = ["string", "number"].includes(typeof this.parameters) ? [this.parameters] : this.parameters;
|
|
753
|
-
const segments = this.route.parameterSegments.filter(({ name }) => !state.routes.value?.defaults[name]);
|
|
754
|
-
if (Array.isArray(this.parameters)) {
|
|
755
|
-
this.parameters = this.parameters.reduce((result, current, i) => segments[i] ? { ...result, [segments[i].name]: current } : typeof current === "object" ? { ...result, ...current } : { ...result, [current]: "" }, {});
|
|
756
|
-
} else if (segments.length === 1 && !this.parameters[segments[0].name] && (Reflect.has(this.parameters, Object.values(this.route.definition.bindings)[0]) || Reflect.has(this.parameters, "id"))) {
|
|
757
|
-
this.parameters = { [segments[0].name]: this.parameters };
|
|
758
|
-
}
|
|
759
|
-
this.parameters = {
|
|
760
|
-
...this.getDefaults(),
|
|
761
|
-
...this.substituteBindings()
|
|
762
|
-
};
|
|
724
|
+
const registerHook = (hook, fn, options) => {
|
|
725
|
+
const unregister = core.registerHook(hook, fn, options);
|
|
726
|
+
if (vue.getCurrentInstance()) {
|
|
727
|
+
vue.onUnmounted(() => unregister());
|
|
763
728
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
}
|
|
767
|
-
substituteBindings() {
|
|
768
|
-
return Object.entries(this.parameters).reduce((result, [key, value]) => {
|
|
769
|
-
if (!value || typeof value !== "object" || Array.isArray(value) || !this.route.parameterSegments.some(({ name }) => name === key)) {
|
|
770
|
-
return { ...result, [key]: value };
|
|
771
|
-
}
|
|
772
|
-
if (!Reflect.has(value, this.route.definition.bindings[key])) {
|
|
773
|
-
if (Reflect.has(value, "id")) {
|
|
774
|
-
this.route.definition.bindings[key] = "id";
|
|
775
|
-
} else {
|
|
776
|
-
throw new Error(`Router error: object passed as [${key}] parameter is missing route model binding key [${this.route.definition.bindings?.[key]}].`);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
return { ...result, [key]: value[this.route.definition.bindings[key]] };
|
|
780
|
-
}, {});
|
|
781
|
-
}
|
|
782
|
-
valueOf() {
|
|
783
|
-
return this.toString();
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
function route(name, parameters, absolute) {
|
|
788
|
-
return new Router(name, parameters, absolute).toString();
|
|
789
|
-
}
|
|
729
|
+
return unregister;
|
|
730
|
+
};
|
|
790
731
|
|
|
732
|
+
exports.can = core.can;
|
|
733
|
+
exports.route = core.route;
|
|
791
734
|
exports.router = core.router;
|
|
792
735
|
exports.HybridlyImports = HybridlyImports;
|
|
793
736
|
exports.HybridlyResolver = HybridlyResolver;
|
|
794
737
|
exports.RouterLink = RouterLink;
|
|
738
|
+
exports.defineLayout = defineLayout;
|
|
739
|
+
exports.defineLayoutProperties = defineLayoutProperties;
|
|
795
740
|
exports.initializeHybridly = initializeHybridly;
|
|
796
|
-
exports.
|
|
741
|
+
exports.registerHook = registerHook;
|
|
742
|
+
exports.resolvePageComponent = resolvePageComponent;
|
|
797
743
|
exports.useBackForward = useBackForward;
|
|
798
744
|
exports.useContext = useContext;
|
|
799
745
|
exports.useForm = useForm;
|
|
800
746
|
exports.useHistoryState = useHistoryState;
|
|
801
|
-
exports.useLayout = useLayout;
|
|
802
747
|
exports.usePaginator = usePaginator;
|
|
803
748
|
exports.useProperties = useProperties;
|
|
804
749
|
exports.useProperty = useProperty;
|
|
805
|
-
exports.
|
|
750
|
+
exports.useTypedProperty = useTypedProperty;
|