@hybridly/vue 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +261 -44
- package/dist/index.d.cts +421 -64
- package/dist/index.d.mts +421 -64
- package/dist/index.d.ts +421 -64
- package/dist/index.mjs +262 -46
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -236,19 +236,25 @@ const wrapper = vue.defineComponent({
|
|
|
236
236
|
renderDialog()
|
|
237
237
|
];
|
|
238
238
|
}
|
|
239
|
-
function
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
function hijackOnMounted(component, type) {
|
|
240
|
+
if (!component) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const actual = component?.mounted;
|
|
244
|
+
component.mounted = () => {
|
|
244
245
|
actual?.();
|
|
245
246
|
vue.nextTick(() => {
|
|
246
|
-
utils.debug.adapter(
|
|
247
|
+
utils.debug.adapter(`vue:render:${type}`, "Calling mounted callbacks.");
|
|
247
248
|
while (onMountedCallbacks.length) {
|
|
248
249
|
onMountedCallbacks.shift()?.();
|
|
249
250
|
}
|
|
250
251
|
});
|
|
251
252
|
};
|
|
253
|
+
}
|
|
254
|
+
function renderView() {
|
|
255
|
+
utils.debug.adapter("vue:render:view", "Rendering view.");
|
|
256
|
+
state.view.value.inheritAttrs = !!state.view.value.inheritAttrs;
|
|
257
|
+
hijackOnMounted(state.view.value, "view");
|
|
252
258
|
return vue.h(state.view.value, {
|
|
253
259
|
...state.properties.value,
|
|
254
260
|
key: state.viewKey.value
|
|
@@ -257,6 +263,7 @@ const wrapper = vue.defineComponent({
|
|
|
257
263
|
function renderDialog() {
|
|
258
264
|
if (dialogStore.state.component.value && dialogStore.state.properties.value) {
|
|
259
265
|
utils.debug.adapter("vue:render:dialog", "Rendering dialog.");
|
|
266
|
+
hijackOnMounted(dialogStore.state.component.value, "dialog");
|
|
260
267
|
return vue.h(dialogStore.state.component.value, {
|
|
261
268
|
...dialogStore.state.properties.value,
|
|
262
269
|
key: dialogStore.state.key.value
|
|
@@ -310,6 +317,11 @@ function setupDevtools(app) {
|
|
|
310
317
|
key: "component",
|
|
311
318
|
value: state.context.value?.view.component
|
|
312
319
|
});
|
|
320
|
+
payload.instanceData.state.push({
|
|
321
|
+
type: hybridlyStateType,
|
|
322
|
+
key: "deferred",
|
|
323
|
+
value: state.context.value?.view.deferred
|
|
324
|
+
});
|
|
313
325
|
payload.instanceData.state.push({
|
|
314
326
|
type: hybridlyStateType,
|
|
315
327
|
key: "dialog",
|
|
@@ -404,8 +416,8 @@ function viewTransition() {
|
|
|
404
416
|
let domUpdated;
|
|
405
417
|
return {
|
|
406
418
|
name: "view-transition",
|
|
407
|
-
navigating: async ({
|
|
408
|
-
if (
|
|
419
|
+
navigating: async ({ type, hasDialog }) => {
|
|
420
|
+
if (type === "initial" || hasDialog) {
|
|
409
421
|
return;
|
|
410
422
|
}
|
|
411
423
|
return new Promise((confirmTransitionStarted) => document.startViewTransition(() => {
|
|
@@ -416,6 +428,10 @@ function viewTransition() {
|
|
|
416
428
|
mounted: () => {
|
|
417
429
|
domUpdated?.();
|
|
418
430
|
domUpdated = void 0;
|
|
431
|
+
},
|
|
432
|
+
navigated: () => {
|
|
433
|
+
domUpdated?.();
|
|
434
|
+
domUpdated = void 0;
|
|
419
435
|
}
|
|
420
436
|
};
|
|
421
437
|
}
|
|
@@ -444,12 +460,16 @@ async function initializeHybridly(options = {}) {
|
|
|
444
460
|
state.setContext(context);
|
|
445
461
|
},
|
|
446
462
|
onViewSwap: async (options2) => {
|
|
447
|
-
|
|
463
|
+
if (options2.component) {
|
|
464
|
+
onMountedCallbacks.push(() => options2.onMounted?.({ isDialog: false }));
|
|
465
|
+
state.setView(options2.component);
|
|
466
|
+
}
|
|
448
467
|
state.setProperties(options2.properties);
|
|
449
468
|
if (!options2.preserveState && !options2.dialog) {
|
|
450
469
|
state.setViewKey(utils.random());
|
|
451
470
|
}
|
|
452
471
|
if (options2.dialog) {
|
|
472
|
+
onMountedCallbacks.push(() => options2.onMounted?.({ isDialog: true }));
|
|
453
473
|
dialogStore.setComponent(await resolve(options2.dialog.component));
|
|
454
474
|
dialogStore.setProperties(options2.dialog.properties);
|
|
455
475
|
dialogStore.setKey(options2.dialog.key);
|
|
@@ -524,8 +544,8 @@ async function resolveViewComponent(name, options) {
|
|
|
524
544
|
const result = options.components.views.find((view) => name === view.identifier);
|
|
525
545
|
const path = Object.keys(components).sort((a, b) => a.length - b.length).find((path2) => result ? path2.endsWith(result?.path) : false);
|
|
526
546
|
if (!result || !path) {
|
|
527
|
-
console.warn(`
|
|
528
|
-
utils.
|
|
547
|
+
console.warn(`View component [${name}] not found. Available components: `, options.components.views.map(({ identifier }) => identifier));
|
|
548
|
+
utils.showViewComponentErrorModal(name);
|
|
529
549
|
return;
|
|
530
550
|
}
|
|
531
551
|
let component = typeof components[path] === "function" ? await components[path]() : components[path];
|
|
@@ -539,6 +559,8 @@ const RouterLink = vue.defineComponent({
|
|
|
539
559
|
return (props) => {
|
|
540
560
|
let data = props.data ?? {};
|
|
541
561
|
const preloads = props.preload ?? false;
|
|
562
|
+
const preserveScroll = props.preserveScroll;
|
|
563
|
+
const preserveState = props.preserveState;
|
|
542
564
|
const url = core.makeUrl(props.href ?? "");
|
|
543
565
|
const method = props.method?.toUpperCase() ?? "GET";
|
|
544
566
|
const as = typeof props.as === "object" ? props.as : props.as?.toLowerCase() ?? "a";
|
|
@@ -578,6 +600,8 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
578
600
|
}
|
|
579
601
|
core.router.preload(url, {
|
|
580
602
|
data,
|
|
603
|
+
preserveScroll,
|
|
604
|
+
preserveState,
|
|
581
605
|
...props.options
|
|
582
606
|
});
|
|
583
607
|
}
|
|
@@ -647,6 +671,14 @@ Please specify a more appropriate element using the "as" attribute. For example:
|
|
|
647
671
|
preload: {
|
|
648
672
|
type: [Boolean, String],
|
|
649
673
|
default: false
|
|
674
|
+
},
|
|
675
|
+
preserveScroll: {
|
|
676
|
+
type: Boolean,
|
|
677
|
+
default: void 0
|
|
678
|
+
},
|
|
679
|
+
preserveState: {
|
|
680
|
+
type: Boolean,
|
|
681
|
+
default: void 0
|
|
650
682
|
}
|
|
651
683
|
}
|
|
652
684
|
});
|
|
@@ -880,7 +912,7 @@ function useHistoryState(key, initial) {
|
|
|
880
912
|
function useBackForward() {
|
|
881
913
|
const callbacks = [];
|
|
882
914
|
core.registerHook("navigated", (options) => {
|
|
883
|
-
if (options.
|
|
915
|
+
if (options.type === "back-forward") {
|
|
884
916
|
callbacks.forEach((fn) => fn(state.context.value));
|
|
885
917
|
callbacks.splice(0, callbacks.length);
|
|
886
918
|
}
|
|
@@ -897,33 +929,6 @@ function useBackForward() {
|
|
|
897
929
|
};
|
|
898
930
|
}
|
|
899
931
|
|
|
900
|
-
function usePaginator(paginator) {
|
|
901
|
-
const meta = paginator.meta ?? paginator;
|
|
902
|
-
const links = meta.links ?? paginator.links;
|
|
903
|
-
const items = links.map((link, index) => {
|
|
904
|
-
return {
|
|
905
|
-
url: link.url,
|
|
906
|
-
label: link.label,
|
|
907
|
-
isPage: !isNaN(+link.label),
|
|
908
|
-
isPrevious: index === 0,
|
|
909
|
-
isNext: index === links.length - 1,
|
|
910
|
-
isCurrent: link.active,
|
|
911
|
-
isSeparator: link.label === "...",
|
|
912
|
-
isActive: !!link.url && !link.active
|
|
913
|
-
};
|
|
914
|
-
});
|
|
915
|
-
const pages = items.filter((item) => item.isPage || item.isSeparator);
|
|
916
|
-
const current = items.find((item) => item.isCurrent);
|
|
917
|
-
const previous = items.find((item) => item.isPrevious);
|
|
918
|
-
const next = items.find((item) => item.isNext);
|
|
919
|
-
const first = { ...items[1], isActive: items[1].url !== current?.url, label: "«" };
|
|
920
|
-
const last = { ...items[items.length - 1], isActive: items[items.length - 1].url !== current?.url, label: "»" };
|
|
921
|
-
const from = meta.from;
|
|
922
|
-
const to = meta.to;
|
|
923
|
-
const total = meta.total;
|
|
924
|
-
return { pages, items, previous, next, first, last, total, from, to };
|
|
925
|
-
}
|
|
926
|
-
|
|
927
932
|
function defineLayout(...args) {
|
|
928
933
|
const layouts = args[0];
|
|
929
934
|
const properties = args[1];
|
|
@@ -1035,9 +1040,9 @@ function useRefinements(properties, refinementsKeys, defaultOptions = {}) {
|
|
|
1035
1040
|
function currentFilters() {
|
|
1036
1041
|
return refinements.value.filters.filter(({ is_active }) => is_active);
|
|
1037
1042
|
}
|
|
1038
|
-
function isSorting(name) {
|
|
1043
|
+
function isSorting(name, direction) {
|
|
1039
1044
|
if (name) {
|
|
1040
|
-
return currentSorts().some((sort) => sort.name === name);
|
|
1045
|
+
return currentSorts().some((sort) => sort.name === name && (direction ? sort.direction === direction : true));
|
|
1041
1046
|
}
|
|
1042
1047
|
return currentSorts().length !== 0;
|
|
1043
1048
|
}
|
|
@@ -1080,11 +1085,35 @@ function useRefinements(properties, refinementsKeys, defaultOptions = {}) {
|
|
|
1080
1085
|
/**
|
|
1081
1086
|
* Available filters.
|
|
1082
1087
|
*/
|
|
1083
|
-
filters: toReactive(refinements.value.filters)
|
|
1088
|
+
filters: toReactive(refinements.value.filters.map((filter) => ({
|
|
1089
|
+
...filter,
|
|
1090
|
+
/**
|
|
1091
|
+
* Applies this filter.
|
|
1092
|
+
*/
|
|
1093
|
+
apply: (value, options) => applyFilter(filter.name, value, options),
|
|
1094
|
+
/**
|
|
1095
|
+
* Clears this filter.
|
|
1096
|
+
*/
|
|
1097
|
+
clear: (options) => clearFilter(filter.name, options)
|
|
1098
|
+
}))),
|
|
1084
1099
|
/**
|
|
1085
1100
|
* Available sorts.
|
|
1086
1101
|
*/
|
|
1087
|
-
sorts: toReactive(refinements.value.sorts)
|
|
1102
|
+
sorts: toReactive(refinements.value.sorts.map((sort) => ({
|
|
1103
|
+
...sort,
|
|
1104
|
+
/**
|
|
1105
|
+
* Toggles this sort.
|
|
1106
|
+
*/
|
|
1107
|
+
toggle: (options) => toggleSort(sort.name, options),
|
|
1108
|
+
/**
|
|
1109
|
+
* Checks if this sort is active.
|
|
1110
|
+
*/
|
|
1111
|
+
isSorting: (direction) => isSorting(sort.name, direction),
|
|
1112
|
+
/**
|
|
1113
|
+
* Clears this sort.
|
|
1114
|
+
*/
|
|
1115
|
+
clear: (options) => clearSorts(options)
|
|
1116
|
+
}))),
|
|
1088
1117
|
/**
|
|
1089
1118
|
* Gets a filter by name.
|
|
1090
1119
|
*/
|
|
@@ -1150,6 +1179,193 @@ function useRoute() {
|
|
|
1150
1179
|
};
|
|
1151
1180
|
}
|
|
1152
1181
|
|
|
1182
|
+
function useBulkSelect() {
|
|
1183
|
+
const selection = vue.ref({
|
|
1184
|
+
all: false,
|
|
1185
|
+
only: /* @__PURE__ */ new Set(),
|
|
1186
|
+
except: /* @__PURE__ */ new Set()
|
|
1187
|
+
});
|
|
1188
|
+
function selectAll() {
|
|
1189
|
+
selection.value.all = true;
|
|
1190
|
+
selection.value.only.clear();
|
|
1191
|
+
selection.value.except.clear();
|
|
1192
|
+
}
|
|
1193
|
+
function deselectAll() {
|
|
1194
|
+
selection.value.all = false;
|
|
1195
|
+
selection.value.only.clear();
|
|
1196
|
+
selection.value.except.clear();
|
|
1197
|
+
}
|
|
1198
|
+
function select(...records) {
|
|
1199
|
+
records.forEach((record) => selection.value.except.delete(record));
|
|
1200
|
+
records.forEach((record) => selection.value.only.add(record));
|
|
1201
|
+
}
|
|
1202
|
+
function deselect(...records) {
|
|
1203
|
+
records.forEach((record) => selection.value.except.add(record));
|
|
1204
|
+
records.forEach((record) => selection.value.only.delete(record));
|
|
1205
|
+
}
|
|
1206
|
+
function toggle(record, force) {
|
|
1207
|
+
if (selected(record) || force === false) {
|
|
1208
|
+
return deselect(record);
|
|
1209
|
+
}
|
|
1210
|
+
if (!selected(record) || force === true) {
|
|
1211
|
+
return select(record);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
function selected(record) {
|
|
1215
|
+
if (selection.value.all) {
|
|
1216
|
+
return !selection.value.except.has(record);
|
|
1217
|
+
}
|
|
1218
|
+
return selection.value.only.has(record);
|
|
1219
|
+
}
|
|
1220
|
+
const allSelected = vue.computed(() => {
|
|
1221
|
+
return selection.value.all && selection.value.except.size === 0;
|
|
1222
|
+
});
|
|
1223
|
+
return {
|
|
1224
|
+
allSelected,
|
|
1225
|
+
selectAll,
|
|
1226
|
+
deselectAll,
|
|
1227
|
+
select,
|
|
1228
|
+
deselect,
|
|
1229
|
+
toggle,
|
|
1230
|
+
selected,
|
|
1231
|
+
selection
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
function useTable(props, key, defaultOptions = {}) {
|
|
1236
|
+
const table = vue.computed(() => props[key]);
|
|
1237
|
+
const bulk = useBulkSelect();
|
|
1238
|
+
const refinements = useRefinements(toReactive(table), "refinements", defaultOptions);
|
|
1239
|
+
function getRecordKey(record) {
|
|
1240
|
+
if (typeof record !== "object") {
|
|
1241
|
+
return record;
|
|
1242
|
+
}
|
|
1243
|
+
if (Reflect.has(record, "__hybridId")) {
|
|
1244
|
+
return Reflect.get(record, "__hybridId");
|
|
1245
|
+
}
|
|
1246
|
+
return Reflect.get(record, table.value.keyName);
|
|
1247
|
+
}
|
|
1248
|
+
function getActionName(action) {
|
|
1249
|
+
return typeof action === "string" ? action : action.name;
|
|
1250
|
+
}
|
|
1251
|
+
async function executeInlineAction(action, record) {
|
|
1252
|
+
return await hybridly.router.navigate({
|
|
1253
|
+
method: "post",
|
|
1254
|
+
url: hybridly.route(table.value.endpoint),
|
|
1255
|
+
preserveState: true,
|
|
1256
|
+
data: {
|
|
1257
|
+
type: "action:inline",
|
|
1258
|
+
action: getActionName(action),
|
|
1259
|
+
tableId: table.value.id,
|
|
1260
|
+
recordId: getRecordKey(record)
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
async function executeBulkAction(action, options) {
|
|
1265
|
+
const actionName = getActionName(action);
|
|
1266
|
+
return await hybridly.router.navigate({
|
|
1267
|
+
method: "post",
|
|
1268
|
+
url: hybridly.route(table.value.endpoint),
|
|
1269
|
+
preserveState: true,
|
|
1270
|
+
data: {
|
|
1271
|
+
type: "action:bulk",
|
|
1272
|
+
action: actionName,
|
|
1273
|
+
tableId: table.value.id,
|
|
1274
|
+
all: bulk.selection.value.all,
|
|
1275
|
+
only: [...bulk.selection.value.only],
|
|
1276
|
+
except: [...bulk.selection.value.except]
|
|
1277
|
+
},
|
|
1278
|
+
hooks: {
|
|
1279
|
+
after: () => {
|
|
1280
|
+
if (options?.deselect === true || table.value.bulkActions.find(({ name }) => name === actionName)?.deselect !== false) {
|
|
1281
|
+
bulk.deselectAll();
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
return vue.reactive({
|
|
1288
|
+
/** Selects all records. */
|
|
1289
|
+
selectAll: bulk.selectAll,
|
|
1290
|
+
/** Deselects all records. */
|
|
1291
|
+
deselectAll: bulk.deselectAll,
|
|
1292
|
+
/** Checks if the given record is selected. */
|
|
1293
|
+
isSelected: (record) => bulk.selected(getRecordKey(record)),
|
|
1294
|
+
/** Whether all records are selected. */
|
|
1295
|
+
allSelected: bulk.allSelected,
|
|
1296
|
+
/** The current record selection. */
|
|
1297
|
+
selection: bulk.selection,
|
|
1298
|
+
/** Toggles selection for the given record. */
|
|
1299
|
+
toggle: (record) => bulk.toggle(getRecordKey(record)),
|
|
1300
|
+
/** Selects selection for the given record. */
|
|
1301
|
+
select: (record) => bulk.select(getRecordKey(record)),
|
|
1302
|
+
/** Deselects selection for the given record. */
|
|
1303
|
+
deselect: (record) => bulk.deselect(getRecordKey(record)),
|
|
1304
|
+
/** List of inline actions for this table. */
|
|
1305
|
+
inlineActions: vue.computed(() => table.value.inlineActions.map((action) => ({
|
|
1306
|
+
/** Executes the action. */
|
|
1307
|
+
execute: (record) => executeInlineAction(action.name, record),
|
|
1308
|
+
...action
|
|
1309
|
+
}))),
|
|
1310
|
+
/** List of bulk actions for this table. */
|
|
1311
|
+
bulkActions: vue.computed(() => table.value.bulkActions.map((action) => ({
|
|
1312
|
+
/** Executes the action. */
|
|
1313
|
+
execute: (options) => executeBulkAction(action.name, options),
|
|
1314
|
+
...action
|
|
1315
|
+
}))),
|
|
1316
|
+
/** Executes the given inline action for the given record. */
|
|
1317
|
+
executeInlineAction,
|
|
1318
|
+
/** Executes the given bulk action. */
|
|
1319
|
+
executeBulkAction,
|
|
1320
|
+
/** List of columns for this table. */
|
|
1321
|
+
columns: vue.computed(() => table.value.columns.map((column) => ({
|
|
1322
|
+
...column,
|
|
1323
|
+
/** Toggles sorting for this column. */
|
|
1324
|
+
toggleSort: (options) => refinements.toggleSort(column.name, options),
|
|
1325
|
+
/** Checks whether the column is being sorted. */
|
|
1326
|
+
isSorting: (direction) => refinements.isSorting(column.name, direction),
|
|
1327
|
+
/** Applies the filer for this column. */
|
|
1328
|
+
applyFilter: (value, options) => refinements.applyFilter(column.name, value, options),
|
|
1329
|
+
/** Clears the filter for this column. */
|
|
1330
|
+
clearFilter: (options) => refinements.clearFilter(column.name, options),
|
|
1331
|
+
/** Checks whether the column is sortable. */
|
|
1332
|
+
isSortable: refinements.sorts.find((sort) => sort.name === column.name),
|
|
1333
|
+
/** Checks whether the column is filterable. */
|
|
1334
|
+
isFilterable: refinements.filters.find((filters) => filters.name === column.name)
|
|
1335
|
+
}))),
|
|
1336
|
+
/** List of records for this table. */
|
|
1337
|
+
records: vue.computed(() => table.value.records.map((record) => ({
|
|
1338
|
+
/** The actual record. */
|
|
1339
|
+
record,
|
|
1340
|
+
/** The key of the record. Use this instead of `id`. */
|
|
1341
|
+
key: getRecordKey(record),
|
|
1342
|
+
/** Executes the given inline action. */
|
|
1343
|
+
execute: (action) => executeInlineAction(getActionName(action), getRecordKey(record)),
|
|
1344
|
+
/** Gets the available inline actions. */
|
|
1345
|
+
actions: table.value.inlineActions.map((action) => ({
|
|
1346
|
+
...action,
|
|
1347
|
+
/** Executes the action. */
|
|
1348
|
+
execute: () => executeInlineAction(action.name, getRecordKey(record))
|
|
1349
|
+
})),
|
|
1350
|
+
/** Selects this record. */
|
|
1351
|
+
select: () => bulk.select(getRecordKey(record)),
|
|
1352
|
+
/** Deselects this record. */
|
|
1353
|
+
deselect: () => bulk.deselect(getRecordKey(record)),
|
|
1354
|
+
/** Toggles the selection for this record. */
|
|
1355
|
+
toggle: (force) => bulk.toggle(getRecordKey(record), force),
|
|
1356
|
+
/** Checks whether this record is selected. */
|
|
1357
|
+
selected: bulk.selected(getRecordKey(record)),
|
|
1358
|
+
/** Gets the value of the record for the specified column. */
|
|
1359
|
+
value: (column) => record[typeof column === "string" ? column : column.name]
|
|
1360
|
+
}))),
|
|
1361
|
+
/**
|
|
1362
|
+
* Paginated meta and links.
|
|
1363
|
+
*/
|
|
1364
|
+
paginator: vue.computed(() => table.value.paginator),
|
|
1365
|
+
...refinements
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1153
1369
|
exports.can = core.can;
|
|
1154
1370
|
exports.route = core.route;
|
|
1155
1371
|
exports.router = core.router;
|
|
@@ -1160,12 +1376,13 @@ exports.initializeHybridly = initializeHybridly;
|
|
|
1160
1376
|
exports.registerHook = registerHook;
|
|
1161
1377
|
exports.setProperty = setProperty;
|
|
1162
1378
|
exports.useBackForward = useBackForward;
|
|
1379
|
+
exports.useBulkSelect = useBulkSelect;
|
|
1163
1380
|
exports.useContext = useContext;
|
|
1164
1381
|
exports.useDialog = useDialog;
|
|
1165
1382
|
exports.useForm = useForm;
|
|
1166
1383
|
exports.useHistoryState = useHistoryState;
|
|
1167
|
-
exports.usePaginator = usePaginator;
|
|
1168
1384
|
exports.useProperties = useProperties;
|
|
1169
1385
|
exports.useProperty = useProperty;
|
|
1170
1386
|
exports.useRefinements = useRefinements;
|
|
1171
1387
|
exports.useRoute = useRoute;
|
|
1388
|
+
exports.useTable = useTable;
|