@hybridly/vue 0.10.0-beta.26 → 0.10.0-beta.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +65 -29
- package/dist/index.mjs +99 -36
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -34,10 +34,8 @@ declare const Deferred: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
34
34
|
type Errors$1<T extends SearchableObject$1> = { [K in keyof T]?: T[K] extends Record<string, any> ? Errors$1<T[K]> : string };
|
|
35
35
|
type FormFieldBehavior$1 = boolean | string[];
|
|
36
36
|
type DefaultFormOptions = Pick<FormOptions<object>, 'timeout' | 'resetOnSuccess' | 'resetOnError' | 'setDefaultOnSuccess' | 'progress' | 'preserveScroll' | 'preserveState' | 'preserveUrl' | 'headers' | 'errorBag' | 'spoof' | 'transformUrl' | 'updateHistoryState' | 'useFormData'>;
|
|
37
|
-
|
|
38
|
-
fields: T;
|
|
37
|
+
type FormSubmitOptions$1<T extends SearchableObject$1> = Omit<HybridRequestOptions, 'data' | 'url' | 'reset'> & {
|
|
39
38
|
url?: UrlResolvable | (() => UrlResolvable);
|
|
40
|
-
key?: string | false;
|
|
41
39
|
/**
|
|
42
40
|
* Defines the delay after which the `recentlySuccessful` and `recentlyFailed` variables are reset to `false`.
|
|
43
41
|
*/
|
|
@@ -61,6 +59,27 @@ interface FormOptions<T extends SearchableObject$1> extends Omit<HybridRequestOp
|
|
|
61
59
|
* Callback executed before the form submission for transforming the fields.
|
|
62
60
|
*/
|
|
63
61
|
transform?: (fields: T) => any;
|
|
62
|
+
};
|
|
63
|
+
type FormAutomaticallySubmitOptions<T extends SearchableObject$1> = true | (FormSubmitOptions$1<T> & {
|
|
64
|
+
/**
|
|
65
|
+
* Debounce delay in milliseconds before submitting automatically.
|
|
66
|
+
* @default 100
|
|
67
|
+
*/
|
|
68
|
+
debounce?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Whether to immediately submit the form on any change. If `false`, submits after the `debounce` delay.
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
immediate?: boolean;
|
|
74
|
+
});
|
|
75
|
+
interface FormOptions<T extends SearchableObject$1> extends FormSubmitOptions$1<T> {
|
|
76
|
+
fields: T;
|
|
77
|
+
key?: string | false;
|
|
78
|
+
/**
|
|
79
|
+
* Automatically submits the form when fields change.
|
|
80
|
+
* Pass `true` to use defaults or an object to customize submit overrides and debounce delay.
|
|
81
|
+
*/
|
|
82
|
+
automaticallySubmit?: FormAutomaticallySubmitOptions<T>;
|
|
64
83
|
}
|
|
65
84
|
interface FormReturn<T extends SearchableObject$1, P extends Path$1<T> & string = Path$1<T> & string> {
|
|
66
85
|
resetFields: (...keys: P[]) => void;
|
|
@@ -74,7 +93,7 @@ interface FormReturn<T extends SearchableObject$1, P extends Path$1<T> & string
|
|
|
74
93
|
clearError: (key: P) => void;
|
|
75
94
|
setDefault: (newDefault: Partial<T>) => void;
|
|
76
95
|
hasDirty: (...keys: P[]) => boolean;
|
|
77
|
-
submit: (optionsOverrides?:
|
|
96
|
+
submit: (optionsOverrides?: FormSubmitOptions$1<T>) => Promise<any>;
|
|
78
97
|
hasErrors: boolean;
|
|
79
98
|
defaults: DeepReadonly<T>;
|
|
80
99
|
loaded: DeepReadonly<T>;
|
|
@@ -292,7 +311,7 @@ declare const WhenVisible: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
|
292
311
|
}>> & Readonly<{
|
|
293
312
|
onLoading?: ((_state: LoadStateSlotProps) => any) | undefined;
|
|
294
313
|
}>, {
|
|
295
|
-
options: Omit<HybridRequestOptions, "
|
|
314
|
+
options: Omit<HybridRequestOptions, "data" | "method" | "url">;
|
|
296
315
|
as: string;
|
|
297
316
|
buffer: number;
|
|
298
317
|
root: string | Element | null;
|
|
@@ -325,6 +344,14 @@ interface BulkSelection<T = any> {
|
|
|
325
344
|
/** Excluded records. */
|
|
326
345
|
except: Set<T>;
|
|
327
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Returns the inclusive range between two records in the given order.
|
|
349
|
+
*
|
|
350
|
+
* This is useful for implementing shift-click bulk selection: keep track of the last selected anchor,
|
|
351
|
+
* then pass the currently visible record identifiers and the clicked target identifier to this helper.
|
|
352
|
+
* If the target is not in the list, an empty range is returned. If the anchor is missing, only the target is returned.
|
|
353
|
+
*/
|
|
354
|
+
declare function getBulkSelectionRange<T>(records: readonly T[], anchor: T | undefined, target: T): T[];
|
|
328
355
|
declare function useBulkSelect<T = any>(): {
|
|
329
356
|
allSelected: vue.ComputedRef<boolean>;
|
|
330
357
|
anySelected: vue.ComputedRef<boolean>;
|
|
@@ -1052,12 +1079,13 @@ declare const registerHook: typeof registerHook$1;
|
|
|
1052
1079
|
//#region src/composables/table.d.ts
|
|
1053
1080
|
interface Table<T extends Record<string, any> = any, PaginatorKind extends 'cursor' | 'length-aware' | 'simple' = 'length-aware'> {
|
|
1054
1081
|
id: string;
|
|
1055
|
-
keyName:
|
|
1082
|
+
keyName: keyof T | null;
|
|
1056
1083
|
scope?: string;
|
|
1057
1084
|
columns: Column<T>[];
|
|
1058
1085
|
inlineActions: InlineAction[];
|
|
1059
1086
|
bulkActions: BulkAction[];
|
|
1060
1087
|
records: Array<T>;
|
|
1088
|
+
cells: TableCellRow<T>[];
|
|
1061
1089
|
paginator: Omit<PaginatorKind extends 'cursor' ? CursorPaginator<T> : (PaginatorKind extends 'simple' ? SimplePaginator<T> : Paginator<T>), 'data'>;
|
|
1062
1090
|
refinements: Refinements;
|
|
1063
1091
|
endpoint: string;
|
|
@@ -1072,6 +1100,14 @@ interface Column<T extends object = never> {
|
|
|
1072
1100
|
/** Metadata of this column. */
|
|
1073
1101
|
metadata: Record<string, any>;
|
|
1074
1102
|
}
|
|
1103
|
+
interface TableCell<T extends object = never> {
|
|
1104
|
+
value: any;
|
|
1105
|
+
extra: Record<string, any>;
|
|
1106
|
+
}
|
|
1107
|
+
interface TableCellRow<T extends object = never> {
|
|
1108
|
+
key: RecordIdentifier | null;
|
|
1109
|
+
columns: Partial<Record<keyof T | string, TableCell<T>>>;
|
|
1110
|
+
}
|
|
1075
1111
|
interface Action {
|
|
1076
1112
|
/** The name of this action. */
|
|
1077
1113
|
name: string;
|
|
@@ -1094,10 +1130,6 @@ interface BulkActionOptions extends Omit<HybridRequestOptions, 'url'> {
|
|
|
1094
1130
|
}
|
|
1095
1131
|
interface InlineAction extends Action {}
|
|
1096
1132
|
type RecordIdentifier = string | number;
|
|
1097
|
-
type AsRecordTypeWithExtra<T extends Record<string, any>> = { [K in keyof T]: {
|
|
1098
|
-
extra: Record<string, any>;
|
|
1099
|
-
value: T[K];
|
|
1100
|
-
} };
|
|
1101
1133
|
interface TableDefaultOptions extends AvailableHybridRequestOptions {
|
|
1102
1134
|
/**
|
|
1103
1135
|
* Whether to include existing query parameters in the request.
|
|
@@ -1113,15 +1145,15 @@ type UseTableNavigationResponse = Promise<_hybridly_core0.NavigationResponse | u
|
|
|
1113
1145
|
type ExtractRefValue<T> = T extends {
|
|
1114
1146
|
value: infer Value;
|
|
1115
1147
|
} ? Value : T;
|
|
1116
|
-
interface UseTableInlineActionItem<RecordType extends Record<string, any
|
|
1148
|
+
interface UseTableInlineActionItem<RecordType extends Record<string, any>> extends InlineAction {
|
|
1117
1149
|
/** Executes the action. */
|
|
1118
|
-
execute: (record:
|
|
1150
|
+
execute: (record: RecordIdentifier | RecordType) => UseTableNavigationResponse;
|
|
1119
1151
|
}
|
|
1120
1152
|
interface UseTableBulkActionItem extends BulkAction {
|
|
1121
1153
|
/** Executes the action. */
|
|
1122
1154
|
execute: (options?: BulkActionOptions) => UseTableNavigationResponse;
|
|
1123
1155
|
}
|
|
1124
|
-
interface UseTableColumn<
|
|
1156
|
+
interface UseTableColumn<RecordType extends Record<string, any>> extends Column<RecordType> {
|
|
1125
1157
|
/** Toggles sorting for this column. */
|
|
1126
1158
|
toggleSort: (options?: ToggleSortOptions) => UseTableNavigationResponse;
|
|
1127
1159
|
/** Checks whether the column is being sorted. */
|
|
@@ -1135,11 +1167,15 @@ interface UseTableColumn<RecordTypeWithExtra extends Record<string, any>> extend
|
|
|
1135
1167
|
/** Checks whether the column is filterable. */
|
|
1136
1168
|
isFilterable: boolean;
|
|
1137
1169
|
}
|
|
1138
|
-
interface UseTableRecordItem<RecordType extends Record<string, any
|
|
1170
|
+
interface UseTableRecordItem<RecordType extends Record<string, any>> {
|
|
1139
1171
|
/** The actual record. */
|
|
1140
1172
|
record: RecordType;
|
|
1141
|
-
/**
|
|
1173
|
+
/** Local key of the record. Use this as a rendering key. */
|
|
1142
1174
|
key: RecordIdentifier;
|
|
1175
|
+
/** Server-side key of the record, if any. */
|
|
1176
|
+
recordKey: RecordIdentifier | undefined;
|
|
1177
|
+
/** Whether this record has a server-side key. */
|
|
1178
|
+
hasKey: boolean;
|
|
1143
1179
|
/** Executes the given inline action. */
|
|
1144
1180
|
execute: (action: string | InlineAction) => UseTableNavigationResponse;
|
|
1145
1181
|
/** Gets the available inline actions. */
|
|
@@ -1155,11 +1191,11 @@ interface UseTableRecordItem<RecordType extends Record<string, any>, RecordTypeW
|
|
|
1155
1191
|
/** Checks whether this record is selected. */
|
|
1156
1192
|
selected: boolean;
|
|
1157
1193
|
/** Gets the value of the record for the specified column. */
|
|
1158
|
-
value: (column: string | Column<
|
|
1194
|
+
value: (column: string | Column<RecordType>) => any;
|
|
1159
1195
|
/** Gets the extra object of the record for the specified column. */
|
|
1160
|
-
extra: (column: string | Column<
|
|
1196
|
+
extra: (column: string | Column<RecordType>, path: string) => any;
|
|
1161
1197
|
}
|
|
1162
|
-
interface UseTableReturn<T extends Table<any, any>, RecordType extends Record<string, any> = (T extends Table<infer R, any> ? R : any), PaginatorKind extends 'cursor' | 'length-aware' | 'simple' = (T extends Table<any, infer P> ? P : 'length-aware')
|
|
1198
|
+
interface UseTableReturn<T extends Table<any, any>, RecordType extends Record<string, any> = (T extends Table<infer R, any> ? R : any), PaginatorKind extends 'cursor' | 'length-aware' | 'simple' = (T extends Table<any, infer P> ? P : 'length-aware')> extends Omit<UseRefinements, 'filters' | 'sorts' | 'filtersKey' | 'sortsKey'> {
|
|
1163
1199
|
/** Selects all records. */
|
|
1164
1200
|
selectAll: () => void;
|
|
1165
1201
|
/** Deselects all records. */
|
|
@@ -1171,7 +1207,7 @@ interface UseTableReturn<T extends Table<any, any>, RecordType extends Record<st
|
|
|
1171
1207
|
/** Whether all records on the current page are selected. */
|
|
1172
1208
|
isPageSelected: boolean;
|
|
1173
1209
|
/** Checks if the given record is selected. */
|
|
1174
|
-
isSelected: (record:
|
|
1210
|
+
isSelected: (record: RecordType) => boolean;
|
|
1175
1211
|
/** Whether all records are selected. */
|
|
1176
1212
|
allSelected: boolean;
|
|
1177
1213
|
/** Whether any records are selected. */
|
|
@@ -1185,33 +1221,33 @@ interface UseTableReturn<T extends Table<any, any>, RecordType extends Record<st
|
|
|
1185
1221
|
value: RecordIdentifier;
|
|
1186
1222
|
};
|
|
1187
1223
|
/** Toggles selection for the given record. */
|
|
1188
|
-
toggle: (record:
|
|
1224
|
+
toggle: (record: RecordType, force?: boolean) => void;
|
|
1189
1225
|
/** Toggles selection for all records. */
|
|
1190
1226
|
toggleAll: (force?: boolean) => void;
|
|
1191
1227
|
/** Selects selection for the given record. */
|
|
1192
|
-
select: (record:
|
|
1228
|
+
select: (record: RecordType) => void;
|
|
1193
1229
|
/** Deselects selection for the given record. */
|
|
1194
|
-
deselect: (record:
|
|
1230
|
+
deselect: (record: RecordType) => void;
|
|
1195
1231
|
/** List of inline actions for this table. */
|
|
1196
|
-
inlineActions: Array<UseTableInlineActionItem<RecordType
|
|
1232
|
+
inlineActions: Array<UseTableInlineActionItem<RecordType>>;
|
|
1197
1233
|
/** List of bulk actions for this table. */
|
|
1198
1234
|
bulkActions: Array<UseTableBulkActionItem>;
|
|
1199
1235
|
/** Executes the given inline action for the given record. */
|
|
1200
1236
|
executeInlineAction: (action: InlineAction | string, options: {
|
|
1201
|
-
record:
|
|
1237
|
+
record: RecordIdentifier | RecordType;
|
|
1202
1238
|
} & Omit<HybridRequestOptions, 'url'>) => UseTableNavigationResponse;
|
|
1203
1239
|
/** Executes the given bulk action. */
|
|
1204
1240
|
executeBulkAction: (action: BulkAction | string, options?: Omit<HybridRequestOptions, 'url'> & {
|
|
1205
1241
|
deselect?: boolean;
|
|
1206
1242
|
}) => UseTableNavigationResponse;
|
|
1207
1243
|
/** List of columns for this table. */
|
|
1208
|
-
columns: Array<UseTableColumn<
|
|
1244
|
+
columns: Array<UseTableColumn<RecordType>>;
|
|
1209
1245
|
/** List of records for this table. */
|
|
1210
1246
|
data: RecordType[];
|
|
1211
1247
|
/** List of records for this table. */
|
|
1212
|
-
records: Array<UseTableRecordItem<RecordType
|
|
1248
|
+
records: Array<UseTableRecordItem<RecordType>>;
|
|
1213
1249
|
/** Paginated meta and links. */
|
|
1214
|
-
paginator: PaginatorResult<
|
|
1250
|
+
paginator: PaginatorResult<RecordType, Table<RecordType, PaginatorKind>['paginator']>;
|
|
1215
1251
|
/** Available filters. */
|
|
1216
1252
|
filters: ExtractRefValue<UseRefinements['filters']>;
|
|
1217
1253
|
/** Available sorts. */
|
|
@@ -1224,7 +1260,7 @@ interface UseTableReturn<T extends Table<any, any>, RecordType extends Record<st
|
|
|
1224
1260
|
/**
|
|
1225
1261
|
* Provides utilities for working with tables.
|
|
1226
1262
|
*/
|
|
1227
|
-
declare function useTable<T extends Table<any, any>, RecordType extends Record<string, any> = (T extends Table<infer R, any> ? R : any), PaginatorKind extends 'cursor' | 'length-aware' | 'simple' = (T extends Table<any, infer P> ? P : 'length-aware')
|
|
1263
|
+
declare function useTable<T extends Table<any, any>, RecordType extends Record<string, any> = (T extends Table<infer R, any> ? R : any), PaginatorKind extends 'cursor' | 'length-aware' | 'simple' = (T extends Table<any, infer P> ? P : 'length-aware')>(input: MaybeRefOrGetter<T>, defaultOptions?: TableDefaultOptions): UseTableReturn<T, RecordType, PaginatorKind>;
|
|
1228
1264
|
//#endregion
|
|
1229
1265
|
//#region src/composables/validation.d.ts
|
|
1230
1266
|
/** Accesses all validation errors grouped by bag name. */
|
|
@@ -1322,4 +1358,4 @@ interface SetupArguments {
|
|
|
1322
1358
|
payload: Record<string, any>;
|
|
1323
1359
|
}
|
|
1324
1360
|
//#endregion
|
|
1325
|
-
export { Action, AvailableHybridRequestOptions, AvailableHybridRequestOptionsForFilters, BaseFilterRefinement, BindFilterOptions, BooleanFilterRefinement, BoundBooleanFilterRefinement, BoundCallbackFilterRefinement, BoundDateFilterRefinement, BoundFilterRefinement, BoundSelectFilterRefinement, BoundSortRefinement, BoundTernaryFilterRefinement, BoundTextFilterRefinement, BoundTrashedFilterRefinement, BulkAction, BulkSelection, CallbackFilterRefinement, Column, DateFilterRefinement, DefaultFormOptions, Deferred, FilterOperator, FilterRefinement, Form, type FormProps, FormReturn, type FormSlotProps, type FormSubmitOptions, type InitializeOptions, InlineAction, InternalProperties, MaybeWithData, NumericFilterRefinement, PaginatorResult, RecordIdentifier, Refinements, RouterLink, SelectFilterRefinement, SortDirection, SortRefinement, Table, TableDefaultOptions, TernaryFilterRefinement, TextFilterRefinement, TimeSuggestion, TimeframeSuggestion, ToggleSortOptions, TrashedFilterRefinement, UseRefinements, UseTableBulkActionItem, UseTableColumn, UseTableInlineActionItem, UseTableRecordItem, UseTableReturn, WhenVisible, createPaginator, initializeHybridly, isBooleanFilter, isCallbackFilter, isDateFilter, isSelectFilter, isTernaryFilter, isTextFilter, isTrashedFilter, registerHook, route, router, setProperty, useBackForward, useBulkSelect, useDialog, useForm, useHistoryState, useProperties, useProperty, useQueryParameter, useQueryParameters, useRefinements, useRoute, useTable, useValidation, useValidationBag };
|
|
1361
|
+
export { Action, AvailableHybridRequestOptions, AvailableHybridRequestOptionsForFilters, BaseFilterRefinement, BindFilterOptions, BooleanFilterRefinement, BoundBooleanFilterRefinement, BoundCallbackFilterRefinement, BoundDateFilterRefinement, BoundFilterRefinement, BoundSelectFilterRefinement, BoundSortRefinement, BoundTernaryFilterRefinement, BoundTextFilterRefinement, BoundTrashedFilterRefinement, BulkAction, BulkSelection, CallbackFilterRefinement, Column, DateFilterRefinement, DefaultFormOptions, Deferred, FilterOperator, FilterRefinement, Form, type FormProps, FormReturn, type FormSlotProps, type FormSubmitOptions, type InitializeOptions, InlineAction, InternalProperties, MaybeWithData, NumericFilterRefinement, PaginatorResult, RecordIdentifier, Refinements, RouterLink, SelectFilterRefinement, SortDirection, SortRefinement, Table, TableCell, TableCellRow, TableDefaultOptions, TernaryFilterRefinement, TextFilterRefinement, TimeSuggestion, TimeframeSuggestion, ToggleSortOptions, TrashedFilterRefinement, UseRefinements, UseTableBulkActionItem, UseTableColumn, UseTableInlineActionItem, UseTableRecordItem, UseTableReturn, WhenVisible, createPaginator, getBulkSelectionRange, initializeHybridly, isBooleanFilter, isCallbackFilter, isDateFilter, isSelectFilter, isTernaryFilter, isTextFilter, isTrashedFilter, registerHook, route, router, setProperty, useBackForward, useBulkSelect, useDialog, useForm, useHistoryState, useProperties, useProperty, useQueryParameter, useQueryParameters, useRefinements, useRoute, useTable, useValidation, useValidationBag };
|
package/dist/index.mjs
CHANGED
|
@@ -3,11 +3,11 @@ import { debug, merge, random, showViewComponentErrorModal, wrap } from "@hybrid
|
|
|
3
3
|
import { computed, createApp, defineComponent, getCurrentInstance, h, isRef, nextTick, onMounted, onUnmounted, reactive, readonly, ref, shallowRef, toRaw, toValue, triggerRef, unref, watch } from "vue";
|
|
4
4
|
import { createRouter, definePlugin, makeUrl, parseQueryString, registerHook as registerHook$1, route, route as route$1, router, router as router$1, stringifyQueryString } from "@hybridly/core";
|
|
5
5
|
import { get, set, unset } from "es-toolkit/compat";
|
|
6
|
+
import { debounce } from "es-toolkit/function";
|
|
6
7
|
import { clone, cloneDeep } from "es-toolkit/object";
|
|
7
8
|
import { isEqual } from "es-toolkit/predicate";
|
|
8
9
|
import { setupDevtoolsPlugin } from "@vue/devtools-api";
|
|
9
10
|
import nprogress from "nprogress";
|
|
10
|
-
import { debounce } from "es-toolkit/function";
|
|
11
11
|
import { getByPath } from "@clickbar/dot-diver";
|
|
12
12
|
//#region src/stores/state.ts
|
|
13
13
|
const state = {
|
|
@@ -216,7 +216,7 @@ function useForm(options) {
|
|
|
216
216
|
* Submits the form.
|
|
217
217
|
*/
|
|
218
218
|
function submit(optionsOverrides) {
|
|
219
|
-
const { fields: _f, key: _k, ...optionsWithoutFields } = options;
|
|
219
|
+
const { fields: _f, key: _k, automaticallySubmit: _as, ...optionsWithoutFields } = options;
|
|
220
220
|
const resolvedOptions = optionsOverrides ? merge(optionsWithoutFields, optionsOverrides, { mergePlainObjects: true }) : optionsWithoutFields;
|
|
221
221
|
const { timeout, resetOnSuccess, resetOnError, setDefaultOnSuccess, transform, ...requestOptions } = merge(formStore.getDefaultConfig(), resolvedOptions, { mergePlainObjects: true });
|
|
222
222
|
const url = typeof requestOptions.url === "function" ? requestOptions.url() : requestOptions.url;
|
|
@@ -274,6 +274,23 @@ function useForm(options) {
|
|
|
274
274
|
}
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
|
+
if (options.automaticallySubmit) {
|
|
278
|
+
const submitOptions = options.automaticallySubmit === true ? void 0 : (() => {
|
|
279
|
+
const { debounce: _debounce, ...submitOptions } = options.automaticallySubmit;
|
|
280
|
+
return submitOptions;
|
|
281
|
+
})();
|
|
282
|
+
const automaticallySubmitOptions = options.automaticallySubmit === true ? {
|
|
283
|
+
debounce: 100,
|
|
284
|
+
immediate: true
|
|
285
|
+
} : options.automaticallySubmit;
|
|
286
|
+
watch(() => fields, debounce(() => {
|
|
287
|
+
if (!isDirty.value) return;
|
|
288
|
+
submit(submitOptions);
|
|
289
|
+
}, automaticallySubmitOptions.debounce ?? 100), {
|
|
290
|
+
deep: true,
|
|
291
|
+
immediate: automaticallySubmitOptions.immediate ?? true
|
|
292
|
+
});
|
|
293
|
+
}
|
|
277
294
|
/**
|
|
278
295
|
* Clears all errors.
|
|
279
296
|
*/
|
|
@@ -1373,6 +1390,21 @@ function useBackForward(options) {
|
|
|
1373
1390
|
}
|
|
1374
1391
|
//#endregion
|
|
1375
1392
|
//#region src/composables/bulk-select.ts
|
|
1393
|
+
/**
|
|
1394
|
+
* Returns the inclusive range between two records in the given order.
|
|
1395
|
+
*
|
|
1396
|
+
* This is useful for implementing shift-click bulk selection: keep track of the last selected anchor,
|
|
1397
|
+
* then pass the currently visible record identifiers and the clicked target identifier to this helper.
|
|
1398
|
+
* If the target is not in the list, an empty range is returned. If the anchor is missing, only the target is returned.
|
|
1399
|
+
*/
|
|
1400
|
+
function getBulkSelectionRange(records, anchor, target) {
|
|
1401
|
+
const targetIndex = records.indexOf(target);
|
|
1402
|
+
if (targetIndex === -1) return [];
|
|
1403
|
+
if (anchor === void 0) return [target];
|
|
1404
|
+
const anchorIndex = records.indexOf(anchor);
|
|
1405
|
+
if (anchorIndex === -1) return [target];
|
|
1406
|
+
return records.slice(Math.min(anchorIndex, targetIndex), Math.max(anchorIndex, targetIndex) + 1);
|
|
1407
|
+
}
|
|
1376
1408
|
function useBulkSelect() {
|
|
1377
1409
|
const selection = ref({
|
|
1378
1410
|
all: false,
|
|
@@ -1921,11 +1953,24 @@ function useTable(input, defaultOptions = {}) {
|
|
|
1921
1953
|
*/
|
|
1922
1954
|
function getRecordKey(record) {
|
|
1923
1955
|
if (typeof record !== "object") return record;
|
|
1924
|
-
if (
|
|
1925
|
-
if (!table.value.keyName) throw new Error("Record key cannot be fetched because the table has no defined key.");
|
|
1956
|
+
if (!table.value.keyName) return;
|
|
1926
1957
|
const value = Reflect.get(record, table.value.keyName);
|
|
1927
|
-
if (typeof value === "
|
|
1928
|
-
|
|
1958
|
+
if (typeof value === "string" || typeof value === "number") return value;
|
|
1959
|
+
}
|
|
1960
|
+
function getPageRecordKeys() {
|
|
1961
|
+
return table.value.records.map((record) => getRecordKey(record)).filter((key) => key !== void 0);
|
|
1962
|
+
}
|
|
1963
|
+
function warnMissingRecordKey(action) {
|
|
1964
|
+
console.warn(`Cannot ${action} because this table record has no key.`);
|
|
1965
|
+
}
|
|
1966
|
+
function getColumnName(column) {
|
|
1967
|
+
return typeof column === "string" ? column : column.name;
|
|
1968
|
+
}
|
|
1969
|
+
function getCell(index, column) {
|
|
1970
|
+
return table.value.cells[index]?.columns[getColumnName(column)] ?? {
|
|
1971
|
+
value: void 0,
|
|
1972
|
+
extra: {}
|
|
1973
|
+
};
|
|
1929
1974
|
}
|
|
1930
1975
|
function resolveInlineAction(action) {
|
|
1931
1976
|
if (typeof action !== "string") return action;
|
|
@@ -1944,10 +1989,15 @@ function useTable(input, defaultOptions = {}) {
|
|
|
1944
1989
|
*/
|
|
1945
1990
|
async function executeInlineAction(action, options) {
|
|
1946
1991
|
const resolvedAction = resolveInlineAction(action);
|
|
1992
|
+
const recordKey = getRecordKey(options.record);
|
|
1947
1993
|
if (!resolvedAction) {
|
|
1948
1994
|
console.warn(`Action [${action}] is not defined`);
|
|
1949
1995
|
return;
|
|
1950
1996
|
}
|
|
1997
|
+
if (recordKey === void 0) {
|
|
1998
|
+
warnMissingRecordKey("execute an inline action");
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
1951
2001
|
return await router$1.navigate({
|
|
1952
2002
|
method: "post",
|
|
1953
2003
|
url: getActionUrl(resolvedAction, table.value),
|
|
@@ -1957,7 +2007,7 @@ function useTable(input, defaultOptions = {}) {
|
|
|
1957
2007
|
type: "action:inline",
|
|
1958
2008
|
action: resolvedAction.name,
|
|
1959
2009
|
tableId: table.value.id,
|
|
1960
|
-
recordId:
|
|
2010
|
+
recordId: recordKey
|
|
1961
2011
|
}
|
|
1962
2012
|
});
|
|
1963
2013
|
}
|
|
@@ -1996,20 +2046,35 @@ function useTable(input, defaultOptions = {}) {
|
|
|
1996
2046
|
});
|
|
1997
2047
|
}
|
|
1998
2048
|
return reactive({
|
|
1999
|
-
selectAll: bulk.selectAll,
|
|
2049
|
+
selectAll: () => table.value.keyName ? bulk.selectAll() : warnMissingRecordKey("select all records"),
|
|
2000
2050
|
deselectAll: bulk.deselectAll,
|
|
2001
|
-
selectPage: () => bulk.select(...
|
|
2002
|
-
deselectPage: () => bulk.deselect(...
|
|
2003
|
-
isPageSelected: computed(() =>
|
|
2004
|
-
|
|
2051
|
+
selectPage: () => bulk.select(...getPageRecordKeys()),
|
|
2052
|
+
deselectPage: () => bulk.deselect(...getPageRecordKeys()),
|
|
2053
|
+
isPageSelected: computed(() => {
|
|
2054
|
+
const keys = getPageRecordKeys();
|
|
2055
|
+
return keys.length > 0 && keys.every((key) => bulk.selected(key));
|
|
2056
|
+
}),
|
|
2057
|
+
isSelected: (record) => {
|
|
2058
|
+
const key = getRecordKey(record);
|
|
2059
|
+
return key === void 0 ? false : bulk.selected(key);
|
|
2060
|
+
},
|
|
2005
2061
|
allSelected: bulk.allSelected,
|
|
2006
2062
|
anySelected: bulk.anySelected,
|
|
2007
2063
|
selection: bulk.selection,
|
|
2008
2064
|
bindCheckbox: (key) => bulk.bindCheckbox(key),
|
|
2009
|
-
toggle: (record, force) =>
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2065
|
+
toggle: (record, force) => {
|
|
2066
|
+
const key = getRecordKey(record);
|
|
2067
|
+
return key === void 0 ? warnMissingRecordKey("toggle record selection") : bulk.toggle(key, force);
|
|
2068
|
+
},
|
|
2069
|
+
toggleAll: (force) => table.value.keyName ? bulk.toggleAll(force) : warnMissingRecordKey("toggle all records"),
|
|
2070
|
+
select: (record) => {
|
|
2071
|
+
const key = getRecordKey(record);
|
|
2072
|
+
return key === void 0 ? warnMissingRecordKey("select this record") : bulk.select(key);
|
|
2073
|
+
},
|
|
2074
|
+
deselect: (record) => {
|
|
2075
|
+
const key = getRecordKey(record);
|
|
2076
|
+
return key === void 0 ? warnMissingRecordKey("deselect this record") : bulk.deselect(key);
|
|
2077
|
+
},
|
|
2013
2078
|
inlineActions: computed(() => table.value.inlineActions.map((action) => ({
|
|
2014
2079
|
execute: (record) => executeInlineAction(action, { record }),
|
|
2015
2080
|
...action
|
|
@@ -2029,29 +2094,27 @@ function useTable(input, defaultOptions = {}) {
|
|
|
2029
2094
|
isSortable: !!refinements.sorts.value.find((sort) => sort.name === column.name),
|
|
2030
2095
|
isFilterable: !!refinements.filters.value.find((filters) => filters.name === column.name)
|
|
2031
2096
|
}))),
|
|
2032
|
-
data: computed(() =>
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
}).filter(Boolean);
|
|
2038
|
-
}),
|
|
2039
|
-
records: computed(() => table.value.records.map((record) => {
|
|
2040
|
-
const entries = Object.entries(record).map(([key, value]) => [key, value.value]).filter(([key]) => key !== "__hybridId");
|
|
2097
|
+
data: computed(() => table.value.records),
|
|
2098
|
+
records: computed(() => table.value.records.map((record, index) => {
|
|
2099
|
+
const recordKey = getRecordKey(record);
|
|
2100
|
+
const localKey = recordKey ?? `row-${index}`;
|
|
2101
|
+
const selected = recordKey === void 0 ? false : bulk.selected(recordKey);
|
|
2041
2102
|
return {
|
|
2042
|
-
record
|
|
2043
|
-
key:
|
|
2044
|
-
|
|
2103
|
+
record,
|
|
2104
|
+
key: localKey,
|
|
2105
|
+
recordKey,
|
|
2106
|
+
hasKey: recordKey !== void 0,
|
|
2107
|
+
execute: (action) => executeInlineAction(action, { record }),
|
|
2045
2108
|
actions: table.value.inlineActions.map((action) => ({
|
|
2046
2109
|
...action,
|
|
2047
|
-
execute: () => executeInlineAction(action.name, { record
|
|
2110
|
+
execute: () => executeInlineAction(action.name, { record })
|
|
2048
2111
|
})),
|
|
2049
|
-
select: () => bulk.select(
|
|
2050
|
-
deselect: () => bulk.deselect(
|
|
2051
|
-
toggle: (force) => bulk.toggle(
|
|
2052
|
-
selected
|
|
2053
|
-
value: (column) =>
|
|
2054
|
-
extra: (column, path) => getByPath(
|
|
2112
|
+
select: () => recordKey === void 0 ? warnMissingRecordKey("select this record") : bulk.select(recordKey),
|
|
2113
|
+
deselect: () => recordKey === void 0 ? warnMissingRecordKey("deselect this record") : bulk.deselect(recordKey),
|
|
2114
|
+
toggle: (force) => recordKey === void 0 ? warnMissingRecordKey("toggle record selection") : bulk.toggle(recordKey, force),
|
|
2115
|
+
selected,
|
|
2116
|
+
value: (column) => getCell(index, column).value,
|
|
2117
|
+
extra: (column, path) => getByPath(getCell(index, column).extra, path)
|
|
2055
2118
|
};
|
|
2056
2119
|
})),
|
|
2057
2120
|
paginator: computed(() => createPaginator(table.value.paginator, defaultOptions)),
|
|
@@ -2069,4 +2132,4 @@ function useValidationBag(bag = "default") {
|
|
|
2069
2132
|
return readonly(toReactive(computed(() => state.context.value?.validation?.[bag] ?? {})));
|
|
2070
2133
|
}
|
|
2071
2134
|
//#endregion
|
|
2072
|
-
export { Deferred, Form, RouterLink, WhenVisible, createPaginator, initializeHybridly, isBooleanFilter, isCallbackFilter, isDateFilter, isSelectFilter, isTernaryFilter, isTextFilter, isTrashedFilter, registerHook, route, router, setProperty, useBackForward, useBulkSelect, useDialog, useForm, useHistoryState, useProperties, useProperty, useQueryParameter, useQueryParameters, useRefinements, useRoute, useTable, useValidation, useValidationBag };
|
|
2135
|
+
export { Deferred, Form, RouterLink, WhenVisible, createPaginator, getBulkSelectionRange, initializeHybridly, isBooleanFilter, isCallbackFilter, isDateFilter, isSelectFilter, isTernaryFilter, isTextFilter, isTrashedFilter, registerHook, route, router, setProperty, useBackForward, useBulkSelect, useDialog, useForm, useHistoryState, useProperties, useProperty, useQueryParameter, useQueryParameters, useRefinements, useRoute, useTable, useValidation, useValidationBag };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridly/vue",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.10.0-beta.
|
|
4
|
+
"version": "0.10.0-beta.27",
|
|
5
5
|
"description": "Vue adapter for Hybridly",
|
|
6
6
|
"author": "Enzo Innocenzi <enzo@innocenzi.dev>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@clickbar/dot-diver": "^1.0.7",
|
|
49
49
|
"es-toolkit": "^1.45.1",
|
|
50
|
-
"@hybridly/core": "0.10.0-beta.
|
|
51
|
-
"@hybridly/utils": "0.10.0-beta.
|
|
50
|
+
"@hybridly/core": "0.10.0-beta.27",
|
|
51
|
+
"@hybridly/utils": "0.10.0-beta.27",
|
|
52
52
|
"@vue/devtools-api": "^8.1.0",
|
|
53
53
|
"defu": "^6.1.4",
|
|
54
54
|
"nprogress": "^0.2.0"
|