@directus/composables 11.1.11 → 11.2.1
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.ts +904 -6
- package/dist/index.js +6 -5
- package/package.json +14 -13
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AppCollection, Field, Item, Query, RefRecord } from '@directus/types';
|
|
2
2
|
import { ComputedRef, Ref, WritableComputedRef, Component } from 'vue';
|
|
3
|
-
import { AppExtensionConfigs } from '@directus/extensions';
|
|
3
|
+
import { LayoutConfig, AppExtensionConfigs } from '@directus/extensions';
|
|
4
4
|
import { DirectusClient, RestClient } from '@directus/sdk';
|
|
5
5
|
import { AxiosInstance } from 'axios';
|
|
6
6
|
|
|
@@ -14,22 +14,133 @@ type UsableCollection = {
|
|
|
14
14
|
isSingleton: ComputedRef<boolean>;
|
|
15
15
|
accountabilityScope: ComputedRef<'all' | 'activity' | null>;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* A Vue composable that provides reactive access to collection metadata, fields, and computed properties.
|
|
19
|
+
*
|
|
20
|
+
* This composable serves as a centralized way to access and work with Directus collections,
|
|
21
|
+
* providing reactive computed properties for collection information, field definitions,
|
|
22
|
+
* default values, and various collection-specific metadata.
|
|
23
|
+
*
|
|
24
|
+
* @param collectionKey - The collection identifier. Can be a string or a reactive reference to a string.
|
|
25
|
+
* If null, most computed properties will return empty/null values.
|
|
26
|
+
*
|
|
27
|
+
* @returns An object containing reactive computed properties for the collection:
|
|
28
|
+
* - `info` - The complete collection configuration object or null if not found
|
|
29
|
+
* - `fields` - Array of sorted field definitions for the collection
|
|
30
|
+
* - `defaults` - Object mapping field names to their default values from schema
|
|
31
|
+
* - `primaryKeyField` - The field marked as primary key, or null if none exists
|
|
32
|
+
* - `userCreatedField` - The field with 'user_created' special type, or null if none exists
|
|
33
|
+
* - `sortField` - The field name used for sorting, from collection meta, or null
|
|
34
|
+
* - `isSingleton` - Boolean indicating if the collection is configured as a singleton
|
|
35
|
+
* - `accountabilityScope` - The accountability scope setting ('all', 'activity', or null)
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Using with a static collection name
|
|
40
|
+
* const { info, fields, primaryKeyField } = useCollection('users');
|
|
41
|
+
*
|
|
42
|
+
* // Using with a reactive collection name
|
|
43
|
+
* const collectionName = ref('articles');
|
|
44
|
+
* const { fields, defaults, isSingleton } = useCollection(collectionName);
|
|
45
|
+
*
|
|
46
|
+
* // Accessing properties
|
|
47
|
+
* console.log(info.value?.name); // Collection display name
|
|
48
|
+
* console.log(fields.value.length); // Number of fields
|
|
49
|
+
* console.log(primaryKeyField.value?.field); // Primary key field name
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
17
52
|
declare function useCollection(collectionKey: string | Ref<string | null>): UsableCollection;
|
|
18
53
|
|
|
19
54
|
type UsableCustomSelection = {
|
|
20
55
|
otherValue: Ref<string | null>;
|
|
21
56
|
usesOtherValue: ComputedRef<boolean>;
|
|
22
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* A Vue composable for managing custom selection values that aren't present in a predefined list of items.
|
|
60
|
+
*
|
|
61
|
+
* This composable is typically used in form components where users can select from a predefined list
|
|
62
|
+
* of options, but also have the ability to enter custom values that aren't in the list. It manages
|
|
63
|
+
* the state and logic for detecting when a custom value is being used and provides a reactive
|
|
64
|
+
* interface for getting and setting custom values.
|
|
65
|
+
*
|
|
66
|
+
* @param currentValue - A reactive reference to the currently selected value. Can be null if no value is selected.
|
|
67
|
+
* @param items - A reactive reference to the array of available predefined items. Each item should have a 'value' property.
|
|
68
|
+
* @param emit - A callback function to emit value changes to the parent component.
|
|
69
|
+
*
|
|
70
|
+
* @returns An object containing:
|
|
71
|
+
* - `otherValue` - A computed ref for getting/setting custom values. Returns current value when using custom,
|
|
72
|
+
* empty string otherwise. Setting triggers the emit callback.
|
|
73
|
+
* - `usesOtherValue` - A computed boolean indicating whether the current value is a custom value
|
|
74
|
+
* (not found in the predefined items list).
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const currentValue = ref('custom-option');
|
|
79
|
+
* const items = ref([
|
|
80
|
+
* { value: 'option1', label: 'Option 1' },
|
|
81
|
+
* { value: 'option2', label: 'Option 2' }
|
|
82
|
+
* ]);
|
|
83
|
+
* const emit = (value: string | null) => console.log('Value changed:', value);
|
|
84
|
+
*
|
|
85
|
+
* const { otherValue, usesOtherValue } = useCustomSelection(currentValue, items, emit);
|
|
86
|
+
*
|
|
87
|
+
* console.log(usesOtherValue.value); // true (custom-option not in items)
|
|
88
|
+
* console.log(otherValue.value); // 'custom-option'
|
|
89
|
+
*
|
|
90
|
+
* otherValue.value = 'new-custom-value'; // Triggers emit with 'new-custom-value'
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
23
93
|
declare function useCustomSelection(currentValue: Ref<string | null>, items: Ref<any[]>, emit: (event: string | null) => void): UsableCustomSelection;
|
|
24
94
|
type OtherValue = {
|
|
25
95
|
key: string;
|
|
26
96
|
value: string;
|
|
97
|
+
focus?: boolean;
|
|
27
98
|
};
|
|
28
99
|
type UsableCustomSelectionMultiple = {
|
|
29
100
|
otherValues: Ref<OtherValue[]>;
|
|
30
|
-
addOtherValue: (value?: string) => void;
|
|
101
|
+
addOtherValue: (value?: string, focus?: boolean) => void;
|
|
31
102
|
setOtherValue: (key: string, newValue: string | null) => void;
|
|
32
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* A Vue composable for managing multiple custom selection values that aren't present in a predefined list of items.
|
|
106
|
+
*
|
|
107
|
+
* This composable extends the single custom selection pattern to support multiple values. It's typically used
|
|
108
|
+
* in multi-select form components where users can select multiple predefined options and also add custom
|
|
109
|
+
* values that aren't in the predefined list. It automatically detects custom values in the current selection,
|
|
110
|
+
* manages their state, and provides functions for adding and updating custom values.
|
|
111
|
+
*
|
|
112
|
+
* @param currentValues - A reactive reference to the currently selected values array. Can be null if no values are selected.
|
|
113
|
+
* @param items - A reactive reference to the array of available predefined items. Each item should have a 'value' property.
|
|
114
|
+
* @param emit - A callback function to emit value changes to the parent component.
|
|
115
|
+
*
|
|
116
|
+
* @returns An object containing:
|
|
117
|
+
* - `otherValues` - A reactive array of custom value objects, each with a unique key, value, and optional focus state.
|
|
118
|
+
* - `addOtherValue` - A function to add a new custom value with optional value and focus parameters.
|
|
119
|
+
* - `setOtherValue` - A function to update or remove a custom value by its key, automatically syncing with currentValues.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const currentValues = ref(['option1', 'custom-value1', 'custom-value2']);
|
|
124
|
+
* const items = ref([
|
|
125
|
+
* { value: 'option1', label: 'Option 1' },
|
|
126
|
+
* { value: 'option2', label: 'Option 2' }
|
|
127
|
+
* ]);
|
|
128
|
+
* const emit = (values: string[] | null) => console.log('Values changed:', values);
|
|
129
|
+
*
|
|
130
|
+
* const { otherValues, addOtherValue, setOtherValue } = useCustomSelectionMultiple(currentValues, items, emit);
|
|
131
|
+
*
|
|
132
|
+
* console.log(otherValues.value); // [{ key: 'abc123', value: 'custom-value1' }, { key: 'def456', value: 'custom-value2' }]
|
|
133
|
+
*
|
|
134
|
+
* // Add a new custom value
|
|
135
|
+
* addOtherValue('new-custom-value', true);
|
|
136
|
+
*
|
|
137
|
+
* // Update an existing custom value
|
|
138
|
+
* setOtherValue('abc123', 'updated-custom-value');
|
|
139
|
+
*
|
|
140
|
+
* // Remove a custom value
|
|
141
|
+
* setOtherValue('def456', null);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
33
144
|
declare function useCustomSelectionMultiple(currentValues: Ref<string[] | null>, items: Ref<any[]>, emit: (event: string[] | null) => void): UsableCustomSelectionMultiple;
|
|
34
145
|
|
|
35
146
|
declare global {
|
|
@@ -37,56 +148,239 @@ declare global {
|
|
|
37
148
|
ResizeObserver: any;
|
|
38
149
|
}
|
|
39
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* A Vue composable that reactively tracks the size of a DOM element using ResizeObserver.
|
|
153
|
+
*
|
|
154
|
+
* @template T - The type of the element being observed, must extend Element
|
|
155
|
+
* @param target - The element to observe. Can be:
|
|
156
|
+
* - A direct element reference
|
|
157
|
+
* - A Vue ref containing an element
|
|
158
|
+
* - A Vue ref that might be undefined
|
|
159
|
+
*
|
|
160
|
+
* @returns An object containing reactive width and height values:
|
|
161
|
+
* - width: Ref<number> - The current width of the element in pixels
|
|
162
|
+
* - height: Ref<number> - The current height of the element in pixels
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // With a template ref
|
|
167
|
+
* const elementRef = ref<HTMLDivElement>();
|
|
168
|
+
* const { width, height } = useElementSize(elementRef);
|
|
169
|
+
*
|
|
170
|
+
* // With a direct element
|
|
171
|
+
* const element = document.getElementById('my-element');
|
|
172
|
+
* const { width, height } = useElementSize(element);
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* @remarks
|
|
176
|
+
* - The composable automatically sets up a ResizeObserver when the component mounts
|
|
177
|
+
* - The observer is automatically disconnected when the component unmounts
|
|
178
|
+
* - Initial values are 0 until the first resize event
|
|
179
|
+
* - Handles cases where the target element might be undefined
|
|
180
|
+
*/
|
|
40
181
|
declare function useElementSize<T extends Element>(target: T | Ref<T> | Ref<undefined>): {
|
|
41
182
|
width: Ref<number>;
|
|
42
183
|
height: Ref<number>;
|
|
43
184
|
};
|
|
44
185
|
|
|
186
|
+
/**
|
|
187
|
+
* A Vue composable that filters and groups fields based on multiple filter criteria.
|
|
188
|
+
*
|
|
189
|
+
* @template T - The type of filter names as string literals
|
|
190
|
+
* @param fields - A Vue ref containing an array of Field objects to be filtered
|
|
191
|
+
* @param filters - An object where keys are filter names and values are predicate functions
|
|
192
|
+
* that return true if a field should be included in that group
|
|
193
|
+
*
|
|
194
|
+
* @returns An object containing:
|
|
195
|
+
* - fieldGroups: ComputedRef<Record<Extract<T, string>, Field[]>> - A reactive object
|
|
196
|
+
* where each key corresponds to a filter name and the value is an array of fields
|
|
197
|
+
* that pass that filter
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* // Define filter criteria
|
|
202
|
+
* const fieldFilters = {
|
|
203
|
+
* required: (field: Field) => field.required === true,
|
|
204
|
+
* optional: (field: Field) => field.required !== true,
|
|
205
|
+
* text: (field: Field) => field.type === 'string',
|
|
206
|
+
* numeric: (field: Field) => ['integer', 'float', 'decimal'].includes(field.type)
|
|
207
|
+
* };
|
|
208
|
+
*
|
|
209
|
+
* const fieldsRef = ref<Field[]>([
|
|
210
|
+
* { name: 'id', type: 'integer', required: true },
|
|
211
|
+
* { name: 'title', type: 'string', required: true },
|
|
212
|
+
* { name: 'description', type: 'text', required: false },
|
|
213
|
+
* { name: 'price', type: 'decimal', required: false }
|
|
214
|
+
* ]);
|
|
215
|
+
*
|
|
216
|
+
* const { fieldGroups } = useFilterFields(fieldsRef, fieldFilters);
|
|
217
|
+
*
|
|
218
|
+
* // Access filtered groups
|
|
219
|
+
* console.log(fieldGroups.value.required); // [id, title]
|
|
220
|
+
* console.log(fieldGroups.value.text); // [title]
|
|
221
|
+
* console.log(fieldGroups.value.numeric); // [id, price]
|
|
222
|
+
* ```
|
|
223
|
+
*
|
|
224
|
+
* @remarks
|
|
225
|
+
* - Fields can appear in multiple groups if they pass multiple filters
|
|
226
|
+
* - If a field doesn't pass any filter, it won't appear in any group
|
|
227
|
+
* - The result is reactive and will update when the input fields change
|
|
228
|
+
* - Filter functions are called for each field against each filter criterion
|
|
229
|
+
* - Groups are initialized as empty arrays even if no fields match the criteria
|
|
230
|
+
*/
|
|
45
231
|
declare function useFilterFields<T extends string>(fields: Ref<Field[]>, filters: Record<T, (field: Field) => boolean>): {
|
|
46
232
|
fieldGroups: ComputedRef<Record<Extract<T, string>, Field[]>>;
|
|
47
233
|
};
|
|
48
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Represents a groupable item instance with its active state and value.
|
|
237
|
+
*/
|
|
49
238
|
type GroupableInstance = {
|
|
239
|
+
/** Reactive reference to the active state of the item */
|
|
50
240
|
active: Ref<boolean>;
|
|
241
|
+
/** Unique identifier for the item within the group */
|
|
51
242
|
value: string | number | undefined;
|
|
52
243
|
};
|
|
53
244
|
/**
|
|
245
|
+
* Configuration options for the useGroupable composable.
|
|
54
246
|
* Used to make child item part of the group context. Needs to be used in a component that is a child
|
|
55
|
-
* of a component that has the `useGroupableParent` composition enabled
|
|
247
|
+
* of a component that has the `useGroupableParent` composition enabled.
|
|
56
248
|
*/
|
|
57
249
|
type GroupableOptions = {
|
|
250
|
+
/** Unique identifier for this groupable item */
|
|
58
251
|
value?: string | number;
|
|
252
|
+
/** Name of the group to inject from (defaults to 'item-group') */
|
|
59
253
|
group?: string;
|
|
254
|
+
/** External reactive reference to control the active state */
|
|
60
255
|
active?: Ref<boolean>;
|
|
256
|
+
/** Whether to watch the external active reference for changes */
|
|
61
257
|
watch?: boolean;
|
|
62
258
|
};
|
|
259
|
+
/**
|
|
260
|
+
* Return type for the useGroupable composable.
|
|
261
|
+
*/
|
|
63
262
|
type UsableGroupable = {
|
|
263
|
+
/** Reactive reference to the active state */
|
|
64
264
|
active: Ref<boolean>;
|
|
265
|
+
/** Toggle the active state of this item */
|
|
65
266
|
toggle: () => void;
|
|
267
|
+
/** Activate this item (if not already active) */
|
|
66
268
|
activate: () => void;
|
|
269
|
+
/** Deactivate this item (if currently active) */
|
|
67
270
|
deactivate: () => void;
|
|
68
271
|
};
|
|
272
|
+
/**
|
|
273
|
+
* Vue composable for creating groupable child items that can participate in group selection.
|
|
274
|
+
*
|
|
275
|
+
* This composable enables a component to be part of a group context managed by a parent component
|
|
276
|
+
* using `useGroupableParent`. It provides reactive active state management and selection control.
|
|
277
|
+
*
|
|
278
|
+
* @param options - Configuration options for the groupable item
|
|
279
|
+
* @param options.value - Unique identifier for this item within the group
|
|
280
|
+
* @param options.group - Name of the group to inject from (defaults to 'item-group')
|
|
281
|
+
* @param options.active - External reactive reference to control the active state
|
|
282
|
+
* @param options.watch - Whether to watch the external active reference for changes
|
|
283
|
+
*
|
|
284
|
+
* @returns Object containing active state and control methods
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```vue
|
|
288
|
+
* <script setup>
|
|
289
|
+
* import { useGroupable } from '@directus/composables';
|
|
290
|
+
*
|
|
291
|
+
* const props = defineProps(['value', 'active']);
|
|
292
|
+
*
|
|
293
|
+
* const { active, toggle, activate, deactivate } = useGroupable({
|
|
294
|
+
* value: props.value,
|
|
295
|
+
* active: toRef(props, 'active'),
|
|
296
|
+
* watch: true
|
|
297
|
+
* });
|
|
298
|
+
* </script>
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
69
301
|
declare function useGroupable(options?: GroupableOptions): UsableGroupable;
|
|
302
|
+
/**
|
|
303
|
+
* State configuration for the groupable parent.
|
|
304
|
+
*/
|
|
70
305
|
type GroupableParentState = {
|
|
306
|
+
/** External selection state (can be readonly) */
|
|
71
307
|
selection?: Ref<(string | number)[] | undefined> | Ref<readonly (string | number)[] | undefined>;
|
|
308
|
+
/** Callback fired when the selection changes */
|
|
72
309
|
onSelectionChange?: (newSelectionValues: readonly (string | number)[]) => void;
|
|
310
|
+
/** Callback fired when an item is toggled */
|
|
73
311
|
onToggle?: (item: GroupableInstance) => void;
|
|
74
312
|
};
|
|
313
|
+
/**
|
|
314
|
+
* Configuration options for the groupable parent.
|
|
315
|
+
*/
|
|
75
316
|
type GroupableParentOptions = {
|
|
317
|
+
/** Whether at least one item must always be selected */
|
|
76
318
|
mandatory?: Ref<boolean>;
|
|
319
|
+
/** Maximum number of items that can be selected (-1 for unlimited) */
|
|
77
320
|
max?: Ref<number>;
|
|
321
|
+
/** Whether multiple items can be selected simultaneously */
|
|
78
322
|
multiple?: Ref<boolean>;
|
|
79
323
|
};
|
|
324
|
+
/**
|
|
325
|
+
* Return type for the useGroupableParent composable.
|
|
326
|
+
*/
|
|
80
327
|
type UsableGroupableParent = {
|
|
328
|
+
/** Reactive array of all registered groupable items */
|
|
81
329
|
items: Ref<GroupableInstance[]>;
|
|
330
|
+
/** Computed selection array (readonly) */
|
|
82
331
|
selection: Ref<readonly (string | number)[]>;
|
|
332
|
+
/** Internal selection state */
|
|
83
333
|
internalSelection: Ref<(string | number)[]>;
|
|
334
|
+
/** Get the value identifier for a given item */
|
|
84
335
|
getValueForItem: (item: GroupableInstance) => string | number;
|
|
336
|
+
/** Synchronize children's active state with selection */
|
|
85
337
|
updateChildren: () => void;
|
|
86
338
|
};
|
|
87
339
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
340
|
+
* Vue composable for creating a group parent that manages multiple groupable child items.
|
|
341
|
+
*
|
|
342
|
+
* This composable provides the foundation for components that need to manage a collection
|
|
343
|
+
* of selectable items, such as tabs, radio groups, or multi-select lists. It handles
|
|
344
|
+
* registration of child items, selection state management, and provides various selection
|
|
345
|
+
* constraints (mandatory, maximum, multiple).
|
|
346
|
+
*
|
|
347
|
+
* @param state - External state configuration for selection management
|
|
348
|
+
* @param state.selection - External selection state reference
|
|
349
|
+
* @param state.onSelectionChange - Callback fired when selection changes
|
|
350
|
+
* @param state.onToggle - Callback fired when an item is toggled
|
|
351
|
+
* @param options - Configuration options for selection behavior
|
|
352
|
+
* @param options.mandatory - Whether at least one item must always be selected
|
|
353
|
+
* @param options.max - Maximum number of items that can be selected (-1 for unlimited)
|
|
354
|
+
* @param options.multiple - Whether multiple items can be selected simultaneously
|
|
355
|
+
* @param group - Injection key for the group (defaults to 'item-group')
|
|
356
|
+
*
|
|
357
|
+
* @returns Object containing items array, selection state, and utility functions
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
* ```vue
|
|
361
|
+
* <script setup>
|
|
362
|
+
* import { useGroupableParent } from '@directus/composables';
|
|
363
|
+
* import { ref } from 'vue';
|
|
364
|
+
*
|
|
365
|
+
* const selectedItems = ref([]);
|
|
366
|
+
* const isMultiple = ref(true);
|
|
367
|
+
* const isMandatory = ref(false);
|
|
368
|
+
*
|
|
369
|
+
* const { items, selection } = useGroupableParent(
|
|
370
|
+
* {
|
|
371
|
+
* selection: selectedItems,
|
|
372
|
+
* onSelectionChange: (values) => {
|
|
373
|
+
* console.log('Selection changed:', values);
|
|
374
|
+
* }
|
|
375
|
+
* },
|
|
376
|
+
* {
|
|
377
|
+
* multiple: isMultiple,
|
|
378
|
+
* mandatory: isMandatory,
|
|
379
|
+
* max: ref(3)
|
|
380
|
+
* }
|
|
381
|
+
* );
|
|
382
|
+
* </script>
|
|
383
|
+
* ```
|
|
90
384
|
*/
|
|
91
385
|
declare function useGroupableParent(state?: GroupableParentState, options?: GroupableParentOptions, group?: string): UsableGroupableParent;
|
|
92
386
|
|
|
@@ -120,10 +414,127 @@ type ComputedQuery = {
|
|
|
120
414
|
};
|
|
121
415
|
declare function useItems(collection: Ref<string | null>, query: ComputedQuery): UsableItems;
|
|
122
416
|
|
|
417
|
+
declare const WRITABLE_PROPS: readonly ["selection", "layoutOptions", "layoutQuery"];
|
|
418
|
+
type WritableProp = (typeof WRITABLE_PROPS)[number];
|
|
419
|
+
/**
|
|
420
|
+
* Type guard to check if a property is writable (can be updated via emit).
|
|
421
|
+
*
|
|
422
|
+
* This function determines whether a given property name corresponds to one of the
|
|
423
|
+
* writable properties that can be updated through Vue's emit system.
|
|
424
|
+
*
|
|
425
|
+
* @param prop - The property name to check
|
|
426
|
+
* @returns True if the property is writable, false otherwise
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```typescript
|
|
430
|
+
* if (isWritableProp('selection')) {
|
|
431
|
+
* // Property is writable, can emit update
|
|
432
|
+
* emit('update:selection', newValue);
|
|
433
|
+
* }
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
declare function isWritableProp(prop: string): prop is WritableProp;
|
|
437
|
+
/**
|
|
438
|
+
* Creates a Vue component wrapper for a layout configuration.
|
|
439
|
+
*
|
|
440
|
+
* This function creates a dynamic Vue component that wraps a layout with standardized
|
|
441
|
+
* props, emits, and state management. It handles reactive state updates, prop validation,
|
|
442
|
+
* and provides a consistent interface for all layout components.
|
|
443
|
+
*
|
|
444
|
+
* @template Options - The type for layout-specific options
|
|
445
|
+
* @template Query - The type for layout-specific query parameters
|
|
446
|
+
* @param layout - The layout configuration object containing id and setup function
|
|
447
|
+
* @returns A Vue component that can be used to render the layout
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* ```typescript
|
|
451
|
+
* interface MyLayoutOptions {
|
|
452
|
+
* itemSize: number;
|
|
453
|
+
* showHeaders: boolean;
|
|
454
|
+
* }
|
|
455
|
+
*
|
|
456
|
+
* interface MyLayoutQuery {
|
|
457
|
+
* page: number;
|
|
458
|
+
* limit: number;
|
|
459
|
+
* }
|
|
460
|
+
*
|
|
461
|
+
* const layoutConfig: LayoutConfig = {
|
|
462
|
+
* id: 'my-layout',
|
|
463
|
+
* setup: (props, { emit }) => ({
|
|
464
|
+
* // Layout-specific setup logic
|
|
465
|
+
* })
|
|
466
|
+
* };
|
|
467
|
+
*
|
|
468
|
+
* const LayoutWrapper = createLayoutWrapper<MyLayoutOptions, MyLayoutQuery>(layoutConfig);
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
471
|
+
declare function createLayoutWrapper<Options, Query>(layout: LayoutConfig): Component;
|
|
472
|
+
/**
|
|
473
|
+
* Composable for managing layout components in Directus.
|
|
474
|
+
*
|
|
475
|
+
* This composable provides access to layout components and handles the dynamic
|
|
476
|
+
* selection of layout wrappers based on the provided layout ID. It automatically
|
|
477
|
+
* falls back to the tabular layout if the requested layout is not found.
|
|
478
|
+
*
|
|
479
|
+
* @template Options - The type for layout-specific options (default: any)
|
|
480
|
+
* @template Query - The type for layout-specific query parameters (default: any)
|
|
481
|
+
* @param layoutId - A reactive reference to the layout ID
|
|
482
|
+
* @returns An object containing the layout wrapper component
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* import { ref } from 'vue';
|
|
487
|
+
* import { useLayout } from './use-layout';
|
|
488
|
+
*
|
|
489
|
+
* const selectedLayoutId = ref('table');
|
|
490
|
+
* const { layoutWrapper } = useLayout(selectedLayoutId);
|
|
491
|
+
*
|
|
492
|
+
* // Use the layout wrapper in your template
|
|
493
|
+
* // <component :is="layoutWrapper" :collection="'users'" />
|
|
494
|
+
* ```
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* ```typescript
|
|
498
|
+
* // With typed options and query
|
|
499
|
+
* interface TableOptions {
|
|
500
|
+
* spacing: 'cozy' | 'comfortable' | 'compact';
|
|
501
|
+
* showHeaders: boolean;
|
|
502
|
+
* }
|
|
503
|
+
*
|
|
504
|
+
* interface TableQuery {
|
|
505
|
+
* sort: string[];
|
|
506
|
+
* limit: number;
|
|
507
|
+
* }
|
|
508
|
+
*
|
|
509
|
+
* const layoutId = ref<string | null>('table');
|
|
510
|
+
* const { layoutWrapper } = useLayout<TableOptions, TableQuery>(layoutId);
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
123
513
|
declare function useLayout<Options = any, Query = any>(layoutId: Ref<string | null>): {
|
|
124
514
|
layoutWrapper: ComputedRef<Component>;
|
|
125
515
|
};
|
|
126
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Vue props definition for size-related boolean properties.
|
|
519
|
+
*
|
|
520
|
+
* This object defines the standard size props that can be used in Vue components
|
|
521
|
+
* to control size-based styling through CSS classes.
|
|
522
|
+
*
|
|
523
|
+
* @example
|
|
524
|
+
* ```typescript
|
|
525
|
+
* // In a Vue component
|
|
526
|
+
* export default defineComponent({
|
|
527
|
+
* props: {
|
|
528
|
+
* ...sizeProps,
|
|
529
|
+
* // other props
|
|
530
|
+
* },
|
|
531
|
+
* setup(props) {
|
|
532
|
+
* const sizeClass = useSizeClass(props);
|
|
533
|
+
* return { sizeClass };
|
|
534
|
+
* }
|
|
535
|
+
* });
|
|
536
|
+
* ```
|
|
537
|
+
*/
|
|
127
538
|
declare const sizeProps: {
|
|
128
539
|
xSmall: {
|
|
129
540
|
type: BooleanConstructor;
|
|
@@ -148,13 +559,500 @@ interface SizeProps {
|
|
|
148
559
|
large?: boolean;
|
|
149
560
|
xLarge?: boolean;
|
|
150
561
|
}
|
|
562
|
+
/**
|
|
563
|
+
* Composable for generating CSS size class names based on size props.
|
|
564
|
+
*
|
|
565
|
+
* This composable takes props containing size boolean flags and returns a computed
|
|
566
|
+
* CSS class name string. It follows a priority order: xSmall > small > large > xLarge.
|
|
567
|
+
* If no size props are true, it returns null.
|
|
568
|
+
*
|
|
569
|
+
* @template T - The type of additional props that extend SizeProps
|
|
570
|
+
* @param props - The props object containing size boolean properties
|
|
571
|
+
* @returns A computed ref that resolves to the appropriate CSS class name or null
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```typescript
|
|
575
|
+
* // Basic usage in a Vue component
|
|
576
|
+
* const props = { small: true, large: false };
|
|
577
|
+
* const sizeClass = useSizeClass(props);
|
|
578
|
+
* console.log(sizeClass.value); // 'small'
|
|
579
|
+
* ```
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```typescript
|
|
583
|
+
* // Usage with additional props
|
|
584
|
+
* interface MyProps {
|
|
585
|
+
* color: string;
|
|
586
|
+
* disabled: boolean;
|
|
587
|
+
* }
|
|
588
|
+
*
|
|
589
|
+
* const props: MyProps & SizeProps = {
|
|
590
|
+
* color: 'blue',
|
|
591
|
+
* disabled: false,
|
|
592
|
+
* xLarge: true
|
|
593
|
+
* };
|
|
594
|
+
*
|
|
595
|
+
* const sizeClass = useSizeClass(props);
|
|
596
|
+
* console.log(sizeClass.value); // 'x-large'
|
|
597
|
+
* ```
|
|
598
|
+
*
|
|
599
|
+
* @example
|
|
600
|
+
* ```typescript
|
|
601
|
+
* // In a Vue component with reactive props
|
|
602
|
+
* export default defineComponent({
|
|
603
|
+
* props: {
|
|
604
|
+
* ...sizeProps,
|
|
605
|
+
* label: String,
|
|
606
|
+
* },
|
|
607
|
+
* setup(props) {
|
|
608
|
+
* const sizeClass = useSizeClass(props);
|
|
609
|
+
*
|
|
610
|
+
* return { sizeClass };
|
|
611
|
+
* },
|
|
612
|
+
* template: `
|
|
613
|
+
* <button :class="['btn', sizeClass]">
|
|
614
|
+
* {{ label }}
|
|
615
|
+
* </button>
|
|
616
|
+
* `
|
|
617
|
+
* });
|
|
618
|
+
* ```
|
|
619
|
+
*/
|
|
151
620
|
declare function useSizeClass<T>(props: T & SizeProps): ComputedRef<string | null>;
|
|
152
621
|
|
|
622
|
+
/**
|
|
623
|
+
* Composable for creating two-way binding between parent and child components.
|
|
624
|
+
*
|
|
625
|
+
* @deprecated Use Vue's native `defineModel()` instead. This composable is kept for backward compatibility.
|
|
626
|
+
* Vue 3.4+ provides `defineModel()` which offers a more streamlined and performant way to create v-model bindings.
|
|
627
|
+
*
|
|
628
|
+
* @see {@link https://vuejs.org/api/sfc-script-setup.html#definemodel} Vue's defineModel documentation
|
|
629
|
+
*
|
|
630
|
+
* This composable creates a computed ref that synchronizes a prop value with
|
|
631
|
+
* its parent component through Vue's v-model pattern. It provides a getter
|
|
632
|
+
* that returns the current prop value and a setter that emits an update event
|
|
633
|
+
* to notify the parent component of changes.
|
|
634
|
+
*
|
|
635
|
+
* This is particularly useful for creating custom form components that need
|
|
636
|
+
* to work with v-model while maintaining proper data flow patterns.
|
|
637
|
+
*
|
|
638
|
+
* @template T - The type of the props object
|
|
639
|
+
* @template K - The key of the prop to sync (must be a string key of T)
|
|
640
|
+
* @template E - The emit function type with proper event typing
|
|
641
|
+
*
|
|
642
|
+
* @param props - The component props object containing the value to sync
|
|
643
|
+
* @param key - The specific prop key to create a two-way binding for
|
|
644
|
+
* @param emit - The Vue emit function for sending update events to parent
|
|
645
|
+
*
|
|
646
|
+
* @returns A computed ref that can be used with v-model pattern
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```typescript
|
|
650
|
+
* // DEPRECATED: Old way using useSync
|
|
651
|
+
* export default defineComponent({
|
|
652
|
+
* props: {
|
|
653
|
+
* modelValue: String,
|
|
654
|
+
* disabled: Boolean,
|
|
655
|
+
* },
|
|
656
|
+
* emits: ['update:modelValue'],
|
|
657
|
+
* setup(props, { emit }) {
|
|
658
|
+
* const syncedValue = useSync(props, 'modelValue', emit);
|
|
659
|
+
* return { syncedValue };
|
|
660
|
+
* }
|
|
661
|
+
* });
|
|
662
|
+
*
|
|
663
|
+
* // RECOMMENDED: New way using defineModel (Vue 3.4+)
|
|
664
|
+
* <script setup lang="ts">
|
|
665
|
+
* const modelValue = defineModel<string>();
|
|
666
|
+
* const disabled = defineProps<{ disabled?: boolean }>();
|
|
667
|
+
* </script>
|
|
668
|
+
*
|
|
669
|
+
* <template>
|
|
670
|
+
* <input v-model="modelValue" :disabled="disabled" />
|
|
671
|
+
* </template>
|
|
672
|
+
* ```
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```typescript
|
|
676
|
+
* // DEPRECATED: Custom input component with useSync
|
|
677
|
+
* interface Props {
|
|
678
|
+
* value: string;
|
|
679
|
+
* placeholder?: string;
|
|
680
|
+
* type?: string;
|
|
681
|
+
* }
|
|
682
|
+
*
|
|
683
|
+
* export default defineComponent({
|
|
684
|
+
* props: {
|
|
685
|
+
* value: { type: String, required: true },
|
|
686
|
+
* placeholder: String,
|
|
687
|
+
* type: { type: String, default: 'text' },
|
|
688
|
+
* },
|
|
689
|
+
* emits: ['update:value'],
|
|
690
|
+
* setup(props: Props, { emit }) {
|
|
691
|
+
* const syncedValue = useSync(props, 'value', emit);
|
|
692
|
+
* return { syncedValue };
|
|
693
|
+
* }
|
|
694
|
+
* });
|
|
695
|
+
*
|
|
696
|
+
* // RECOMMENDED: Using defineModel with custom prop name
|
|
697
|
+
* <script setup lang="ts">
|
|
698
|
+
* const value = defineModel<string>('value', { required: true });
|
|
699
|
+
* const { placeholder, type = 'text' } = defineProps<{
|
|
700
|
+
* placeholder?: string;
|
|
701
|
+
* type?: string;
|
|
702
|
+
* }>();
|
|
703
|
+
* </script>
|
|
704
|
+
* ```
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* ```typescript
|
|
708
|
+
* // DEPRECATED: Usage with complex objects using useSync
|
|
709
|
+
* interface UserData {
|
|
710
|
+
* name: string;
|
|
711
|
+
* email: string;
|
|
712
|
+
* age: number;
|
|
713
|
+
* }
|
|
714
|
+
*
|
|
715
|
+
* export default defineComponent({
|
|
716
|
+
* props: {
|
|
717
|
+
* userData: { type: Object as PropType<UserData>, required: true },
|
|
718
|
+
* isLoading: Boolean,
|
|
719
|
+
* },
|
|
720
|
+
* emits: ['update:userData'],
|
|
721
|
+
* setup(props, { emit }) {
|
|
722
|
+
* const syncedUserData = useSync(props, 'userData', emit);
|
|
723
|
+
*
|
|
724
|
+
* const updateName = (newName: string) => {
|
|
725
|
+
* syncedUserData.value = {
|
|
726
|
+
* ...syncedUserData.value,
|
|
727
|
+
* name: newName
|
|
728
|
+
* };
|
|
729
|
+
* };
|
|
730
|
+
*
|
|
731
|
+
* return { syncedUserData, updateName };
|
|
732
|
+
* }
|
|
733
|
+
* });
|
|
734
|
+
*
|
|
735
|
+
* // RECOMMENDED: Using defineModel with complex objects
|
|
736
|
+
* <script setup lang="ts">
|
|
737
|
+
* interface UserData {
|
|
738
|
+
* name: string;
|
|
739
|
+
* email: string;
|
|
740
|
+
* age: number;
|
|
741
|
+
* }
|
|
742
|
+
*
|
|
743
|
+
* const userData = defineModel<UserData>('userData', { required: true });
|
|
744
|
+
* const { isLoading } = defineProps<{ isLoading?: boolean }>();
|
|
745
|
+
*
|
|
746
|
+
* const updateName = (newName: string) => {
|
|
747
|
+
* userData.value = {
|
|
748
|
+
* ...userData.value,
|
|
749
|
+
* name: newName
|
|
750
|
+
* };
|
|
751
|
+
* };
|
|
752
|
+
* </script>
|
|
753
|
+
* ```
|
|
754
|
+
*/
|
|
153
755
|
declare function useSync<T, K extends keyof T & string, E extends (event: `update:${K}`, ...args: any[]) => void>(props: T, key: K, emit: E): Ref<T[K]>;
|
|
154
756
|
|
|
757
|
+
/**
|
|
758
|
+
* Vue composable that provides access to the global Directus stores through dependency injection.
|
|
759
|
+
*
|
|
760
|
+
* This composable injects the stores object that contains all the Pinia stores used throughout
|
|
761
|
+
* the Directus application, including user store, permissions store, collections store, etc.
|
|
762
|
+
*
|
|
763
|
+
* @returns The injected stores object containing all application stores
|
|
764
|
+
* @throws Error if the stores could not be found in the injection context
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* ```typescript
|
|
768
|
+
* import { useStores } from '@directus/composables';
|
|
769
|
+
*
|
|
770
|
+
* export default defineComponent({
|
|
771
|
+
* setup() {
|
|
772
|
+
* const stores = useStores();
|
|
773
|
+
*
|
|
774
|
+
* // Access specific stores
|
|
775
|
+
* const userStore = stores.useUserStore();
|
|
776
|
+
* const collectionsStore = stores.useCollectionsStore();
|
|
777
|
+
* const permissionsStore = stores.usePermissionsStore();
|
|
778
|
+
*
|
|
779
|
+
* return {
|
|
780
|
+
* userInfo: userStore.currentUser,
|
|
781
|
+
* collections: collectionsStore.collections,
|
|
782
|
+
* permissions: permissionsStore.permissions
|
|
783
|
+
* };
|
|
784
|
+
* }
|
|
785
|
+
* });
|
|
786
|
+
* ```
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* ```typescript
|
|
790
|
+
* // Using in a component with reactive store data
|
|
791
|
+
* import { useStores } from '@directus/composables';
|
|
792
|
+
* import { computed } from 'vue';
|
|
793
|
+
*
|
|
794
|
+
* export default defineComponent({
|
|
795
|
+
* setup() {
|
|
796
|
+
* const stores = useStores();
|
|
797
|
+
* const userStore = stores.useUserStore();
|
|
798
|
+
*
|
|
799
|
+
* const isAdmin = computed(() => {
|
|
800
|
+
* return userStore.currentUser?.role?.admin_access === true;
|
|
801
|
+
* });
|
|
802
|
+
*
|
|
803
|
+
* const hasCreatePermission = computed(() => {
|
|
804
|
+
* const permissionsStore = stores.usePermissionsStore();
|
|
805
|
+
* return permissionsStore.hasPermission('directus_files', 'create');
|
|
806
|
+
* });
|
|
807
|
+
*
|
|
808
|
+
* return { isAdmin, hasCreatePermission };
|
|
809
|
+
* }
|
|
810
|
+
* });
|
|
811
|
+
* ```
|
|
812
|
+
*/
|
|
155
813
|
declare function useStores(): Record<string, any>;
|
|
814
|
+
/**
|
|
815
|
+
* Vue composable that provides access to the Axios HTTP client instance through dependency injection.
|
|
816
|
+
*
|
|
817
|
+
* This composable injects the configured Axios instance that is set up with the proper base URL,
|
|
818
|
+
* authentication headers, interceptors, and other configuration needed to communicate with the
|
|
819
|
+
* Directus API. It provides a convenient way to make HTTP requests from components and composables.
|
|
820
|
+
*
|
|
821
|
+
* @returns The injected Axios instance configured for Directus API communication
|
|
822
|
+
* @throws Error if the API instance could not be found in the injection context
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* ```typescript
|
|
826
|
+
* import { useApi } from '@directus/composables';
|
|
827
|
+
*
|
|
828
|
+
* export default defineComponent({
|
|
829
|
+
* setup() {
|
|
830
|
+
* const api = useApi();
|
|
831
|
+
*
|
|
832
|
+
* const fetchUserData = async (userId: string) => {
|
|
833
|
+
* try {
|
|
834
|
+
* const response = await api.get(`/users/${userId}`);
|
|
835
|
+
* return response.data;
|
|
836
|
+
* } catch (error) {
|
|
837
|
+
* console.error('Failed to fetch user data:', error);
|
|
838
|
+
* throw error;
|
|
839
|
+
* }
|
|
840
|
+
* };
|
|
841
|
+
*
|
|
842
|
+
* return { fetchUserData };
|
|
843
|
+
* }
|
|
844
|
+
* });
|
|
845
|
+
* ```
|
|
846
|
+
*
|
|
847
|
+
* @example
|
|
848
|
+
* ```typescript
|
|
849
|
+
* // Using with reactive data and error handling
|
|
850
|
+
* import { useApi } from '@directus/composables';
|
|
851
|
+
* import { ref, onMounted } from 'vue';
|
|
852
|
+
*
|
|
853
|
+
* export default defineComponent({
|
|
854
|
+
* setup() {
|
|
855
|
+
* const api = useApi();
|
|
856
|
+
* const collections = ref([]);
|
|
857
|
+
* const loading = ref(false);
|
|
858
|
+
* const error = ref(null);
|
|
859
|
+
*
|
|
860
|
+
* const loadCollections = async () => {
|
|
861
|
+
* loading.value = true;
|
|
862
|
+
* error.value = null;
|
|
863
|
+
*
|
|
864
|
+
* try {
|
|
865
|
+
* const response = await api.get('/collections');
|
|
866
|
+
* collections.value = response.data.data;
|
|
867
|
+
* } catch (err) {
|
|
868
|
+
* error.value = err.response?.data?.errors?.[0]?.message || 'Failed to load collections';
|
|
869
|
+
* } finally {
|
|
870
|
+
* loading.value = false;
|
|
871
|
+
* }
|
|
872
|
+
* };
|
|
873
|
+
*
|
|
874
|
+
* onMounted(loadCollections);
|
|
875
|
+
*
|
|
876
|
+
* return { collections, loading, error, loadCollections };
|
|
877
|
+
* }
|
|
878
|
+
* });
|
|
879
|
+
* ```
|
|
880
|
+
*/
|
|
156
881
|
declare function useApi(): AxiosInstance;
|
|
882
|
+
/**
|
|
883
|
+
* Vue composable that provides access to the Directus SDK client instance through dependency injection.
|
|
884
|
+
*
|
|
885
|
+
* This composable injects the configured Directus SDK client that provides a type-safe, modern API
|
|
886
|
+
* for interacting with Directus. The SDK offers methods for CRUD operations, authentication, file
|
|
887
|
+
* management, and more, with full TypeScript support and automatic type inference based on your schema.
|
|
888
|
+
*
|
|
889
|
+
* @template Schema - The TypeScript schema type for your Directus instance, defaults to `any`
|
|
890
|
+
* @returns The injected Directus SDK client with REST client capabilities
|
|
891
|
+
* @throws Error if the SDK instance could not be found in the injection context
|
|
892
|
+
*
|
|
893
|
+
* @example
|
|
894
|
+
* ```typescript
|
|
895
|
+
* import { useSdk } from '@directus/composables';
|
|
896
|
+
*
|
|
897
|
+
* // Using with default schema
|
|
898
|
+
* export default defineComponent({
|
|
899
|
+
* setup() {
|
|
900
|
+
* const sdk = useSdk();
|
|
901
|
+
*
|
|
902
|
+
* const fetchArticles = async () => {
|
|
903
|
+
* try {
|
|
904
|
+
* const articles = await sdk.items('articles').readByQuery({
|
|
905
|
+
* filter: { status: { _eq: 'published' } },
|
|
906
|
+
* sort: ['-date_created'],
|
|
907
|
+
* limit: 10
|
|
908
|
+
* });
|
|
909
|
+
* return articles;
|
|
910
|
+
* } catch (error) {
|
|
911
|
+
* console.error('Failed to fetch articles:', error);
|
|
912
|
+
* throw error;
|
|
913
|
+
* }
|
|
914
|
+
* };
|
|
915
|
+
*
|
|
916
|
+
* return { fetchArticles };
|
|
917
|
+
* }
|
|
918
|
+
* });
|
|
919
|
+
* ```
|
|
920
|
+
*
|
|
921
|
+
* @example
|
|
922
|
+
* ```typescript
|
|
923
|
+
* // Using with typed schema for better type safety
|
|
924
|
+
* import { useSdk } from '@directus/composables';
|
|
925
|
+
*
|
|
926
|
+
* interface MySchema {
|
|
927
|
+
* articles: {
|
|
928
|
+
* id: string;
|
|
929
|
+
* title: string;
|
|
930
|
+
* content: string;
|
|
931
|
+
* status: 'draft' | 'published';
|
|
932
|
+
* author: string;
|
|
933
|
+
* date_created: string;
|
|
934
|
+
* };
|
|
935
|
+
* authors: {
|
|
936
|
+
* id: string;
|
|
937
|
+
* name: string;
|
|
938
|
+
* email: string;
|
|
939
|
+
* };
|
|
940
|
+
* }
|
|
941
|
+
*
|
|
942
|
+
* export default defineComponent({
|
|
943
|
+
* setup() {
|
|
944
|
+
* const sdk = useSdk<MySchema>();
|
|
945
|
+
*
|
|
946
|
+
* const createArticle = async (articleData: Partial<MySchema['articles']>) => {
|
|
947
|
+
* try {
|
|
948
|
+
* const newArticle = await sdk.items('articles').createOne(articleData);
|
|
949
|
+
* return newArticle; // Fully typed return value
|
|
950
|
+
* } catch (error) {
|
|
951
|
+
* console.error('Failed to create article:', error);
|
|
952
|
+
* throw error;
|
|
953
|
+
* }
|
|
954
|
+
* };
|
|
955
|
+
*
|
|
956
|
+
* const updateArticle = async (id: string, updates: Partial<MySchema['articles']>) => {
|
|
957
|
+
* try {
|
|
958
|
+
* const updatedArticle = await sdk.items('articles').updateOne(id, updates);
|
|
959
|
+
* return updatedArticle; // Type-safe updates
|
|
960
|
+
* } catch (error) {
|
|
961
|
+
* console.error('Failed to update article:', error);
|
|
962
|
+
* throw error;
|
|
963
|
+
* }
|
|
964
|
+
* };
|
|
965
|
+
*
|
|
966
|
+
* return { createArticle, updateArticle };
|
|
967
|
+
* }
|
|
968
|
+
* });
|
|
969
|
+
* ```
|
|
970
|
+
*/
|
|
157
971
|
declare function useSdk<Schema extends object = any>(): DirectusClient<Schema> & RestClient<Schema>;
|
|
972
|
+
/**
|
|
973
|
+
* Vue composable that provides access to the registered Directus extensions through dependency injection.
|
|
974
|
+
*
|
|
975
|
+
* This composable injects the extensions configuration object that contains all registered app
|
|
976
|
+
* extensions including interfaces, displays, layouts, modules, panels, operations, and more.
|
|
977
|
+
* The extensions are provided as reactive references and can be used to dynamically access
|
|
978
|
+
* and utilize custom functionality within the Directus application.
|
|
979
|
+
*
|
|
980
|
+
* @returns A reactive record of extension configurations organized by extension type
|
|
981
|
+
* @throws Error if the extensions could not be found in the injection context
|
|
982
|
+
*
|
|
983
|
+
* @example
|
|
984
|
+
* ```typescript
|
|
985
|
+
* import { useExtensions } from '@directus/composables';
|
|
986
|
+
*
|
|
987
|
+
* export default defineComponent({
|
|
988
|
+
* setup() {
|
|
989
|
+
* const extensions = useExtensions();
|
|
990
|
+
*
|
|
991
|
+
* const getAvailableInterfaces = () => {
|
|
992
|
+
* return Object.values(extensions.interfaces || {});
|
|
993
|
+
* };
|
|
994
|
+
*
|
|
995
|
+
* const getAvailableDisplays = () => {
|
|
996
|
+
* return Object.values(extensions.displays || {});
|
|
997
|
+
* };
|
|
998
|
+
*
|
|
999
|
+
* const findInterfaceByName = (name: string) => {
|
|
1000
|
+
* return extensions.interfaces?.[name] || null;
|
|
1001
|
+
* };
|
|
1002
|
+
*
|
|
1003
|
+
* return {
|
|
1004
|
+
* getAvailableInterfaces,
|
|
1005
|
+
* getAvailableDisplays,
|
|
1006
|
+
* findInterfaceByName
|
|
1007
|
+
* };
|
|
1008
|
+
* }
|
|
1009
|
+
* });
|
|
1010
|
+
* ```
|
|
1011
|
+
*
|
|
1012
|
+
* @example
|
|
1013
|
+
* ```typescript
|
|
1014
|
+
* // Using with computed properties for reactive extension lists
|
|
1015
|
+
* import { useExtensions } from '@directus/composables';
|
|
1016
|
+
* import { computed } from 'vue';
|
|
1017
|
+
*
|
|
1018
|
+
* export default defineComponent({
|
|
1019
|
+
* setup() {
|
|
1020
|
+
* const extensions = useExtensions();
|
|
1021
|
+
*
|
|
1022
|
+
* const availableLayouts = computed(() => {
|
|
1023
|
+
* return Object.entries(extensions.layouts || {}).map(([key, config]) => ({
|
|
1024
|
+
* id: key,
|
|
1025
|
+
* name: config.name,
|
|
1026
|
+
* icon: config.icon,
|
|
1027
|
+
* component: config.component
|
|
1028
|
+
* }));
|
|
1029
|
+
* });
|
|
1030
|
+
*
|
|
1031
|
+
* const customModules = computed(() => {
|
|
1032
|
+
* return Object.values(extensions.modules || {}).filter(module =>
|
|
1033
|
+
* !module.preRegisterCheck || module.preRegisterCheck()
|
|
1034
|
+
* );
|
|
1035
|
+
* });
|
|
1036
|
+
*
|
|
1037
|
+
* const operationsByGroup = computed(() => {
|
|
1038
|
+
* const operations = Object.values(extensions.operations || {});
|
|
1039
|
+
* return operations.reduce((groups, operation) => {
|
|
1040
|
+
* const group = operation.overview?.group || 'other';
|
|
1041
|
+
* if (!groups[group]) groups[group] = [];
|
|
1042
|
+
* groups[group].push(operation);
|
|
1043
|
+
* return groups;
|
|
1044
|
+
* }, {} as Record<string, any[]>);
|
|
1045
|
+
* });
|
|
1046
|
+
*
|
|
1047
|
+
* return {
|
|
1048
|
+
* availableLayouts,
|
|
1049
|
+
* customModules,
|
|
1050
|
+
* operationsByGroup
|
|
1051
|
+
* };
|
|
1052
|
+
* }
|
|
1053
|
+
* });
|
|
1054
|
+
* ```
|
|
1055
|
+
*/
|
|
158
1056
|
declare function useExtensions(): RefRecord<AppExtensionConfigs>;
|
|
159
1057
|
|
|
160
|
-
export { type ComputedQuery, type GroupableInstance, type GroupableOptions, type ManualSortData, type UsableCollection, type UsableCustomSelection, type UsableGroupable, type UsableItems, sizeProps, useApi, useCollection, useCustomSelection, useCustomSelectionMultiple, useElementSize, useExtensions, useFilterFields, useGroupable, useGroupableParent, useItems, useLayout, useSdk, useSizeClass, useStores, useSync };
|
|
1058
|
+
export { type ComputedQuery, type GroupableInstance, type GroupableOptions, type ManualSortData, type OtherValue, type UsableCollection, type UsableCustomSelection, type UsableGroupable, type UsableItems, createLayoutWrapper, isWritableProp, sizeProps, useApi, useCollection, useCustomSelection, useCustomSelectionMultiple, useElementSize, useExtensions, useFilterFields, useGroupable, useGroupableParent, useItems, useLayout, useSdk, useSizeClass, useStores, useSync };
|
package/dist/index.js
CHANGED
|
@@ -61,9 +61,7 @@ function useCollection(collectionKey) {
|
|
|
61
61
|
return info.value?.meta?.singleton === true;
|
|
62
62
|
});
|
|
63
63
|
const accountabilityScope = computed(() => {
|
|
64
|
-
|
|
65
|
-
if (!info.value.meta) return null;
|
|
66
|
-
return info.value.meta.accountability;
|
|
64
|
+
return info.value?.meta?.accountability || null;
|
|
67
65
|
});
|
|
68
66
|
return { info, fields, defaults, primaryKeyField, userCreatedField, sortField, isSingleton, accountabilityScope };
|
|
69
67
|
}
|
|
@@ -118,12 +116,13 @@ function useCustomSelectionMultiple(currentValues, items, emit) {
|
|
|
118
116
|
{ immediate: true }
|
|
119
117
|
);
|
|
120
118
|
return { otherValues, addOtherValue, setOtherValue };
|
|
121
|
-
function addOtherValue(value = "") {
|
|
119
|
+
function addOtherValue(value = "", focus = false) {
|
|
122
120
|
otherValues.value = [
|
|
123
121
|
...otherValues.value,
|
|
124
122
|
{
|
|
125
123
|
key: nanoid(),
|
|
126
|
-
value
|
|
124
|
+
value,
|
|
125
|
+
focus
|
|
127
126
|
}
|
|
128
127
|
];
|
|
129
128
|
}
|
|
@@ -683,6 +682,8 @@ function useSync(props, key, emit) {
|
|
|
683
682
|
});
|
|
684
683
|
}
|
|
685
684
|
export {
|
|
685
|
+
createLayoutWrapper,
|
|
686
|
+
isWritableProp,
|
|
686
687
|
sizeProps,
|
|
687
688
|
useApi,
|
|
688
689
|
useCollection,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/composables",
|
|
3
|
-
"version": "11.1
|
|
3
|
+
"version": "11.2.1",
|
|
4
4
|
"description": "Shared Vue composables for Directus use",
|
|
5
5
|
"homepage": "https://directus.io",
|
|
6
6
|
"repository": {
|
|
@@ -22,24 +22,24 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"axios": "1.
|
|
25
|
+
"axios": "1.11.0",
|
|
26
26
|
"lodash-es": "4.17.21",
|
|
27
|
-
"nanoid": "5.1.
|
|
27
|
+
"nanoid": "5.1.5",
|
|
28
28
|
"@directus/constants": "13.0.1",
|
|
29
|
-
"@directus/utils": "13.0.
|
|
29
|
+
"@directus/utils": "13.0.8"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@directus/tsconfig": "3.0.0",
|
|
33
33
|
"@types/lodash-es": "4.17.12",
|
|
34
|
-
"@vitest/coverage-v8": "2.
|
|
34
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
35
35
|
"@vue/test-utils": "2.4.6",
|
|
36
|
-
"tsup": "8.
|
|
37
|
-
"typescript": "5.8.
|
|
38
|
-
"vitest": "2.
|
|
39
|
-
"vue": "3.5.
|
|
40
|
-
"@directus/extensions": "3.0.
|
|
41
|
-
"@directus/
|
|
42
|
-
"@directus/
|
|
36
|
+
"tsup": "8.5.0",
|
|
37
|
+
"typescript": "5.8.3",
|
|
38
|
+
"vitest": "3.2.4",
|
|
39
|
+
"vue": "3.5.18",
|
|
40
|
+
"@directus/extensions": "3.0.8",
|
|
41
|
+
"@directus/sdk": "20.0.1",
|
|
42
|
+
"@directus/types": "13.2.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"vue": "^3.4"
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "tsup src/index.ts --format=esm --dts",
|
|
49
49
|
"dev": "tsup src/index.ts --format=esm --dts --watch",
|
|
50
|
-
"test": "vitest
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:coverage": "vitest run --coverage"
|
|
51
52
|
}
|
|
52
53
|
}
|