@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.mjs
CHANGED
|
@@ -1,35 +1,37 @@
|
|
|
1
|
-
import { ref, shallowRef, unref, triggerRef, defineComponent, h, isRef, reactive, readonly, computed,
|
|
2
|
-
import { registerHook
|
|
3
|
-
export { router } from '@hybridly/core';
|
|
4
|
-
import { debug, showPageComponentErrorModal, merge } from '@hybridly/utils';
|
|
1
|
+
import { ref, shallowRef, unref, triggerRef, defineComponent, toRaw, h, createApp, isRef, reactive, readonly, computed, watch, getCurrentInstance, onUnmounted } from 'vue';
|
|
2
|
+
import { registerHook as registerHook$1, createRouter, makeUrl, router } from '@hybridly/core';
|
|
3
|
+
export { can, route, router } from '@hybridly/core';
|
|
4
|
+
import { debug, showPageComponentErrorModal, merge, clone } from '@hybridly/utils';
|
|
5
5
|
import { progress } from '@hybridly/progress-plugin';
|
|
6
6
|
import { setupDevtoolsPlugin } from '@vue/devtools-api';
|
|
7
|
-
import qs
|
|
7
|
+
import qs from 'qs';
|
|
8
8
|
import isEqual from 'lodash.isequal';
|
|
9
|
-
import clone from 'lodash.clonedeep';
|
|
10
9
|
|
|
11
10
|
const state = {
|
|
12
11
|
context: ref(),
|
|
13
12
|
view: shallowRef(),
|
|
13
|
+
properties: ref(),
|
|
14
14
|
viewLayout: shallowRef(),
|
|
15
|
+
viewLayoutProperties: ref(),
|
|
15
16
|
viewKey: ref(),
|
|
16
17
|
dialog: shallowRef(),
|
|
17
18
|
dialogKey: ref(),
|
|
18
|
-
routes: ref(),
|
|
19
|
-
setRoutes(routes) {
|
|
20
|
-
debug.adapter("vue:state:routes", "Setting routes:", routes);
|
|
21
|
-
if (routes) {
|
|
22
|
-
state.routes.value = unref(routes);
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
19
|
setView(view) {
|
|
26
20
|
debug.adapter("vue:state:view", "Setting view:", view);
|
|
27
21
|
state.view.value = view;
|
|
28
22
|
},
|
|
23
|
+
setProperties(properties) {
|
|
24
|
+
debug.adapter("vue:state:view", "Setting properties:", properties);
|
|
25
|
+
state.properties.value = properties;
|
|
26
|
+
},
|
|
29
27
|
setViewLayout(layout) {
|
|
30
|
-
debug.adapter("vue:state:view", "Setting layout
|
|
28
|
+
debug.adapter("vue:state:view", "Setting layout", layout);
|
|
31
29
|
state.viewLayout.value = layout;
|
|
32
30
|
},
|
|
31
|
+
setViewLayoutProperties(properties) {
|
|
32
|
+
debug.adapter("vue:state:view", "Setting layout properties:", properties);
|
|
33
|
+
state.viewLayoutProperties.value = properties;
|
|
34
|
+
},
|
|
33
35
|
setDialog(dialog) {
|
|
34
36
|
debug.adapter("vue:state:dialog", "Setting dialog:", dialog);
|
|
35
37
|
state.dialog.value = dialog;
|
|
@@ -51,13 +53,7 @@ const state = {
|
|
|
51
53
|
|
|
52
54
|
const wrapper = defineComponent({
|
|
53
55
|
name: "Hybridly",
|
|
54
|
-
setup(
|
|
55
|
-
if (typeof window !== "undefined") {
|
|
56
|
-
state.setContext(props.context);
|
|
57
|
-
if (!props.context) {
|
|
58
|
-
throw new Error("Hybridly was not properly initialized. The context is missing.");
|
|
59
|
-
}
|
|
60
|
-
}
|
|
56
|
+
setup() {
|
|
61
57
|
function renderLayout(child) {
|
|
62
58
|
debug.adapter("vue:render:layout", "Rendering layout.");
|
|
63
59
|
if (typeof state.view.value?.layout === "function") {
|
|
@@ -66,11 +62,17 @@ const wrapper = defineComponent({
|
|
|
66
62
|
if (Array.isArray(state.view.value?.layout)) {
|
|
67
63
|
return state.view.value.layout.concat(child).reverse().reduce((child2, layout) => {
|
|
68
64
|
layout.inheritAttrs = !!layout.inheritAttrs;
|
|
69
|
-
return h(layout, {
|
|
65
|
+
return h(layout, {
|
|
66
|
+
...state.view.value?.layoutProperties ?? {},
|
|
67
|
+
...state.properties.value
|
|
68
|
+
}, () => child2);
|
|
70
69
|
});
|
|
71
70
|
}
|
|
72
71
|
return [
|
|
73
|
-
h(state.view.value?.layout, {
|
|
72
|
+
h(state.view.value?.layout, {
|
|
73
|
+
...state.view.value?.layoutProperties ?? {},
|
|
74
|
+
...state.properties.value
|
|
75
|
+
}, () => child),
|
|
74
76
|
renderDialog()
|
|
75
77
|
];
|
|
76
78
|
}
|
|
@@ -78,7 +80,7 @@ const wrapper = defineComponent({
|
|
|
78
80
|
debug.adapter("vue:render:view", "Rendering view.");
|
|
79
81
|
state.view.value.inheritAttrs = !!state.view.value.inheritAttrs;
|
|
80
82
|
return h(state.view.value, {
|
|
81
|
-
...state.
|
|
83
|
+
...state.properties.value,
|
|
82
84
|
key: state.viewKey.value
|
|
83
85
|
});
|
|
84
86
|
}
|
|
@@ -91,25 +93,24 @@ const wrapper = defineComponent({
|
|
|
91
93
|
});
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
|
-
return () => {
|
|
95
|
-
if (state.view.value) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
return (...a) => {
|
|
97
|
+
if (!state.view.value) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
debug.adapter("vue:render:wrapper", "Rendering wrapper component.", a.map(toRaw));
|
|
101
|
+
const view = renderView();
|
|
102
|
+
if (state.viewLayout.value) {
|
|
103
|
+
state.view.value.layout = state.viewLayout.value;
|
|
104
|
+
}
|
|
105
|
+
if (state.viewLayoutProperties.value) {
|
|
106
|
+
state.view.value.layoutProperties = state.viewLayoutProperties.value;
|
|
107
|
+
state.viewLayoutProperties.value = void 0;
|
|
108
|
+
}
|
|
109
|
+
if (state.view.value.layout) {
|
|
110
|
+
return renderLayout(view);
|
|
105
111
|
}
|
|
112
|
+
return [view, renderDialog()];
|
|
106
113
|
};
|
|
107
|
-
},
|
|
108
|
-
props: {
|
|
109
|
-
context: {
|
|
110
|
-
type: Object,
|
|
111
|
-
required: true
|
|
112
|
-
}
|
|
113
114
|
}
|
|
114
115
|
});
|
|
115
116
|
|
|
@@ -151,8 +152,8 @@ function setupDevtools(app) {
|
|
|
151
152
|
});
|
|
152
153
|
payload.instanceData.state.push({
|
|
153
154
|
type: hybridlyStateType,
|
|
154
|
-
key: "
|
|
155
|
-
value: state.
|
|
155
|
+
key: "routing",
|
|
156
|
+
value: state.context.value?.routing
|
|
156
157
|
});
|
|
157
158
|
});
|
|
158
159
|
api.on.editComponentState((payload) => {
|
|
@@ -168,7 +169,7 @@ function setupDevtools(app) {
|
|
|
168
169
|
const listen = [
|
|
169
170
|
"start",
|
|
170
171
|
"data",
|
|
171
|
-
"
|
|
172
|
+
"navigated",
|
|
172
173
|
"progress",
|
|
173
174
|
"error",
|
|
174
175
|
"abort",
|
|
@@ -178,7 +179,7 @@ function setupDevtools(app) {
|
|
|
178
179
|
"fail",
|
|
179
180
|
"after"
|
|
180
181
|
];
|
|
181
|
-
registerHook("before", (options) => {
|
|
182
|
+
registerHook$1("before", (options) => {
|
|
182
183
|
const groupId = (Math.random() + 1).toString(36).substring(7);
|
|
183
184
|
api.addTimelineEvent({
|
|
184
185
|
layerId: hybridlyEventsTimelineLayerId,
|
|
@@ -189,7 +190,7 @@ function setupDevtools(app) {
|
|
|
189
190
|
data: options
|
|
190
191
|
}
|
|
191
192
|
});
|
|
192
|
-
listen.forEach((event) =>
|
|
193
|
+
listen.forEach((event) => registerHook$1(event, (data) => {
|
|
193
194
|
api.addTimelineEvent({
|
|
194
195
|
layerId: hybridlyEventsTimelineLayerId,
|
|
195
196
|
event: {
|
|
@@ -205,11 +206,11 @@ function setupDevtools(app) {
|
|
|
205
206
|
api.notifyComponentUpdate();
|
|
206
207
|
}, 100);
|
|
207
208
|
}
|
|
208
|
-
}));
|
|
209
|
+
}, { once: true }));
|
|
209
210
|
});
|
|
210
211
|
});
|
|
211
212
|
}
|
|
212
|
-
const
|
|
213
|
+
const devtools = {
|
|
213
214
|
install(app) {
|
|
214
215
|
if (process.env.NODE_ENV === "development" || __VUE_PROD_DEVTOOLS__) {
|
|
215
216
|
setupDevtools(app);
|
|
@@ -226,6 +227,7 @@ async function initializeHybridly(options) {
|
|
|
226
227
|
throw new Error("No payload. Are you using `@hybridly` or the `payload` option?");
|
|
227
228
|
}
|
|
228
229
|
state.setContext(await createRouter({
|
|
230
|
+
axios: options.axios,
|
|
229
231
|
plugins: options.plugins,
|
|
230
232
|
serializer: options.serializer,
|
|
231
233
|
adapter: {
|
|
@@ -234,6 +236,7 @@ async function initializeHybridly(options) {
|
|
|
234
236
|
},
|
|
235
237
|
swapView: async (options2) => {
|
|
236
238
|
state.setView(options2.component);
|
|
239
|
+
state.setProperties(options2.properties);
|
|
237
240
|
if (!options2.preserveState) {
|
|
238
241
|
state.setViewKey(Date.now());
|
|
239
242
|
}
|
|
@@ -244,13 +247,28 @@ async function initializeHybridly(options) {
|
|
|
244
247
|
},
|
|
245
248
|
payload
|
|
246
249
|
}));
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
if (typeof window !== "undefined") {
|
|
251
|
+
window.addEventListener("hybridly:routing", (event) => {
|
|
252
|
+
state.context.value?.adapter.updateRoutingConfiguration(event.detail);
|
|
253
|
+
});
|
|
254
|
+
window.dispatchEvent(new CustomEvent("hybridly:routing", { detail: window?.hybridly?.routing }));
|
|
255
|
+
}
|
|
256
|
+
const render = () => h(wrapper);
|
|
257
|
+
if (options.setup) {
|
|
258
|
+
return await options.setup({
|
|
259
|
+
element,
|
|
260
|
+
wrapper,
|
|
261
|
+
render,
|
|
262
|
+
hybridly: devtools,
|
|
263
|
+
props: { context: state.context.value }
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
const app = createApp({ render });
|
|
267
|
+
if (options.devtools !== false) {
|
|
268
|
+
app.use(devtools);
|
|
269
|
+
}
|
|
270
|
+
await options.enhanceVue?.(app);
|
|
271
|
+
return app.mount(element);
|
|
254
272
|
}
|
|
255
273
|
function prepare(options) {
|
|
256
274
|
debug.adapter("vue", "Preparing Hybridly with options:", options);
|
|
@@ -274,15 +292,6 @@ function prepare(options) {
|
|
|
274
292
|
}
|
|
275
293
|
throw new Error("Either `initializeHybridly#resolve` or `initializeHybridly#pages` should be defined.");
|
|
276
294
|
};
|
|
277
|
-
if (typeof window !== "undefined") {
|
|
278
|
-
const routes = window.hybridly?.routes;
|
|
279
|
-
if (routes) {
|
|
280
|
-
state.setRoutes(window.hybridly?.routes);
|
|
281
|
-
window.addEventListener("hybridly:routes", (event) => {
|
|
282
|
-
state.setRoutes(event.detail);
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
295
|
if (options.progress !== false) {
|
|
287
296
|
options.plugins = [
|
|
288
297
|
progress(typeof options.progress === "object" ? options.progress : {}),
|
|
@@ -297,6 +306,10 @@ function prepare(options) {
|
|
|
297
306
|
};
|
|
298
307
|
}
|
|
299
308
|
async function resolvePageComponent(name, pages, defaultLayout) {
|
|
309
|
+
if (name.includes(":")) {
|
|
310
|
+
const [domain, page] = name.split(":");
|
|
311
|
+
name = `domains.${domain}.pages.${page}`;
|
|
312
|
+
}
|
|
300
313
|
const path = Object.keys(pages).sort((a, b) => a.length - b.length).find((path2) => path2.endsWith(`${name.replaceAll(".", "/")}.vue`));
|
|
301
314
|
if (!path) {
|
|
302
315
|
showPageComponentErrorModal(name);
|
|
@@ -315,7 +328,7 @@ const RouterLink = defineComponent({
|
|
|
315
328
|
return (props) => {
|
|
316
329
|
let data = props.data ?? {};
|
|
317
330
|
const url = makeUrl(props.href ?? "");
|
|
318
|
-
const method = props.method ?? "GET";
|
|
331
|
+
const method = props.method?.toUpperCase() ?? "GET";
|
|
319
332
|
const as = typeof props.as === "object" ? props.as : props.as?.toLowerCase() ?? "a";
|
|
320
333
|
if (method === "GET") {
|
|
321
334
|
debug.adapter("vue", "Moving data object to URL parameters.");
|
|
@@ -347,7 +360,7 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
347
360
|
if (props.disabled) {
|
|
348
361
|
return;
|
|
349
362
|
}
|
|
350
|
-
router.
|
|
363
|
+
router.navigate({
|
|
351
364
|
url,
|
|
352
365
|
data,
|
|
353
366
|
method,
|
|
@@ -355,13 +368,14 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
355
368
|
...props.options
|
|
356
369
|
});
|
|
357
370
|
}
|
|
358
|
-
}, slots);
|
|
371
|
+
}, slots.default ? slots : props.text);
|
|
359
372
|
};
|
|
360
373
|
},
|
|
361
374
|
props: {
|
|
362
375
|
href: {
|
|
363
376
|
type: String,
|
|
364
|
-
required:
|
|
377
|
+
required: false,
|
|
378
|
+
default: void 0
|
|
365
379
|
},
|
|
366
380
|
as: {
|
|
367
381
|
type: [String, Object],
|
|
@@ -386,6 +400,11 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
386
400
|
options: {
|
|
387
401
|
type: Object,
|
|
388
402
|
default: () => ({})
|
|
403
|
+
},
|
|
404
|
+
text: {
|
|
405
|
+
type: String,
|
|
406
|
+
required: false,
|
|
407
|
+
default: void 0
|
|
389
408
|
}
|
|
390
409
|
}
|
|
391
410
|
});
|
|
@@ -397,6 +416,7 @@ function shouldIntercept(event) {
|
|
|
397
416
|
const HybridlyImports = {
|
|
398
417
|
"hybridly/vue": [
|
|
399
418
|
"useProperty",
|
|
419
|
+
"useTypedProperty",
|
|
400
420
|
"useProperties",
|
|
401
421
|
"useRouter",
|
|
402
422
|
"useBackForward",
|
|
@@ -404,13 +424,14 @@ const HybridlyImports = {
|
|
|
404
424
|
"useForm",
|
|
405
425
|
"useHistoryState",
|
|
406
426
|
"usePaginator",
|
|
407
|
-
"
|
|
408
|
-
"
|
|
427
|
+
"defineLayout",
|
|
428
|
+
"defineLayoutProperties",
|
|
429
|
+
"registerHook"
|
|
409
430
|
],
|
|
410
431
|
"hybridly": [
|
|
411
|
-
"registerHook",
|
|
412
|
-
"registerHookOnce",
|
|
413
432
|
"router",
|
|
433
|
+
"route",
|
|
434
|
+
"current",
|
|
414
435
|
"can"
|
|
415
436
|
]
|
|
416
437
|
};
|
|
@@ -472,31 +493,34 @@ function toReactive(objectRef) {
|
|
|
472
493
|
function useProperties() {
|
|
473
494
|
return readonly(toReactive(computed(() => state.context.value?.view.properties)));
|
|
474
495
|
}
|
|
496
|
+
function useTypedProperty(path, fallback) {
|
|
497
|
+
return computed(
|
|
498
|
+
() => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
|
|
499
|
+
);
|
|
500
|
+
}
|
|
475
501
|
function useProperty(path, fallback) {
|
|
476
|
-
return computed(
|
|
502
|
+
return computed(
|
|
503
|
+
() => path.split(".").reduce((o, i) => o[i], state.context.value?.view.properties) ?? fallback
|
|
504
|
+
);
|
|
477
505
|
}
|
|
478
506
|
|
|
479
507
|
function useContext() {
|
|
480
508
|
return computed(() => state.context.value);
|
|
481
509
|
}
|
|
482
510
|
|
|
483
|
-
function useRouter() {
|
|
484
|
-
return router;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
511
|
function safeClone(obj) {
|
|
488
512
|
return clone(toRaw(obj));
|
|
489
513
|
}
|
|
490
514
|
function useForm(options) {
|
|
491
|
-
const shouldRemember = options?.key
|
|
515
|
+
const shouldRemember = !!options?.key;
|
|
492
516
|
const historyKey = options?.key ?? "form:default";
|
|
493
517
|
const historyData = shouldRemember ? router.history.get(historyKey) : void 0;
|
|
494
518
|
const timeoutIds = {
|
|
495
519
|
recentlyFailed: void 0,
|
|
496
520
|
recentlySuccessful: void 0
|
|
497
521
|
};
|
|
498
|
-
const initial =
|
|
499
|
-
const loaded =
|
|
522
|
+
const initial = safeClone(options.fields);
|
|
523
|
+
const loaded = safeClone(historyData?.fields ?? options.fields);
|
|
500
524
|
const fields = reactive(safeClone(historyData?.fields ?? options.fields));
|
|
501
525
|
const errors = ref(historyData?.errors ?? {});
|
|
502
526
|
const isDirty = ref(false);
|
|
@@ -505,61 +529,85 @@ function useForm(options) {
|
|
|
505
529
|
const recentlyFailed = ref(false);
|
|
506
530
|
const failed = ref(false);
|
|
507
531
|
const processing = ref(false);
|
|
532
|
+
const progress = ref();
|
|
508
533
|
function reset(...keys) {
|
|
509
534
|
if (keys.length === 0) {
|
|
510
535
|
keys = Object.keys(fields);
|
|
511
536
|
}
|
|
512
|
-
keys.forEach((key) =>
|
|
513
|
-
|
|
537
|
+
keys.forEach((key) => {
|
|
538
|
+
Reflect.set(fields, key, safeClone(Reflect.get(initial, key)));
|
|
539
|
+
clearError(key);
|
|
540
|
+
});
|
|
514
541
|
}
|
|
515
542
|
function submit(optionsOverrides) {
|
|
516
543
|
const url = typeof options.url === "function" ? options.url() : options.url;
|
|
517
544
|
const data = typeof options.transform === "function" ? options.transform?.(fields) : fields;
|
|
518
|
-
|
|
545
|
+
const preserveState = optionsOverrides?.preserveState ?? options.preserveState;
|
|
546
|
+
return router.navigate({
|
|
547
|
+
...options,
|
|
519
548
|
url: url ?? state.context.value?.url,
|
|
520
549
|
method: options.method ?? "POST",
|
|
521
550
|
...optionsOverrides,
|
|
522
551
|
data: safeClone(data),
|
|
523
|
-
preserveState:
|
|
552
|
+
preserveState: preserveState === void 0 && options.method !== "GET" ? true : preserveState,
|
|
524
553
|
hooks: {
|
|
525
|
-
before: (
|
|
554
|
+
before: (navigation, context) => {
|
|
526
555
|
failed.value = false;
|
|
527
556
|
successful.value = false;
|
|
528
557
|
recentlySuccessful.value = false;
|
|
529
558
|
clearTimeout(timeoutIds.recentlySuccessful);
|
|
530
559
|
clearTimeout(timeoutIds.recentlyFailed);
|
|
531
|
-
|
|
532
|
-
return options.hooks?.before?.(visit);
|
|
560
|
+
return options.hooks?.before?.(navigation, context);
|
|
533
561
|
},
|
|
534
562
|
start: (context) => {
|
|
535
563
|
processing.value = true;
|
|
536
564
|
return options.hooks?.start?.(context);
|
|
537
565
|
},
|
|
538
|
-
|
|
566
|
+
progress: (incoming, context) => {
|
|
567
|
+
progress.value = incoming;
|
|
568
|
+
return options.hooks?.progress?.(incoming, context);
|
|
569
|
+
},
|
|
570
|
+
error: (incoming, context) => {
|
|
539
571
|
setErrors(incoming);
|
|
540
572
|
failed.value = true;
|
|
541
573
|
recentlyFailed.value = true;
|
|
542
574
|
timeoutIds.recentlyFailed = setTimeout(() => recentlyFailed.value = false, options?.timeout ?? 5e3);
|
|
543
|
-
return options.hooks?.error?.(incoming);
|
|
575
|
+
return options.hooks?.error?.(incoming, context);
|
|
544
576
|
},
|
|
545
|
-
success: (payload) => {
|
|
577
|
+
success: (payload, context) => {
|
|
578
|
+
clearErrors();
|
|
546
579
|
if (options?.reset !== false) {
|
|
547
580
|
reset();
|
|
548
581
|
}
|
|
549
582
|
successful.value = true;
|
|
550
583
|
recentlySuccessful.value = true;
|
|
551
584
|
timeoutIds.recentlySuccessful = setTimeout(() => recentlySuccessful.value = false, options?.timeout ?? 5e3);
|
|
552
|
-
return options.hooks?.success?.(payload);
|
|
585
|
+
return options.hooks?.success?.(payload, context);
|
|
553
586
|
},
|
|
554
587
|
after: (context) => {
|
|
588
|
+
progress.value = void 0;
|
|
555
589
|
processing.value = false;
|
|
556
590
|
return options.hooks?.after?.(context);
|
|
557
591
|
}
|
|
558
592
|
}
|
|
559
593
|
});
|
|
560
594
|
}
|
|
561
|
-
function clearErrors() {
|
|
562
|
-
|
|
595
|
+
function clearErrors(...keys) {
|
|
596
|
+
if (keys.length === 0) {
|
|
597
|
+
keys = Object.keys(fields);
|
|
598
|
+
}
|
|
599
|
+
keys.forEach((key) => {
|
|
600
|
+
clearError(key);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
function hasDirty(...keys) {
|
|
604
|
+
if (keys.length === 0) {
|
|
605
|
+
return isDirty.value;
|
|
606
|
+
}
|
|
607
|
+
return keys.some((key) => !isEqual(toRaw(fields[key]), toRaw(initial[key])));
|
|
608
|
+
}
|
|
609
|
+
function clearError(key) {
|
|
610
|
+
errors.value[key] = void 0;
|
|
563
611
|
}
|
|
564
612
|
function setErrors(incoming) {
|
|
565
613
|
errors.value = incoming;
|
|
@@ -578,21 +626,25 @@ function useForm(options) {
|
|
|
578
626
|
}, { deep: true, immediate: true });
|
|
579
627
|
return reactive({
|
|
580
628
|
reset,
|
|
581
|
-
initial,
|
|
582
629
|
fields,
|
|
583
|
-
loaded,
|
|
584
|
-
submit,
|
|
585
630
|
abort,
|
|
586
631
|
setErrors,
|
|
587
632
|
clearErrors,
|
|
633
|
+
clearError,
|
|
634
|
+
hasDirty,
|
|
635
|
+
submitWithOptions: submit,
|
|
636
|
+
submit: () => submit(),
|
|
588
637
|
hasErrors: computed(() => Object.values(errors.value).length > 0),
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
638
|
+
initial,
|
|
639
|
+
loaded,
|
|
640
|
+
progress,
|
|
641
|
+
isDirty,
|
|
642
|
+
errors,
|
|
643
|
+
processing,
|
|
644
|
+
successful,
|
|
645
|
+
failed,
|
|
646
|
+
recentlySuccessful,
|
|
647
|
+
recentlyFailed
|
|
596
648
|
});
|
|
597
649
|
}
|
|
598
650
|
|
|
@@ -606,7 +658,7 @@ function useHistoryState(key, initial) {
|
|
|
606
658
|
|
|
607
659
|
function useBackForward() {
|
|
608
660
|
const callbacks = [];
|
|
609
|
-
registerHook("
|
|
661
|
+
registerHook$1("navigated", (options) => {
|
|
610
662
|
if (options.isBackForward) {
|
|
611
663
|
callbacks.forEach((fn) => fn(state.context.value));
|
|
612
664
|
callbacks.splice(0, callbacks.length);
|
|
@@ -651,132 +703,22 @@ function usePaginator(paginator) {
|
|
|
651
703
|
return { pages, items, previous, next, first, last, total, from, to };
|
|
652
704
|
}
|
|
653
705
|
|
|
654
|
-
function
|
|
655
|
-
|
|
706
|
+
function defineLayout(...args) {
|
|
707
|
+
const layouts = args[0];
|
|
708
|
+
const properties = args[1];
|
|
709
|
+
state.setViewLayout(layouts);
|
|
710
|
+
state.setViewLayoutProperties(properties);
|
|
656
711
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
constructor(name, absolute) {
|
|
660
|
-
this.name = name;
|
|
661
|
-
this.absolute = absolute;
|
|
662
|
-
this.definition = Route.getDefinition(name);
|
|
663
|
-
}
|
|
664
|
-
static getDefinition(name) {
|
|
665
|
-
if (!state.routes.value) {
|
|
666
|
-
throw new Error("Routing is not initialized. Have you enabled the Vite plugin?");
|
|
667
|
-
}
|
|
668
|
-
const routes = state.routes.value;
|
|
669
|
-
const route = routes?.routes?.[name];
|
|
670
|
-
if (!route) {
|
|
671
|
-
throw new Error(`Route ${name.toString()} does not exist.`);
|
|
672
|
-
}
|
|
673
|
-
return route;
|
|
674
|
-
}
|
|
675
|
-
get template() {
|
|
676
|
-
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;
|
|
677
|
-
return `${origin}/${this.definition.uri}`.replace(/\/+$/, "");
|
|
678
|
-
}
|
|
679
|
-
get parameterSegments() {
|
|
680
|
-
return this.template.match(/{[^}?]+\??}/g)?.map((segment) => ({
|
|
681
|
-
name: segment.replace(/{|\??}/g, ""),
|
|
682
|
-
required: !/\?}$/.test(segment)
|
|
683
|
-
})) ?? [];
|
|
684
|
-
}
|
|
685
|
-
matchesUrl(url) {
|
|
686
|
-
if (!this.definition.methods.includes("GET")) {
|
|
687
|
-
return false;
|
|
688
|
-
}
|
|
689
|
-
const pattern = this.template.replace(/(\/?){([^}?]*)(\??)}/g, (_, slash, segment, optional) => {
|
|
690
|
-
const regex = `(?<${segment}>${this.definition.wheres?.[segment]?.replace(/(^\^)|(\$$)/g, "") || "[^/?]+"})`;
|
|
691
|
-
return optional ? `(${slash}${regex})?` : `${slash}${regex}`;
|
|
692
|
-
}).replace(/^\w+:\/\//, "");
|
|
693
|
-
const [location, query] = url.replace(/^\w+:\/\//, "").split("?");
|
|
694
|
-
const matches = new RegExp(`^${pattern}/?$`).exec(location);
|
|
695
|
-
return matches ? { params: matches.groups, query: parse(query) } : false;
|
|
696
|
-
}
|
|
697
|
-
compile(params) {
|
|
698
|
-
const segments = this.parameterSegments;
|
|
699
|
-
if (!segments.length) {
|
|
700
|
-
return this.template;
|
|
701
|
-
}
|
|
702
|
-
return this.template.replace(/{([^}?]+)(\??)}/g, (_, segment, optional) => {
|
|
703
|
-
if (!optional && [null, void 0].includes(params?.[segment])) {
|
|
704
|
-
throw new Error(`Router error: [${segment}] parameter is required for route [${this.name}].`);
|
|
705
|
-
}
|
|
706
|
-
if (segments[segments.length - 1].name === segment && this.definition?.wheres?.[segment] === ".*") {
|
|
707
|
-
return encodeURIComponent(params[segment] ?? "").replace(/%2F/g, "/");
|
|
708
|
-
}
|
|
709
|
-
if (this.definition?.wheres?.[segment] && !new RegExp(`^${optional ? `(${this.definition?.wheres?.[segment]})?` : this.definition?.wheres?.[segment]}$`).test(params[segment] ?? "")) {
|
|
710
|
-
throw new Error(`Router error: [${segment}] parameter does not match required format [${this.definition?.wheres?.[segment]}] for route [${this.name}].`);
|
|
711
|
-
}
|
|
712
|
-
return encodeURIComponent(params[segment] ?? "");
|
|
713
|
-
}).replace(/\/+$/, "");
|
|
714
|
-
}
|
|
712
|
+
function defineLayoutProperties(properties) {
|
|
713
|
+
state.setViewLayoutProperties(properties);
|
|
715
714
|
}
|
|
716
715
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
this.setParameters(parameters);
|
|
722
|
-
}
|
|
723
|
-
toString() {
|
|
724
|
-
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] }), {});
|
|
725
|
-
return this.route.compile(this.parameters) + stringify({ ...unhandled, ...this.parameters._query }, {
|
|
726
|
-
addQueryPrefix: true,
|
|
727
|
-
arrayFormat: "indices",
|
|
728
|
-
encodeValuesOnly: true,
|
|
729
|
-
skipNulls: true,
|
|
730
|
-
encoder: (value, encoder) => typeof value === "boolean" ? Number(value).toString() : encoder(value)
|
|
731
|
-
});
|
|
732
|
-
}
|
|
733
|
-
static has(name) {
|
|
734
|
-
try {
|
|
735
|
-
Route.getDefinition(name);
|
|
736
|
-
return true;
|
|
737
|
-
} catch {
|
|
738
|
-
return false;
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
setParameters(parameters) {
|
|
742
|
-
this.parameters = parameters ?? {};
|
|
743
|
-
this.parameters = ["string", "number"].includes(typeof this.parameters) ? [this.parameters] : this.parameters;
|
|
744
|
-
const segments = this.route.parameterSegments.filter(({ name }) => !state.routes.value?.defaults[name]);
|
|
745
|
-
if (Array.isArray(this.parameters)) {
|
|
746
|
-
this.parameters = this.parameters.reduce((result, current, i) => segments[i] ? { ...result, [segments[i].name]: current } : typeof current === "object" ? { ...result, ...current } : { ...result, [current]: "" }, {});
|
|
747
|
-
} 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"))) {
|
|
748
|
-
this.parameters = { [segments[0].name]: this.parameters };
|
|
749
|
-
}
|
|
750
|
-
this.parameters = {
|
|
751
|
-
...this.getDefaults(),
|
|
752
|
-
...this.substituteBindings()
|
|
753
|
-
};
|
|
716
|
+
const registerHook = (hook, fn, options) => {
|
|
717
|
+
const unregister = registerHook$1(hook, fn, options);
|
|
718
|
+
if (getCurrentInstance()) {
|
|
719
|
+
onUnmounted(() => unregister());
|
|
754
720
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
758
|
-
substituteBindings() {
|
|
759
|
-
return Object.entries(this.parameters).reduce((result, [key, value]) => {
|
|
760
|
-
if (!value || typeof value !== "object" || Array.isArray(value) || !this.route.parameterSegments.some(({ name }) => name === key)) {
|
|
761
|
-
return { ...result, [key]: value };
|
|
762
|
-
}
|
|
763
|
-
if (!Reflect.has(value, this.route.definition.bindings[key])) {
|
|
764
|
-
if (Reflect.has(value, "id")) {
|
|
765
|
-
this.route.definition.bindings[key] = "id";
|
|
766
|
-
} else {
|
|
767
|
-
throw new Error(`Router error: object passed as [${key}] parameter is missing route model binding key [${this.route.definition.bindings?.[key]}].`);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
return { ...result, [key]: value[this.route.definition.bindings[key]] };
|
|
771
|
-
}, {});
|
|
772
|
-
}
|
|
773
|
-
valueOf() {
|
|
774
|
-
return this.toString();
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
function route(name, parameters, absolute) {
|
|
779
|
-
return new Router(name, parameters, absolute).toString();
|
|
780
|
-
}
|
|
721
|
+
return unregister;
|
|
722
|
+
};
|
|
781
723
|
|
|
782
|
-
export { HybridlyImports, HybridlyResolver, RouterLink, initializeHybridly,
|
|
724
|
+
export { HybridlyImports, HybridlyResolver, RouterLink, defineLayout, defineLayoutProperties, initializeHybridly, registerHook, resolvePageComponent, useBackForward, useContext, useForm, useHistoryState, usePaginator, useProperties, useProperty, useTypedProperty };
|