@radio-garden/ditojs-admin 2.85.2-0.5067ad799

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.
Files changed (153) hide show
  1. package/README.md +180 -0
  2. package/dist/dito-admin.css +1 -0
  3. package/dist/dito-admin.es.js +12106 -0
  4. package/dist/dito-admin.umd.js +7 -0
  5. package/package.json +96 -0
  6. package/src/DitoAdmin.js +293 -0
  7. package/src/DitoComponent.js +34 -0
  8. package/src/DitoContext.js +318 -0
  9. package/src/DitoTypeComponent.js +42 -0
  10. package/src/DitoUser.js +12 -0
  11. package/src/appState.js +12 -0
  12. package/src/components/DitoAccount.vue +60 -0
  13. package/src/components/DitoAffix.vue +68 -0
  14. package/src/components/DitoAffixes.vue +200 -0
  15. package/src/components/DitoButtons.vue +80 -0
  16. package/src/components/DitoClipboard.vue +186 -0
  17. package/src/components/DitoContainer.vue +374 -0
  18. package/src/components/DitoCreateButton.vue +146 -0
  19. package/src/components/DitoDialog.vue +242 -0
  20. package/src/components/DitoDraggable.vue +117 -0
  21. package/src/components/DitoEditButtons.vue +135 -0
  22. package/src/components/DitoErrors.vue +83 -0
  23. package/src/components/DitoForm.vue +521 -0
  24. package/src/components/DitoFormInner.vue +26 -0
  25. package/src/components/DitoFormNested.vue +17 -0
  26. package/src/components/DitoHeader.vue +84 -0
  27. package/src/components/DitoLabel.vue +200 -0
  28. package/src/components/DitoMenu.vue +186 -0
  29. package/src/components/DitoNavigation.vue +40 -0
  30. package/src/components/DitoNotifications.vue +170 -0
  31. package/src/components/DitoPagination.vue +42 -0
  32. package/src/components/DitoPane.vue +334 -0
  33. package/src/components/DitoPanel.vue +256 -0
  34. package/src/components/DitoPanels.vue +61 -0
  35. package/src/components/DitoRoot.vue +524 -0
  36. package/src/components/DitoSchema.vue +846 -0
  37. package/src/components/DitoSchemaInlined.vue +97 -0
  38. package/src/components/DitoScopes.vue +76 -0
  39. package/src/components/DitoSidebar.vue +50 -0
  40. package/src/components/DitoSpinner.vue +95 -0
  41. package/src/components/DitoTableCell.vue +64 -0
  42. package/src/components/DitoTableHead.vue +121 -0
  43. package/src/components/DitoTabs.vue +103 -0
  44. package/src/components/DitoTrail.vue +124 -0
  45. package/src/components/DitoTreeItem.vue +420 -0
  46. package/src/components/DitoUploadFile.vue +199 -0
  47. package/src/components/DitoVNode.vue +14 -0
  48. package/src/components/DitoView.vue +143 -0
  49. package/src/components/index.js +42 -0
  50. package/src/directives/resize.js +83 -0
  51. package/src/index.js +1 -0
  52. package/src/mixins/ContextMixin.js +68 -0
  53. package/src/mixins/DataMixin.js +131 -0
  54. package/src/mixins/DitoMixin.js +591 -0
  55. package/src/mixins/DomMixin.js +29 -0
  56. package/src/mixins/EmitterMixin.js +158 -0
  57. package/src/mixins/ItemMixin.js +144 -0
  58. package/src/mixins/LoadingMixin.js +23 -0
  59. package/src/mixins/NumberMixin.js +118 -0
  60. package/src/mixins/OptionsMixin.js +304 -0
  61. package/src/mixins/PulldownMixin.js +63 -0
  62. package/src/mixins/ResourceMixin.js +398 -0
  63. package/src/mixins/RouteMixin.js +190 -0
  64. package/src/mixins/SchemaParentMixin.js +33 -0
  65. package/src/mixins/SortableMixin.js +49 -0
  66. package/src/mixins/SourceMixin.js +734 -0
  67. package/src/mixins/TextMixin.js +26 -0
  68. package/src/mixins/TypeMixin.js +280 -0
  69. package/src/mixins/ValidationMixin.js +119 -0
  70. package/src/mixins/ValidatorMixin.js +57 -0
  71. package/src/mixins/ValueMixin.js +31 -0
  72. package/src/styles/_base.scss +17 -0
  73. package/src/styles/_button.scss +191 -0
  74. package/src/styles/_imports.scss +3 -0
  75. package/src/styles/_info.scss +19 -0
  76. package/src/styles/_layout.scss +19 -0
  77. package/src/styles/_pulldown.scss +38 -0
  78. package/src/styles/_scroll.scss +13 -0
  79. package/src/styles/_settings.scss +88 -0
  80. package/src/styles/_table.scss +223 -0
  81. package/src/styles/_tippy.scss +45 -0
  82. package/src/styles/style.scss +9 -0
  83. package/src/types/DitoTypeButton.vue +143 -0
  84. package/src/types/DitoTypeCheckbox.vue +27 -0
  85. package/src/types/DitoTypeCheckboxes.vue +65 -0
  86. package/src/types/DitoTypeCode.vue +199 -0
  87. package/src/types/DitoTypeColor.vue +272 -0
  88. package/src/types/DitoTypeComponent.vue +31 -0
  89. package/src/types/DitoTypeComputed.vue +50 -0
  90. package/src/types/DitoTypeDate.vue +99 -0
  91. package/src/types/DitoTypeLabel.vue +23 -0
  92. package/src/types/DitoTypeList.vue +364 -0
  93. package/src/types/DitoTypeMarkup.vue +700 -0
  94. package/src/types/DitoTypeMultiselect.vue +522 -0
  95. package/src/types/DitoTypeNumber.vue +66 -0
  96. package/src/types/DitoTypeObject.vue +136 -0
  97. package/src/types/DitoTypePanel.vue +18 -0
  98. package/src/types/DitoTypeProgress.vue +40 -0
  99. package/src/types/DitoTypeRadio.vue +45 -0
  100. package/src/types/DitoTypeSection.vue +80 -0
  101. package/src/types/DitoTypeSelect.vue +133 -0
  102. package/src/types/DitoTypeSlider.vue +66 -0
  103. package/src/types/DitoTypeSpacer.vue +11 -0
  104. package/src/types/DitoTypeSwitch.vue +40 -0
  105. package/src/types/DitoTypeText.vue +101 -0
  106. package/src/types/DitoTypeTextarea.vue +48 -0
  107. package/src/types/DitoTypeTreeList.vue +193 -0
  108. package/src/types/DitoTypeUpload.vue +503 -0
  109. package/src/types/index.js +30 -0
  110. package/src/utils/SchemaGraph.js +147 -0
  111. package/src/utils/accessor.js +75 -0
  112. package/src/utils/agent.js +47 -0
  113. package/src/utils/data.js +92 -0
  114. package/src/utils/filter.js +266 -0
  115. package/src/utils/math.js +14 -0
  116. package/src/utils/options.js +48 -0
  117. package/src/utils/path.js +5 -0
  118. package/src/utils/resource.js +44 -0
  119. package/src/utils/route.js +53 -0
  120. package/src/utils/schema.js +1121 -0
  121. package/src/utils/type.js +81 -0
  122. package/src/utils/uid.js +15 -0
  123. package/src/utils/units.js +5 -0
  124. package/src/validators/_creditcard.js +6 -0
  125. package/src/validators/_decimals.js +11 -0
  126. package/src/validators/_domain.js +6 -0
  127. package/src/validators/_email.js +6 -0
  128. package/src/validators/_hostname.js +6 -0
  129. package/src/validators/_integer.js +6 -0
  130. package/src/validators/_max.js +6 -0
  131. package/src/validators/_min.js +6 -0
  132. package/src/validators/_password.js +5 -0
  133. package/src/validators/_range.js +6 -0
  134. package/src/validators/_required.js +9 -0
  135. package/src/validators/_url.js +6 -0
  136. package/src/validators/index.js +12 -0
  137. package/src/verbs.js +17 -0
  138. package/types/index.d.ts +3298 -0
  139. package/types/tests/admin.test-d.ts +27 -0
  140. package/types/tests/component-buttons.test-d.ts +44 -0
  141. package/types/tests/component-list.test-d.ts +159 -0
  142. package/types/tests/component-misc.test-d.ts +137 -0
  143. package/types/tests/component-object.test-d.ts +69 -0
  144. package/types/tests/component-section.test-d.ts +174 -0
  145. package/types/tests/component-select.test-d.ts +107 -0
  146. package/types/tests/components.test-d.ts +81 -0
  147. package/types/tests/context.test-d.ts +31 -0
  148. package/types/tests/fixtures.ts +24 -0
  149. package/types/tests/form.test-d.ts +109 -0
  150. package/types/tests/instance.test-d.ts +20 -0
  151. package/types/tests/schema-features.test-d.ts +402 -0
  152. package/types/tests/variance.test-d.ts +125 -0
  153. package/types/tests/view.test-d.ts +146 -0
@@ -0,0 +1,3298 @@
1
+ // Type definitions for Dito.js admin
2
+ // Project: <https://github.com/ditojs/dito/>
3
+
4
+ import {
5
+ DateFormat,
6
+ format as utilsFormat,
7
+ NumberFormat,
8
+ TimeFormat
9
+ } from '@ditojs/utils'
10
+ import { RequireAtLeastOne, SetOptional } from 'type-fest'
11
+ import { Component as VueComponent } from 'vue'
12
+ import { Router as VueRouter } from 'vue-router'
13
+
14
+ declare global {
15
+ const dito: DitoGlobal
16
+ }
17
+
18
+ export default DitoAdmin
19
+ export interface DitoGlobal {
20
+ /** Global API configuration shared across the admin. */
21
+ api?: ApiConfig
22
+ /** Base URL path for the admin application. */
23
+ base?: string
24
+ /** Arbitrary settings accessible via `dito.settings`. */
25
+ settings?: Record<string, any>
26
+ }
27
+
28
+ /**
29
+ * A function that performs an HTTP request and returns the parsed
30
+ * response. Used by the admin to communicate with the Dito.js
31
+ * server API.
32
+ *
33
+ * @template T The expected type of the response data.
34
+ */
35
+ export type RequestMethod = <T>(options: {
36
+ /** The URL to send the request to. */
37
+ url: string
38
+ /**
39
+ * The HTTP method to use.
40
+ *
41
+ * @default 'get'
42
+ */
43
+ method?: HTTPMethod
44
+ /** Request body payload. */
45
+ data?: unknown
46
+ /** URL query parameters. */
47
+ query?:
48
+ | Record<string, string | number | (string | number)[]>
49
+ | [string, string | number][]
50
+ | null
51
+ /** Additional HTTP headers to include. */
52
+ headers?: Record<string, string> | null
53
+ /** Abort signal to cancel the request. */
54
+ signal?: AbortSignal | null
55
+ }) => Promise<RequestMethodResponse<T>>
56
+
57
+ /**
58
+ * The response returned by {@link RequestMethod}, extending the
59
+ * standard `Response` with a parsed `data` property.
60
+ *
61
+ * @template T The type of the parsed response data.
62
+ */
63
+ export type RequestMethodResponse<T> = Response & { data: T }
64
+
65
+ /**
66
+ * Describes a resource in the Dito.js server API. Resources can be
67
+ * nested via {@link ApiResource.parent} to build hierarchical API
68
+ * paths. The {@link ApiResource.type} determines how the path is
69
+ * constructed:
70
+ *
71
+ * - `'collection'` — uses `path` directly (e.g. `users`)
72
+ * - `'member'` — appends `id` to the path (e.g. `users/5`)
73
+ * - `'upload'` — builds an upload path under the parent collection
74
+ * (e.g. `users/upload/avatar`)
75
+ *
76
+ * Paths are built recursively through the `parent` chain, so a
77
+ * member nested under a collection produces paths like
78
+ * `users/1/comments/3`.
79
+ */
80
+ export interface ApiResource {
81
+ /**
82
+ * Determines how the resource path is constructed.
83
+ *
84
+ * @see {@link ApiResource} for the path-building rules per type.
85
+ */
86
+ type: LiteralUnion<'collection' | 'member' | 'upload'>
87
+ /**
88
+ * URL path segment for this resource. If it starts with `/`, it is
89
+ * treated as absolute and parent nesting is skipped. Otherwise it
90
+ * is appended to the parent's resolved path.
91
+ */
92
+ path?: string
93
+ /** HTTP method for the resource request. */
94
+ method?: HTTPMethod
95
+ /**
96
+ * Identifier of a specific resource item, used when
97
+ * {@link ApiResource.type} is `'member'` to append the id to the
98
+ * resolved path.
99
+ */
100
+ id?: string | number
101
+ /**
102
+ * Parent resource for nested API paths. The parent's path is
103
+ * resolved first and this resource's path is appended to it,
104
+ * enabling hierarchical URLs.
105
+ */
106
+ parent?: ApiResource
107
+ /** Query parameters appended to the request URL. */
108
+ query?: Record<string, string | number | (string | number)[]>
109
+ }
110
+
111
+ /**
112
+ * Configuration for the admin's API layer. Merged from three
113
+ * sources in order of priority: the constructor `api` parameter,
114
+ * `dito.api` (passed from `AdminController` on the server), and
115
+ * built-in defaults.
116
+ */
117
+ export interface ApiConfig {
118
+ /**
119
+ * The base path for the admin UI, as passed from
120
+ * `AdminController`.
121
+ *
122
+ * @defaultValue `'/'`
123
+ */
124
+ base?: string
125
+ /**
126
+ * The base URL prepended to all API requests. Relative request
127
+ * URLs are combined with this value.
128
+ */
129
+ url?: string
130
+ /**
131
+ * Locale used for date, time, and number formatting throughout
132
+ * the admin.
133
+ *
134
+ * @defaultValue `'en-US'`
135
+ */
136
+ locale?: string
137
+ /**
138
+ * Default format options for numbers, dates, and times. Merged
139
+ * with the built-in `defaultFormats` from `@ditojs/utils`.
140
+ * Individual schemas can override these on a per-component basis.
141
+ */
142
+ formats?: {
143
+ number?: NumberFormat
144
+ date?: DateFormat
145
+ time?: TimeFormat
146
+ }
147
+ /**
148
+ * The function used to perform HTTP requests. Defaults to a
149
+ * built-in `fetch` wrapper that applies {@link ApiConfig.headers},
150
+ * {@link ApiConfig.cors}, and {@link ApiConfig.getApiUrl}
151
+ * automatically for API URLs.
152
+ */
153
+ request?: RequestMethod
154
+ /**
155
+ * Controls admin notification toasts. Set to `false` to disable
156
+ * all notifications, or provide an object to customize display
157
+ * duration.
158
+ *
159
+ * @defaultValue `true`
160
+ */
161
+ notifications?:
162
+ | boolean
163
+ | {
164
+ /**
165
+ * Milliseconds per character used to calculate notification
166
+ * display duration. The formula is:
167
+ * `(40 + text.length + title.length) * durationFactor`.
168
+ *
169
+ * @defaultValue `20`
170
+ */
171
+ durationFactor: number
172
+ }
173
+ /**
174
+ * CORS settings applied to API requests (where
175
+ * {@link ApiConfig.isApiUrl} returns `true`).
176
+ */
177
+ cors?: {
178
+ /**
179
+ * Enables cross-site requests with credentials
180
+ * (`credentials: 'include'`).
181
+ */
182
+ credentials: boolean
183
+ }
184
+ /**
185
+ * When `true`, sets {@link ApiConfig.normalizePath} to
186
+ * `hyphenate` (camelCase to kebab-case) and
187
+ * {@link ApiConfig.denormalizePath} to `camelize` (kebab-case to
188
+ * camelCase). Used for automatic path conversion between JS
189
+ * naming conventions and URL paths.
190
+ *
191
+ * @defaultValue Inherits from
192
+ * `Application.config.app.normalizePaths`, falling back
193
+ * to `false`.
194
+ */
195
+ normalizePaths?: boolean
196
+ /**
197
+ * Converts a camelCase path segment to its URL form. Applied
198
+ * when building schema routes and upload paths.
199
+ *
200
+ * @defaultValue `hyphenate` when {@link ApiConfig.normalizePaths}
201
+ * is `true`, otherwise an identity function.
202
+ */
203
+ normalizePath?: (path: string) => string
204
+ /**
205
+ * Converts a URL path segment back to its camelCase form.
206
+ *
207
+ * @defaultValue `camelize` when {@link ApiConfig.normalizePaths}
208
+ * is `true`, otherwise an identity function.
209
+ */
210
+ denormalizePath?: (path: string) => string
211
+ /**
212
+ * Authentication resource configuration. The `path` defines the
213
+ * user collection endpoint, and `login`, `logout`, and `session`
214
+ * are nested as child resources under it (e.g. `users/login`).
215
+ */
216
+ users?: {
217
+ /** The collection path for the user model. */
218
+ path: string
219
+ /** Login endpoint. */
220
+ login?: {
221
+ /**
222
+ * @defaultValue `'login'`
223
+ */
224
+ path?: string
225
+ /**
226
+ * @defaultValue `'post'`
227
+ */
228
+ method?: HTTPMethod
229
+ }
230
+ /** Logout endpoint. */
231
+ logout?: {
232
+ /**
233
+ * @defaultValue `'logout'`
234
+ */
235
+ path?: string
236
+ /**
237
+ * @defaultValue `'post'`
238
+ */
239
+ method?: HTTPMethod
240
+ }
241
+ /**
242
+ * Session endpoint for checking an existing authenticated
243
+ * session on page load.
244
+ */
245
+ session?: {
246
+ /**
247
+ * @defaultValue `'session'`
248
+ */
249
+ path?: string
250
+ /**
251
+ * @defaultValue `'get'`
252
+ */
253
+ method?: HTTPMethod
254
+ }
255
+ }
256
+ /**
257
+ * Custom resource path handlers, keyed by resource type. Merged
258
+ * with the built-in handlers (`any`, `default`, `collection`,
259
+ * `member`, `upload`). Each handler receives an
260
+ * {@link ApiResource} and returns the resolved path string.
261
+ */
262
+ resources?: Record<string, (resource: ApiResource | string) => string>
263
+
264
+ /**
265
+ * HTTP headers included in all API requests (where
266
+ * {@link ApiConfig.isApiUrl} returns `true`). Merged with the
267
+ * default `Content-Type: application/json` header, and can be
268
+ * further overridden per-request.
269
+ *
270
+ * @defaultValue `{ 'Content-Type': 'application/json' }`
271
+ */
272
+ headers?: Record<string, string>
273
+
274
+ /**
275
+ * Returns the full API URL for a given request configuration.
276
+ * Prepends {@link ApiConfig.url} to relative URLs and appends
277
+ * formatted query parameters.
278
+ */
279
+ getApiUrl?: (options: {
280
+ url: string
281
+ query?:
282
+ | Record<string, string | number | (string | number)[]>
283
+ | [string, string | number][]
284
+ | null
285
+ }) => string
286
+
287
+ /**
288
+ * Returns `true` if the given URL is an API URL. A URL is
289
+ * considered an API URL if it is not absolute or if it starts
290
+ * with {@link ApiConfig.url}. When `true`, the request includes
291
+ * {@link ApiConfig.headers} and respects
292
+ * {@link ApiConfig.cors} settings.
293
+ */
294
+ isApiUrl?: (url: string) => boolean
295
+
296
+ /**
297
+ * Default schema property values per component type. During
298
+ * schema processing, defaults for a matching type are applied
299
+ * to the schema: top-level properties that are `undefined` are
300
+ * set directly, while existing object properties are
301
+ * deep-merged. When a function is provided, it receives the
302
+ * schema and can return defaults or modify it directly.
303
+ *
304
+ * @example
305
+ * ```js
306
+ * defaults: {
307
+ * multiselect: {
308
+ * selectable: true
309
+ * }
310
+ * }
311
+ * ```
312
+ */
313
+ defaults?: Record<
314
+ string,
315
+ | Record<string, any>
316
+ | ((schema: Component) => Record<string, any> | void)
317
+ >
318
+ }
319
+
320
+ export interface BaseSchema<$Item>
321
+ extends SchemaDitoMixin<$Item>,
322
+ SchemaTypeMixin<$Item> {
323
+ /**
324
+ * Value used when the field's key is absent from the
325
+ * data object.
326
+ */
327
+ default?: OrItemAccessor<$Item>
328
+ /**
329
+ * Computes and sets the field value reactively. If
330
+ * the callback returns `undefined`, the current value
331
+ * is preserved.
332
+ */
333
+ compute?: ItemAccessor<$Item>
334
+ /**
335
+ * Additional reactive data properties merged into
336
+ * the component's data scope.
337
+ */
338
+ data?: OrItemAccessor<$Item, {}, Record<string, any>>
339
+ /**
340
+ * Custom CSS class(es) added to the component's container
341
+ * element. Accepts a string or an object of class-boolean
342
+ * pairs.
343
+ */
344
+ class?: string | Record<string, boolean>
345
+ /**
346
+ * Whether the component type omits surrounding spacing.
347
+ *
348
+ * @internal Set as a static option on component type
349
+ * definitions, not configured in schemas.
350
+ */
351
+ omitSpacing?: boolean
352
+ /**
353
+ * Forces a layout line break before, after, or on
354
+ * both sides of the component.
355
+ */
356
+ break?: 'before' | 'after' | 'both'
357
+ }
358
+
359
+ export interface SchemaDitoMixin<$Item> {
360
+ /**
361
+ * Only displays the component if the schema accessor returns `true`
362
+ */
363
+ if?: OrItemAccessor<$Item, {}, boolean>
364
+
365
+ /**
366
+ * Specifies validations rules to add, remove (by setting to `undefined`) or
367
+ * change before value validation occurs. Rule changes do not influence how
368
+ * the component is rendered.
369
+ */
370
+ rules?: {
371
+ /** Override whether the field is required. */
372
+ required?: boolean
373
+ }
374
+ }
375
+
376
+ /**
377
+ * Return false to mark event as handled and stop it from propagating to parent
378
+ * schemas.
379
+ */
380
+ export type ItemEventHandler<$Item = any> = (
381
+ itemParams: DitoContext<$Item>
382
+ ) => void | false
383
+
384
+ export type OpenEventHandler<$Item = any> = (
385
+ itemParams: DitoContext<$Item> & { open: boolean }
386
+ ) => void | false
387
+
388
+ export type ErrorEventHandler<$Item = any> = (
389
+ itemParams: DitoContext<$Item> & { error: Error }
390
+ ) => void | false
391
+
392
+ /**
393
+ * Event handlers shared by component schemas, views,
394
+ * and forms.
395
+ */
396
+ export interface SchemaEvents<$Item = any> {
397
+ /**
398
+ * Fires when the schema's component tree is set up.
399
+ * @see {@link SchemaFields.onInitialize}
400
+ */
401
+ initialize?: ItemEventHandler<$Item>
402
+ /**
403
+ * Fires when the schema component is unmounted.
404
+ * @see {@link SchemaFields.onDestroy}
405
+ */
406
+ destroy?: ItemEventHandler<$Item>
407
+ /**
408
+ * Fires after data has been fetched from the API.
409
+ * @see {@link SchemaFields.onLoad}
410
+ */
411
+ load?: ItemEventHandler<$Item>
412
+ /**
413
+ * Fires after a value change is committed.
414
+ * @see {@link SchemaFields.onChange}
415
+ */
416
+ change?: ItemEventHandler<$Item>
417
+ }
418
+
419
+ export interface SchemaOpen<$Item = any> {
420
+ /**
421
+ * Called when a collapsible schema section is
422
+ * toggled open or closed. The `open` property on
423
+ * the context indicates the new state.
424
+ */
425
+ onOpen?: OpenEventHandler<$Item>
426
+ }
427
+
428
+ export interface SchemaTypeMixin<$Item> extends SchemaFields<$Item> {
429
+ /**
430
+ * The label of the component.
431
+ *
432
+ * @defaultValue The title-cased component name.
433
+ */
434
+ label?: OrItemAccessor<$Item, {}, string | boolean>
435
+
436
+ /**
437
+ * The width of the component. The value can either be given in percent
438
+ * (e.g. '20%' or a value between 0 and 1), or as 'auto' to have the width
439
+ * depend on its contents or as 'fill' to fill left over space. A line will
440
+ * contain multiple components until their widths exceed 100%.
441
+ */
442
+ width?: OrItemAccessor<
443
+ $Item,
444
+ {},
445
+ 'auto' | 'fill' | `${number}%` | `${number}/${number}` | number
446
+ >
447
+
448
+ /**
449
+ * Whether the component is visible.
450
+ *
451
+ * @defaultValue `true`
452
+ */
453
+ visible?: OrItemAccessor<$Item, {}, boolean>
454
+
455
+ /**
456
+ * Whether to exclude the field's value from the processed data
457
+ * sent to the server.
458
+ *
459
+ * @defaultValue `false`
460
+ */
461
+ exclude?: OrItemAccessor<$Item, {}, boolean>
462
+
463
+ /**
464
+ * Whether the field is required.
465
+ * @defaultValue `false`
466
+ */
467
+ required?: OrItemAccessor<$Item, {}, boolean>
468
+
469
+ /**
470
+ * Whether the value is read only.
471
+ *
472
+ * @defaultValue `false`
473
+ */
474
+ readonly?: OrItemAccessor<$Item, {}, boolean>
475
+
476
+ /**
477
+ * Whether to autofocus the field.
478
+ * @defaultValue `false`
479
+ */
480
+ autofocus?: OrItemAccessor<$Item, {}, boolean>
481
+
482
+ /**
483
+ * Whether the field can be cleared.
484
+ * @defaultValue `false`
485
+ */
486
+ clearable?: OrItemAccessor<$Item, {}, boolean>
487
+
488
+ /**
489
+ * Specifies a short hint intended to aid the user
490
+ * with data entry when the input has no value. Set
491
+ * to `false` to disable the placeholder, or `true`
492
+ * to use the component's auto-generated default
493
+ * (e.g. multiselect generates one based on
494
+ * `searchable` and `taggable`).
495
+ */
496
+ placeholder?: OrItemAccessor<$Item, {}, string | boolean>
497
+
498
+ /**
499
+ * Info text displayed near the component label.
500
+ */
501
+ info?: OrItemAccessor<$Item, {}, string>
502
+
503
+ /**
504
+ * The maximum allowed length of the input value.
505
+ */
506
+ maxLength?: OrItemAccessor<$Item, {}, number>
507
+
508
+ /**
509
+ * Whether the input field should have autocomplete enabled.
510
+ */
511
+ autocomplete?: OrItemAccessor<$Item, {}, 'on' | 'off'>
512
+
513
+ /**
514
+ * Specifies a function which transforms the stored
515
+ * value into a display format before it is passed
516
+ * to the component for rendering.
517
+ */
518
+ format?: ItemAccessor<$Item, {}, any>
519
+ /**
520
+ * Whether the component is disabled.
521
+ *
522
+ * @defaultValue `false`
523
+ */
524
+ disabled?: OrItemAccessor<$Item, {}, boolean>
525
+
526
+ /**
527
+ * Specifies a function which parses the component
528
+ * value when it changes, transforming the raw
529
+ * input before it is stored.
530
+ */
531
+ parse?: ItemAccessor<$Item, {}>
532
+
533
+ /**
534
+ * Specifies a function which processes the field value after
535
+ * type-specific processing but before exclusion, allowing
536
+ * custom value transformation before sending data to the
537
+ * server. Can also modify sibling data via `processedItem`
538
+ * in the context, even when `exclude` is `true`.
539
+ */
540
+ process?: ItemAccessor<$Item, {}>
541
+
542
+ /**
543
+ * The property key used to identify the field in data objects.
544
+ * Auto-assigned from the component's key if not provided.
545
+ */
546
+ name?: string
547
+
548
+ /**
549
+ * Called when the input element receives focus.
550
+ */
551
+ onFocus?: ItemEventHandler<$Item>
552
+ /**
553
+ * Called when the input element loses focus.
554
+ */
555
+ onBlur?: ItemEventHandler<$Item>
556
+ /**
557
+ * Called on every keystroke or value modification. Unlike
558
+ * {@link BaseSchema.onChange}, fires synchronously.
559
+ */
560
+ onInput?: ItemEventHandler<$Item>
561
+ /**
562
+ * Grouped event handlers, equivalent to the `on[A-Z]`-style
563
+ * callbacks on the schema (e.g. {@link BaseSchema.onFocus}).
564
+ *
565
+ * @see {@link SchemaFields.onInitialize} and other `on`-
566
+ * prefixed properties for per-event documentation.
567
+ */
568
+ events?: SchemaEvents<$Item> & {
569
+ /** @see {@link BaseSchema.onFocus} */
570
+ focus?: ItemEventHandler<$Item>
571
+ /** @see {@link BaseSchema.onBlur} */
572
+ blur?: ItemEventHandler<$Item>
573
+ /** @see {@link BaseSchema.onInput} */
574
+ input?: ItemEventHandler<$Item>
575
+ }
576
+ }
577
+
578
+ export interface SchemaSourceMixin<$Item> {
579
+ /**
580
+ * The form schema used for editing items.
581
+ */
582
+ form?: ResolvableForm<$Item>
583
+ /**
584
+ * Multiple form schemas keyed by item type, for
585
+ * sources with polymorphic content.
586
+ */
587
+ forms?: {
588
+ [key: string]: ResolvableForm
589
+ }
590
+ /**
591
+ * The label given to items. If no itemLabel is given,
592
+ * the default is the 'name' property of the item,
593
+ * followed by the label of the form (plus item id)
594
+ * and other defaults.
595
+ */
596
+ itemLabel?:
597
+ | OrItemAccessor<
598
+ $Item,
599
+ {},
600
+ | string
601
+ | {
602
+ text?: string
603
+ prefix?: string
604
+ suffix?: string
605
+ }
606
+ >
607
+ | false
608
+ /**
609
+ * The columns displayed in the table. Can be an array
610
+ * of property names or an object with column schemas.
611
+ */
612
+ columns?: Columns<$Item> | (keyof $Item)[]
613
+ /**
614
+ * Scope names as defined on the model. When set, the
615
+ * admin renders scope buttons allowing the user to
616
+ * switch between them while editing.
617
+ */
618
+ scopes?:
619
+ | string[]
620
+ | {
621
+ [scopeName: string]:
622
+ | {
623
+ label?: string
624
+ hint?: string
625
+ defaultScope?: boolean
626
+ }
627
+ | string
628
+ }
629
+ /**
630
+ * Use a Vue component to render the items.
631
+ */
632
+ component?: Resolvable<VueComponent>
633
+ /**
634
+ * Custom render function for items.
635
+ */
636
+ render?: ItemAccessor<$Item, {}, string>
637
+ /**
638
+ * Maximum nesting depth for nested sources.
639
+ *
640
+ * @defaultValue `1`
641
+ */
642
+ maxDepth?: number
643
+ /** Buttons for the source. */
644
+ buttons?: Buttons<$Item>
645
+ /**
646
+ * Whether to wrap primitive values in objects.
647
+ */
648
+ wrapPrimitives?: boolean
649
+ /**
650
+ * URL path for the source items.
651
+ */
652
+ path?: string
653
+ /**
654
+ * The property name used as the item's unique
655
+ * identifier.
656
+ *
657
+ * @defaultValue `'id'`
658
+ */
659
+ idKey?: string
660
+ /**
661
+ * Whether the data is stored under its own key in the parent item.
662
+ * When `true`, an "address" source stores data at `item.address`.
663
+ * When `false`, its fields are stored directly on `item`.
664
+ *
665
+ * @defaultValue `true`
666
+ */
667
+ nested?: boolean
668
+ /**
669
+ * Inline form components. When defined, items are
670
+ * edited inline rather than navigating to a separate
671
+ * page.
672
+ */
673
+ components?: Components<$Item>
674
+ /**
675
+ * The number of items displayed per page. When not provided, all items are
676
+ * rendered.
677
+ *
678
+ * @defaultValue `false`
679
+ */
680
+ paginate?: OrItemAccessor<$Item, {}, number>
681
+ /**
682
+ * The default page number for paginated sources.
683
+ */
684
+ page?: number
685
+ /**
686
+ * Whether to display items inline in an expandable form rather
687
+ * than navigating to a separate page. Also implicitly `true`
688
+ * when `components` is defined on the schema.
689
+ *
690
+ * @defaultValue `false`
691
+ */
692
+ inlined?: OrItemAccessor<$Item, {}, boolean>
693
+ /**
694
+ * Whether to add a button to create list items.
695
+ *
696
+ * @defaultValue `false`
697
+ */
698
+ creatable?: OrItemAccessor<$Item, {}, boolean | { label: string }>
699
+ /**
700
+ * Whether to add edit buttons next to the list items.
701
+ *
702
+ * @defaultValue `false`
703
+ */
704
+ editable?: OrItemAccessor<$Item, {}, boolean | { label: string }>
705
+ /**
706
+ * Whether to add delete buttons next to the list items.
707
+ *
708
+ * @defaultValue `false`
709
+ */
710
+ deletable?: OrItemAccessor<$Item, {}, boolean | { label: string }>
711
+ /**
712
+ * The column used for the order resulting from dragging around list entries
713
+ * when the `draggable` property of the list schema is set to `true`.
714
+ */
715
+ orderKey?: string
716
+ /**
717
+ * Whether the items can be reordered by the user. Set the `orderKey` property
718
+ * if you want the order to be persisted into a column.
719
+ * @defaultValue `false`
720
+ */
721
+ draggable?: OrItemAccessor<$Item, {}, boolean>
722
+ /**
723
+ * Whether an inlined form is collapsible.
724
+ * @defaultValue `null`
725
+ */
726
+ collapsible?: OrItemAccessor<$Item, {}, boolean | null>
727
+ /** Whether the inlined form is collapsed. */
728
+ collapsed?: OrItemAccessor<$Item, {}, boolean>
729
+ /**
730
+ * Default sort configuration.
731
+ */
732
+ defaultSort?:
733
+ | string
734
+ | { key: string; order: 'asc' | 'desc' }
735
+ /**
736
+ * Default scope name as defined on the model.
737
+ */
738
+ defaultScope?: string
739
+ /**
740
+ * Resource configuration for loading data from the
741
+ * API.
742
+ */
743
+ resource?: Resource
744
+ /**
745
+ * The name of a view to reference for form schemas and
746
+ * editing navigation.
747
+ */
748
+ view?: string
749
+ }
750
+
751
+ export type SchemaOptionsOption<$Value> =
752
+ | { label: string; value: $Value }
753
+ | $Value
754
+ export type SchemaOptions<$Item, $Option = any> =
755
+ | SchemaOptionsOption<$Option>[]
756
+ | {
757
+ /**
758
+ * The function which is called to load the options.
759
+ * Can be a double-function: the outer function
760
+ * receives the `DitoContext` and returns an inner
761
+ * function that is called to fetch the actual data,
762
+ * enabling reactive dependency tracking.
763
+ */
764
+ data?: OrItemAccessor<
765
+ $Item,
766
+ {},
767
+ OrItemAccessor<$Item, {}, OrPromiseOf<SchemaOptionsOption<$Option>[]>>
768
+ >
769
+ /**
770
+ * Either the key of the option property which should be treated as
771
+ * the option label or a function returning the option label.
772
+ *
773
+ * @defaultValue `'label'` when no label is supplied and the options are
774
+ * objects
775
+ */
776
+ label?: keyof $Option | ItemAccessor<$Item, { option: $Option }, string>
777
+ /**
778
+ * Either the key of the option property which should be
779
+ * treated as the value or a function returning the option
780
+ * value.
781
+ *
782
+ * @defaultValue `'id'` when `relate` is set, otherwise
783
+ * `'value'` when the options are objects.
784
+ */
785
+ value?: keyof $Option | ItemAccessor<$Item, { option: $Option }>
786
+ /**
787
+ * The key of the option property which should used to group the options.
788
+ */
789
+ groupBy?: keyof $Option
790
+ /**
791
+ * Custom equality function for comparing options.
792
+ */
793
+ equals?: (
794
+ a: $Option,
795
+ b: $Option
796
+ ) => boolean
797
+ /**
798
+ * Relative path to resolve options from data
799
+ * within the same form. Uses filesystem-style
800
+ * path notation: `..` navigates up, `/` navigates
801
+ * into nested properties.
802
+ *
803
+ * @example Sibling data
804
+ * ```js
805
+ * // Form data: { tags: [...], selectedTags: [...] }
806
+ * selectedTags: {
807
+ * type: 'checkboxes',
808
+ * relate: true,
809
+ * options: { dataPath: '../tags' }
810
+ * }
811
+ * ```
812
+ *
813
+ * @example Parent data
814
+ * ```js
815
+ * // Root data: { categories: [...], items: [{ category: ... }] }
816
+ * // Inside a form for items:
817
+ * category: {
818
+ * type: 'select',
819
+ * options: { dataPath: '../../../categories' }
820
+ * }
821
+ * ```
822
+ */
823
+ dataPath?: string
824
+ }
825
+
826
+ export interface SchemaOptionsMixin<$Item, $Option = any> {
827
+ /** The available options for selection. */
828
+ options?: SchemaOptions<$Item, $Option>
829
+ /**
830
+ * When true, treats options as related objects. The
831
+ * full object is used during editing, but only the
832
+ * `id` reference is stored on save.
833
+ */
834
+ relate?: boolean
835
+ /**
836
+ * The property key used as the identifier when
837
+ * relating options. Only relevant when `relate` is
838
+ * `true`.
839
+ *
840
+ * @defaultValue `'id'`
841
+ *
842
+ * Note: Only `'id'` is currently supported.
843
+ */
844
+ relateBy?: string
845
+ /**
846
+ * The key of the option property which should be used to
847
+ * group the options.
848
+ */
849
+ groupBy?: OrItemAccessor<$Item, {}, string>
850
+ /**
851
+ * When defined, a search input field will be added to allow
852
+ * searching for specific options.
853
+ */
854
+ search?:
855
+ | ItemAccessor<$Item, { query: string }, OrPromiseOf<$Option[]>>
856
+ | {
857
+ /**
858
+ * Filters options based on the search `query`
859
+ * available in the context. Returns matching
860
+ * options, optionally as a promise.
861
+ */
862
+ filter?: ItemAccessor<$Item, { query: string }, OrPromiseOf<$Option[]>>
863
+ /**
864
+ * Debounce config for the filter. Delays
865
+ * invocation until input pauses.
866
+ */
867
+ debounce?:
868
+ | number
869
+ | {
870
+ delay: number
871
+ immediate?: boolean
872
+ }
873
+ }
874
+ /**
875
+ * Whether the selected option can be edited by navigating
876
+ * to it.
877
+ */
878
+ editable?: OrItemAccessor<$Item, {}, boolean>
879
+ /**
880
+ * The name of a view to reference for form schemas and
881
+ * editing navigation.
882
+ */
883
+ view?: string
884
+ }
885
+
886
+ export interface SchemaNumberMixin<$Item> {
887
+ /**
888
+ * The minimum value.
889
+ */
890
+ min?: OrItemAccessor<$Item, {}, number>
891
+
892
+ /**
893
+ * The maximum value.
894
+ */
895
+ max?: OrItemAccessor<$Item, {}, number>
896
+
897
+ /**
898
+ * The minimum and maximum value.
899
+ */
900
+ range?: OrItemAccessor<$Item, {}, [number, number]>
901
+ /**
902
+ * When defined, buttons with up and down arrows are added next to the input
903
+ * field. Which when pressed will add or subtract `step` from the value.
904
+ */
905
+ step?: OrItemAccessor<$Item, {}, number>
906
+ /**
907
+ * The amount of decimals to round to.
908
+ */
909
+ decimals?: OrItemAccessor<$Item, {}, number>
910
+ /** Validation rules for numeric constraints. */
911
+ rules?: Omit<SchemaNumberMixin<$Item>, 'rules'> & {
912
+ /** Restrict the value to whole numbers. */
913
+ integer?: boolean
914
+ }
915
+ }
916
+
917
+ export interface SchemaTextMixin<$Item> {
918
+ /**
919
+ * Whether to trim whitespace from the value.
920
+ */
921
+ trim?: OrItemAccessor<$Item, {}, boolean>
922
+ }
923
+
924
+ export type SchemaAffix =
925
+ | string
926
+ | {
927
+ /** The component type name for the affix. */
928
+ type?: string
929
+ /** Plain text content for the affix. */
930
+ text?: string
931
+ /** Raw HTML content for the affix. */
932
+ html?: string
933
+ /** Conditionally display the affix. */
934
+ if?: OrItemAccessor<any, {}, boolean>
935
+ }
936
+
937
+ export interface SchemaAffixMixin<$Item> {
938
+ /**
939
+ * Prefix content displayed before the input.
940
+ */
941
+ prefix?: OrArrayOf<SchemaAffix>
942
+ /**
943
+ * Suffix content displayed after the input.
944
+ */
945
+ suffix?: OrArrayOf<SchemaAffix>
946
+ }
947
+
948
+ export interface SchemaDataMixin<$Item> {
949
+ /**
950
+ * Data source for the component.
951
+ */
952
+ data?: OrItemAccessor<$Item, {}, any>
953
+ /**
954
+ * Path to retrieve data from parent context.
955
+ */
956
+ dataPath?: string
957
+ }
958
+
959
+ /**
960
+ * Properties shared by all schemas that support custom
961
+ * instance members and lifecycle events — component
962
+ * schemas, views, and forms.
963
+ */
964
+ export interface SchemaFields<$Item> {
965
+ /**
966
+ * Methods accessible via `this` from event handlers,
967
+ * computed properties, watchers, and templates. Unlike
968
+ * event handlers, methods do not receive a context
969
+ * parameter — use `this.context` to access it.
970
+ */
971
+ methods?: Record<string, (...args: any[]) => any> &
972
+ ThisType<DitoComponentInstance<$Item>>
973
+
974
+ /**
975
+ * Computed properties defined on the component. Can be a
976
+ * getter function or a `{ get, set }` object for
977
+ * read-write computed properties. Getters and setters
978
+ * are called with the component as `this`. Like
979
+ * {@link SchemaFields.methods}, use `this.context` to
980
+ * access the context.
981
+ */
982
+ computed?: Record<
983
+ string,
984
+ | ((this: DitoComponentInstance<$Item>) => any)
985
+ | {
986
+ get: (this: DitoComponentInstance<$Item>) => any
987
+ set: (
988
+ this: DitoComponentInstance<$Item>,
989
+ value: any
990
+ ) => void
991
+ }
992
+ >
993
+
994
+ /**
995
+ * Watchers on data properties or expression paths. Keys
996
+ * are either component names (resolved to
997
+ * `data.${name}`) or arbitrary expression paths. Can be
998
+ * a plain handler function or an object with `handler`,
999
+ * `deep`, and `immediate` options.
1000
+ */
1001
+ watch?:
1002
+ | WatchHandlers<$Item>
1003
+ | ((
1004
+ this: DitoComponentInstance<$Item>
1005
+ ) => WatchHandlers<$Item>)
1006
+
1007
+ /**
1008
+ * Panel schemas rendered in the sidebar. Panels share
1009
+ * the parent's data unless their schema defines its
1010
+ * own `data` property.
1011
+ */
1012
+ panels?: Record<string, PanelSchema<$Item>>
1013
+
1014
+ /**
1015
+ * Called when the schema's component tree is set up.
1016
+ */
1017
+ onInitialize?: ItemEventHandler<$Item>
1018
+ /**
1019
+ * Called once when the schema component is unmounted
1020
+ * from the DOM.
1021
+ */
1022
+ onDestroy?: ItemEventHandler<$Item>
1023
+ /**
1024
+ * Called after data has been fetched from the API.
1025
+ * Fires after all reactive updates have propagated.
1026
+ */
1027
+ onLoad?: ItemEventHandler<$Item>
1028
+ /**
1029
+ * Called after a value change is committed. Fires
1030
+ * after all reactive updates have propagated. Bubbles
1031
+ * to parent schemas — return `false` to stop
1032
+ * propagation.
1033
+ */
1034
+ onChange?: ItemEventHandler<$Item>
1035
+ }
1036
+
1037
+ /** @deprecated Use {@link SchemaFields} instead. */
1038
+ export type SchemaSetupMixin<$Item = any> = SchemaFields<$Item>
1039
+
1040
+ /**
1041
+ * Properties shared by route-level schemas
1042
+ * ({@link ViewSchema} and {@link Form}).
1043
+ */
1044
+ export interface SchemaRoute<$Item = any>
1045
+ extends SchemaFields<$Item>,
1046
+ SchemaOpen<$Item> {
1047
+ /**
1048
+ * Renders with reduced spacing.
1049
+ *
1050
+ * @defaultValue `false`
1051
+ */
1052
+ compact?: boolean
1053
+ /**
1054
+ * Resource configuration for loading data from
1055
+ * the API.
1056
+ */
1057
+ resource?: Resource
1058
+ /**
1059
+ * Enables copy/paste for the data. Set to `true`
1060
+ * for default behavior or provide custom
1061
+ * copy/paste handlers.
1062
+ */
1063
+ clipboard?: ClipboardConfig
1064
+ /**
1065
+ * Additional reactive data properties merged into
1066
+ * the component's data scope.
1067
+ */
1068
+ data?: OrItemAccessor<$Item, {}, Record<string, any>>
1069
+ /**
1070
+ * Whether to use a wider content area.
1071
+ *
1072
+ * @defaultValue `false`
1073
+ */
1074
+ wide?: OrItemAccessor<$Item, {}, boolean>
1075
+ /**
1076
+ * Custom breadcrumb text shown in page navigation.
1077
+ *
1078
+ * @defaultValue `${breadcrumbPrefix} ${label}`
1079
+ */
1080
+ breadcrumb?: string
1081
+ buttons?: Buttons<$Item>
1082
+ /**
1083
+ * Conditionally display this view or form.
1084
+ */
1085
+ if?: OrItemAccessor<$Item, {}, boolean>
1086
+ }
1087
+
1088
+ /** @deprecated Use {@link SchemaRoute} instead. */
1089
+ export type SchemaRouteMixin<$Item = any> = SchemaRoute<$Item>
1090
+
1091
+ export interface ComponentSchema<$Item = any> extends BaseSchema<$Item> {
1092
+ type: 'component'
1093
+ /**
1094
+ * Use a Vue component to render the component. The component is specified
1095
+ * like this: import(...).
1096
+ */
1097
+ component: Resolvable<VueComponent>
1098
+ }
1099
+
1100
+ export interface InputSchema<$Item = any>
1101
+ extends BaseSchema<$Item>,
1102
+ SchemaTextMixin<$Item>,
1103
+ SchemaAffixMixin<$Item> {
1104
+ /**
1105
+ * The type of the component.
1106
+ */
1107
+ type:
1108
+ | 'text'
1109
+ | 'email'
1110
+ | 'url'
1111
+ | 'hostname'
1112
+ | 'domain'
1113
+ | 'tel'
1114
+ | 'password'
1115
+ | 'creditcard'
1116
+ rules?: {
1117
+ text?: boolean
1118
+ email?: boolean
1119
+ url?: boolean
1120
+ hostname?: boolean
1121
+ domain?: boolean
1122
+ password?: boolean
1123
+ creditcard?: boolean
1124
+ }
1125
+ }
1126
+
1127
+ export interface DateSchema<$Item = any>
1128
+ extends BaseSchema<$Item>,
1129
+ SchemaAffixMixin<$Item> {
1130
+ /**
1131
+ * The type of the component.
1132
+ */
1133
+ type: 'date' | 'datetime' | 'time'
1134
+ /**
1135
+ * @defaultValue `En/US`
1136
+ */
1137
+ locale?: string
1138
+ /**
1139
+ * Format configuration for date/time display.
1140
+ */
1141
+ formats?: OrItemAccessor<
1142
+ $Item,
1143
+ {},
1144
+ {
1145
+ date?: DateFormat
1146
+ time?: TimeFormat
1147
+ }
1148
+ >
1149
+ /**
1150
+ * @deprecated Use `formats` instead.
1151
+ */
1152
+ dateFormat?: OrItemAccessor<$Item, {}, DateFormat>
1153
+ }
1154
+
1155
+ export interface ButtonSchema<$Item = any>
1156
+ extends BaseSchema<$Item>,
1157
+ SchemaAffixMixin<$Item> {
1158
+ /**
1159
+ * The type of the component.
1160
+ */
1161
+ type: 'button' | 'submit'
1162
+ closeForm?: OrItemAccessor<$Item, {}, boolean>
1163
+ text?: OrItemAccessor<$Item, {}, string>
1164
+ resource?: Resource
1165
+ onClick?: ItemEventHandler<$Item>
1166
+ onSuccess?: ItemEventHandler<$Item>
1167
+ onError?: ErrorEventHandler<$Item>
1168
+ events?: {
1169
+ click?: ItemEventHandler<$Item>
1170
+ success?: ItemEventHandler<$Item>
1171
+ error?: ErrorEventHandler<$Item>
1172
+ }
1173
+ }
1174
+
1175
+ export interface SwitchSchema<$Item = any> extends BaseSchema<$Item> {
1176
+ /**
1177
+ * The type of the component.
1178
+ */
1179
+ type: 'switch'
1180
+ labels?: {
1181
+ /**
1182
+ * The displayed label when the switch is checked.
1183
+ *
1184
+ * @defaultValue `'on'`
1185
+ */
1186
+ checked?: string
1187
+ /**
1188
+ * The displayed label when the switch is unchecked.
1189
+ *
1190
+ * @defaultValue `'off'`
1191
+ */
1192
+ unchecked?: string
1193
+ }
1194
+ }
1195
+
1196
+ export interface NumberSchema<$Item = any>
1197
+ extends SchemaNumberMixin<$Item>,
1198
+ BaseSchema<$Item>,
1199
+ SchemaAffixMixin<$Item> {
1200
+ /**
1201
+ * The type of the component.
1202
+ */
1203
+ type: 'number' | 'integer'
1204
+ }
1205
+
1206
+ export interface SliderSchema<$Item = any>
1207
+ extends SchemaNumberMixin<$Item>,
1208
+ BaseSchema<$Item> {
1209
+ /**
1210
+ * The type of the component.
1211
+ */
1212
+ type: 'slider'
1213
+ /**
1214
+ * Whether to show a number input alongside the slider.
1215
+ *
1216
+ * @defaultValue `true`
1217
+ */
1218
+ input?: OrItemAccessor<$Item, {}, boolean>
1219
+ }
1220
+
1221
+ export interface TextareaSchema<$Item = any>
1222
+ extends BaseSchema<$Item>,
1223
+ SchemaTextMixin<$Item> {
1224
+ /**
1225
+ * The type of the component.
1226
+ */
1227
+ type: 'textarea'
1228
+ /**
1229
+ * Whether the input element is resizable.
1230
+ */
1231
+ resizable?: OrItemAccessor<$Item, {}, boolean>
1232
+ /**
1233
+ * The amount of visible lines.
1234
+ *
1235
+ * @defaultValue `4`
1236
+ */
1237
+ lines?: number
1238
+ }
1239
+
1240
+ export interface CodeSchema<$Item = any> extends BaseSchema<$Item> {
1241
+ /**
1242
+ * The type of the component.
1243
+ */
1244
+ type: 'code'
1245
+ /**
1246
+ * The code language.
1247
+ *
1248
+ * @defaultValue `js`
1249
+ */
1250
+ language?: OrItemAccessor<$Item, {}, string>
1251
+ /**
1252
+ * The indent size.
1253
+ *
1254
+ * @defaultValue `2`
1255
+ */
1256
+ indentSize?: OrItemAccessor<$Item, {}, number>
1257
+ /**
1258
+ * The amount of visible lines.
1259
+ *
1260
+ * @defaultValue `3`
1261
+ */
1262
+ lines?: OrItemAccessor<$Item, {}, number>
1263
+ /**
1264
+ * Whether the input element is resizable.
1265
+ */
1266
+ resizable?: OrItemAccessor<$Item, {}, boolean>
1267
+ }
1268
+
1269
+ export interface MarkupSchema<$Item = any> extends BaseSchema<$Item> {
1270
+ /**
1271
+ * The type of the component.
1272
+ */
1273
+ type: 'markup'
1274
+ /**
1275
+ * Whether the input element is resizable.
1276
+ */
1277
+ resizable?: OrItemAccessor<$Item, {}, boolean>
1278
+ /**
1279
+ * @defaultValue `'collapse'`
1280
+ */
1281
+ whitespace?: OrItemAccessor<
1282
+ $Item,
1283
+ {},
1284
+ 'collapse' | 'preserve' | 'preserve-all'
1285
+ >
1286
+ /**
1287
+ * The amount of visible lines.
1288
+ *
1289
+ * @defaultValue `10`
1290
+ */
1291
+ lines?: number
1292
+
1293
+ /**
1294
+ * Whether TipTap input and paste rules are enabled. When
1295
+ * `true`, both input and paste rules are active. Can also be
1296
+ * an object to control input and paste rules independently.
1297
+ *
1298
+ * @defaultValue `false`
1299
+ */
1300
+ enableRules?: OrItemAccessor<
1301
+ $Item,
1302
+ {},
1303
+ | boolean
1304
+ | {
1305
+ input: boolean
1306
+ paste: boolean
1307
+ }
1308
+ >
1309
+ /**
1310
+ * Whether Enter creates a hard break instead of a new
1311
+ * paragraph.
1312
+ */
1313
+ hardBreak?: boolean
1314
+ marks?: {
1315
+ bold?: boolean
1316
+ italic?: boolean
1317
+ underline?: boolean
1318
+ strike?: boolean
1319
+ small?: boolean
1320
+ code?: boolean
1321
+ subscript?: boolean
1322
+ superscript?: boolean
1323
+ link?: boolean
1324
+ }
1325
+ nodes?: {
1326
+ blockquote?: boolean
1327
+ codeBlock?: boolean
1328
+ heading?: (1 | 2 | 3 | 4 | 5 | 6)[]
1329
+ horizontalRule?: boolean
1330
+ orderedList?: boolean
1331
+ bulletList?: boolean
1332
+ }
1333
+ tools?: {
1334
+ history?: boolean
1335
+ footnotes?: boolean
1336
+ }
1337
+ }
1338
+
1339
+ export interface LabelSchema<$Item = any> extends BaseSchema<$Item> {
1340
+ /**
1341
+ * The type of the component.
1342
+ */
1343
+ type: 'label'
1344
+ }
1345
+
1346
+ /**
1347
+ * A non-visible component that includes a computed or
1348
+ * derived value in the form data without rendering it.
1349
+ */
1350
+ export interface HiddenSchema<$Item = any>
1351
+ extends BaseSchema<$Item>,
1352
+ SchemaDataMixin<$Item> {
1353
+ /**
1354
+ * The type of the component.
1355
+ */
1356
+ type: 'hidden'
1357
+ }
1358
+
1359
+ export interface UploadSchema<$Item = any> extends BaseSchema<$Item> {
1360
+ /**
1361
+ * The type of the component.
1362
+ */
1363
+ type: 'upload'
1364
+ /**
1365
+ * Whether multiple files can be uploaded.
1366
+ *
1367
+ * @default false
1368
+ */
1369
+ multiple?: boolean
1370
+ /**
1371
+ * Allowed file extensions for upload.
1372
+ * @example 'zip' // Only files with zip extension
1373
+ * @example ['jpg', 'jpeg', 'gif', 'png']
1374
+ * @example /\.(gif|jpe?g|png)$/i
1375
+ */
1376
+ extensions?: OrArrayOf<RegExp | string>
1377
+ /**
1378
+ * One or more unique file type specifiers that describe the type of file
1379
+ * that may be selected for upload by the user.
1380
+ *
1381
+ * @example 'audio/*' // Any type of audio file
1382
+ * @example ['image/png', 'image/gif', 'image/jpeg']
1383
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers }
1384
+ */
1385
+ accept?: OrArrayOf<string>
1386
+ /**
1387
+ * The maximum size of the file expressed as number of bytes or as a string
1388
+ * like `'200kb'`, `'1mb'`, `'3.2gb'`, etc.
1389
+ *
1390
+ * @see {@link https://github.com/patrickkettner/filesize-parser/blob/master/test.js String Examples}
1391
+ */
1392
+ maxSize?: string | number
1393
+ /**
1394
+ * Whether uploaded files can be reordered by dragging.
1395
+ *
1396
+ * @defaultValue `false`
1397
+ */
1398
+ draggable?: OrItemAccessor<$Item, {}, boolean>
1399
+ /**
1400
+ * Whether files can be deleted.
1401
+ */
1402
+ deletable?: OrItemAccessor<$Item, {}, boolean>
1403
+ /**
1404
+ * Custom render function for file display.
1405
+ */
1406
+ render?: ItemAccessor<$Item, {}, string>
1407
+ /**
1408
+ * Whether to display thumbnails for uploaded files, or
1409
+ * thumbnail size.
1410
+ */
1411
+ thumbnails?: OrItemAccessor<$Item, {}, boolean | string>
1412
+ /**
1413
+ * URL or function returning URL for file thumbnails.
1414
+ */
1415
+ thumbnailUrl?: OrItemAccessor<$Item, {}, string>
1416
+ /**
1417
+ * URL or function returning URL for file downloads.
1418
+ */
1419
+ downloadUrl?: OrItemAccessor<$Item, {}, string>
1420
+ }
1421
+
1422
+ export interface MultiselectSchema<$Item = any, $Option = any>
1423
+ extends BaseSchema<$Item>,
1424
+ SchemaOptionsMixin<$Item, $Option>,
1425
+ SchemaAffixMixin<$Item> {
1426
+ /**
1427
+ * The type of the component.
1428
+ */
1429
+ type: 'multiselect'
1430
+ /**
1431
+ * Whether more than one option can be selected.
1432
+ *
1433
+ * @defaultValue `false`
1434
+ */
1435
+ multiple?: boolean
1436
+ /**
1437
+ * Whether to enable a search input field in the dropdown
1438
+ * for filtering options.
1439
+ *
1440
+ * @defaultValue `false`
1441
+ */
1442
+ searchable?: boolean
1443
+ /**
1444
+ * Whether the dropdown stays open after selecting an option,
1445
+ * useful for making multiple selections without repeated
1446
+ * opening.
1447
+ *
1448
+ * @defaultValue `false`
1449
+ */
1450
+ stayOpen?: boolean
1451
+ /**
1452
+ * Whether users can create new options by typing and
1453
+ * pressing Enter, adding custom tags not in the options
1454
+ * list.
1455
+ *
1456
+ * @defaultValue `false`
1457
+ */
1458
+ taggable?: boolean
1459
+ }
1460
+
1461
+ export interface SelectSchema<$Item = any>
1462
+ extends BaseSchema<$Item>,
1463
+ SchemaOptionsMixin<$Item>,
1464
+ SchemaAffixMixin<$Item> {
1465
+ /**
1466
+ * The type of the component.
1467
+ */
1468
+ type: 'select'
1469
+ }
1470
+
1471
+ export interface RadioSchema<$Item = any>
1472
+ extends BaseSchema<$Item>,
1473
+ SchemaOptionsMixin<$Item> {
1474
+ /**
1475
+ * The type of the component.
1476
+ */
1477
+ type: 'radio'
1478
+ /**
1479
+ * @defaultValue `'vertical'`
1480
+ */
1481
+ layout?: 'horizontal' | 'vertical'
1482
+ }
1483
+
1484
+ type SectionContent<$Data> = {
1485
+ /** The section's field components. */
1486
+ components?: Components<$Data>
1487
+ /**
1488
+ * A form schema for the section's content. Use this
1489
+ * instead of `components` to get form-level options
1490
+ * like `label`, `tabs`, and `mutate`.
1491
+ */
1492
+ form?: ResolvableForm<$Data>
1493
+ /**
1494
+ * Display several schemas in different tabs
1495
+ * within the section.
1496
+ */
1497
+ tabs?: Record<
1498
+ string,
1499
+ Omit<Form<$Data>, 'tabs' | 'type'> & {
1500
+ type: 'tab'
1501
+ defaultTab?: OrItemAccessor<$Data, {}, boolean>
1502
+ }
1503
+ >
1504
+ }
1505
+
1506
+ /**
1507
+ * A visual grouping of components within a form.
1508
+ *
1509
+ * By default, the section's components read and write fields
1510
+ * on the parent item directly. When `nested` is `true`, the
1511
+ * section's fields are stored under their own key on the
1512
+ * parent item instead (e.g. `item.address`).
1513
+ *
1514
+ * For non-nested sections, declare the key as `never` in
1515
+ * your item type. For nested sections, declare it as the
1516
+ * object type of the nested data (see {@link Components}).
1517
+ *
1518
+ * @template $Item The parent item type, used for callbacks
1519
+ * like `label` and `collapsible`.
1520
+ * @template $Nested The type of the section's own data.
1521
+ * For nested sections this is the value type at the
1522
+ * section's key (e.g. `Address`). For non-nested sections
1523
+ * this defaults to `$Item`.
1524
+ *
1525
+ * @example Non-nested section (fields stored on parent item)
1526
+ * ```ts
1527
+ * type Item = {
1528
+ * title: string
1529
+ * details: never // UI-only key
1530
+ * }
1531
+ *
1532
+ * const components: Components<Item> = {
1533
+ * details: {
1534
+ * type: 'section',
1535
+ * components: {
1536
+ * title: { type: 'text' }
1537
+ * }
1538
+ * }
1539
+ * }
1540
+ * ```
1541
+ *
1542
+ * @example Nested section (fields stored at `item.address`)
1543
+ * ```ts
1544
+ * type Address = { street: string; city: string }
1545
+ *
1546
+ * type Item = {
1547
+ * title: string
1548
+ * address: Address // data key for nested section
1549
+ * }
1550
+ *
1551
+ * const components: Components<Item> = {
1552
+ * address: {
1553
+ * type: 'section',
1554
+ * nested: true,
1555
+ * components: {
1556
+ * street: { type: 'text' },
1557
+ * city: { type: 'text' }
1558
+ * }
1559
+ * }
1560
+ * }
1561
+ * ```
1562
+ */
1563
+ export type SectionSchema<$Item = any, $Nested = $Item> = BaseSchema<$Item> &
1564
+ SchemaOpen<$Item> & {
1565
+ /**
1566
+ * The type of the component.
1567
+ */
1568
+ type: 'section'
1569
+ /**
1570
+ * Multiple form schemas keyed by item type, for
1571
+ * sections with polymorphic content.
1572
+ */
1573
+ forms?: {
1574
+ [key: string]: ResolvableForm
1575
+ }
1576
+ /**
1577
+ * Renders the section with reduced spacing.
1578
+ *
1579
+ * @defaultValue `false`
1580
+ */
1581
+ compact?: boolean
1582
+ /**
1583
+ * Enables copy/paste for the section's data.
1584
+ */
1585
+ clipboard?: ClipboardConfig
1586
+ /**
1587
+ * Whether the section can be collapsed.
1588
+ */
1589
+ collapsible?: OrItemAccessor<$Item, {}, boolean>
1590
+ /** Whether the section is collapsed. */
1591
+ collapsed?: OrItemAccessor<$Item, {}, boolean>
1592
+ /**
1593
+ * Grouped event handlers.
1594
+ */
1595
+ events?: {
1596
+ /**
1597
+ * Called when a collapsible section is toggled
1598
+ * open or closed.
1599
+ */
1600
+ open?: OpenEventHandler<$Item>
1601
+ }
1602
+ } & (
1603
+ | ({
1604
+ /**
1605
+ * Whether the data is stored under its own key
1606
+ * on the parent item. When `true`, an "address"
1607
+ * section stores data at `item.address`. When
1608
+ * `false` or omitted, the section's fields are
1609
+ * stored directly on the parent item.
1610
+ *
1611
+ * @defaultValue `false`
1612
+ */
1613
+ nested?: false
1614
+ } & SectionContent<$Item>)
1615
+ | ({
1616
+ /**
1617
+ * Whether the data is stored under its own key
1618
+ * on the parent item. When `true`, an "address"
1619
+ * section stores data at `item.address`. When
1620
+ * `false` or omitted, the section's fields are
1621
+ * stored directly on the parent item.
1622
+ *
1623
+ * @defaultValue `false`
1624
+ */
1625
+ nested: true
1626
+ } & SectionContent<$Nested>)
1627
+ )
1628
+
1629
+ export interface CheckboxSchema<$Item = any> extends BaseSchema<$Item> {
1630
+ /**
1631
+ * The type of the component.
1632
+ */
1633
+ type: 'checkbox'
1634
+ }
1635
+
1636
+ export interface CheckboxesSchema<$Item = any>
1637
+ extends BaseSchema<$Item>,
1638
+ SchemaOptionsMixin<$Item> {
1639
+ /**
1640
+ * The type of the component.
1641
+ */
1642
+ type: 'checkboxes'
1643
+ /**
1644
+ * @defaultValue `'vertical'`
1645
+ */
1646
+ layout?: 'horizontal' | 'vertical'
1647
+ }
1648
+
1649
+ export type ColorFormat =
1650
+ | 'rgb'
1651
+ | 'prgb'
1652
+ | 'hex'
1653
+ | 'hex6'
1654
+ | 'hex3'
1655
+ | 'hex4'
1656
+ | 'hex8'
1657
+ | 'name'
1658
+ | 'hsl'
1659
+ | 'hsv'
1660
+ export interface ColorSchema<$Item = any>
1661
+ extends BaseSchema<$Item>,
1662
+ SchemaAffixMixin<$Item> {
1663
+ /**
1664
+ * The type of the component.
1665
+ */
1666
+ type: 'color'
1667
+ /**
1668
+ * The color format.
1669
+ */
1670
+ format?: OrItemAccessor<$Item, {}, ColorFormat>
1671
+ /**
1672
+ * Whether the color may contain an alpha component.
1673
+ *
1674
+ * @defaultValue `false`
1675
+ */
1676
+ alpha?: OrItemAccessor<$Item, {}, boolean>
1677
+ /**
1678
+ * Whether to display input fields for manual color value
1679
+ * entry (e.g. RGB, HSL) in the color picker.
1680
+ *
1681
+ * @defaultValue `true`
1682
+ */
1683
+ inputs?: OrItemAccessor<$Item, {}, boolean>
1684
+ /**
1685
+ * Color presets as an array of color values as strings in any css
1686
+ * compatible format.
1687
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value}
1688
+ */
1689
+ presets?: OrItemAccessor<$Item, {}, string[]>
1690
+ }
1691
+
1692
+ export type ColumnSchema<$Item = any, $Value = any> = {
1693
+ /**
1694
+ * The label of the column.
1695
+ * @defaultValue The labelized column key.
1696
+ */
1697
+ label?: string
1698
+ /**
1699
+ * Use a Vue component to render the cell. The component is specified
1700
+ * like this: import(...).
1701
+ */
1702
+ component?: Resolvable<VueComponent>
1703
+ /**
1704
+ * Whether the column should be sortable.
1705
+ */
1706
+ sortable?: boolean
1707
+ /**
1708
+ * A function of the value and the item returning the displayed name.
1709
+ * If the column is sortable, the column is sorted by value and not by
1710
+ * rendered name.
1711
+ */
1712
+ render?: ItemAccessor<$Item, { value: $Value }, string | null | undefined>
1713
+ /**
1714
+ * The provided string is applied to the class property of the column
1715
+ * cell html elements.
1716
+ */
1717
+ class?: string
1718
+ /**
1719
+ * The provided string is applied to the style property of the column
1720
+ * cell html elements.
1721
+ */
1722
+ style?: string | Partial<CSSStyleDeclaration>
1723
+ /**
1724
+ * Sort the colum in ascending or descending order. Columns are ordered by the
1725
+ * first column to specify `defaultSort`.
1726
+ */
1727
+ defaultSort?: 'asc' | 'desc'
1728
+ /** Whether to display the column. */
1729
+ if?: OrItemAccessor<$Item, {}, boolean>
1730
+ }
1731
+
1732
+ /**
1733
+ * A form that can be provided directly, as a record of named forms
1734
+ * (e.g. a module namespace from `import()`), wrapped in a promise,
1735
+ * or returned from a function.
1736
+ */
1737
+ export type ResolvableForm<$Item = any> = Resolvable<Form<$Item>>
1738
+
1739
+ export interface ListSchema<$Item = { [key: string]: any }>
1740
+ extends SchemaSourceMixin<$Item>,
1741
+ BaseSchema<$Item>,
1742
+ SchemaOpen<$Item> {
1743
+ /**
1744
+ * The type of the component.
1745
+ */
1746
+ type: 'list'
1747
+
1748
+ /**
1749
+ * Filter definitions that render a filter panel above the
1750
+ * list, allowing users to filter displayed items. Each
1751
+ * filter can be a text filter with operators, a date-range
1752
+ * filter, or a custom filter with components.
1753
+ */
1754
+ filters?: {
1755
+ /**
1756
+ * Whether the filters panel header sticks to
1757
+ * the top of the scroll container.
1758
+ */
1759
+ sticky?: boolean
1760
+ [k: string]:
1761
+ | {
1762
+ label?: string
1763
+ filter: 'text'
1764
+ /**
1765
+ * @defaultValue `['contains']`
1766
+ */
1767
+ operators?: ('contains' | 'equals' | 'starts-with' | 'ends-with')[]
1768
+ }
1769
+ | {
1770
+ label?: string
1771
+ filter: 'date-range'
1772
+ }
1773
+ | {
1774
+ label?: string
1775
+ components: Components
1776
+ }
1777
+ | boolean
1778
+ | undefined
1779
+ }
1780
+ /**
1781
+ * Grouped event handlers.
1782
+ */
1783
+ events?: {
1784
+ /**
1785
+ * Called when a collapsible inlined list is
1786
+ * toggled open or closed.
1787
+ */
1788
+ open?: OpenEventHandler<$Item>
1789
+ }
1790
+ }
1791
+
1792
+ export type OrItemAccessor<
1793
+ $Item = any,
1794
+ $Params extends {} = {},
1795
+ $ReturnValue = any
1796
+ > = ItemAccessor<$Item, $Params, $ReturnValue> | $ReturnValue
1797
+
1798
+ /**
1799
+ * Merges two object types into a single flat mapped type.
1800
+ * Unlike `A & B`, this preserves contextual typing for
1801
+ * callback parameters in complex intersections.
1802
+ */
1803
+ type Merge<A, B> = {
1804
+ [K in keyof A | keyof B]: K extends keyof B
1805
+ ? B[K]
1806
+ : K extends keyof A
1807
+ ? A[K]
1808
+ : never
1809
+ }
1810
+
1811
+ export type ItemAccessor<
1812
+ $Item = any,
1813
+ $Params extends {} = {},
1814
+ $ReturnValue = any
1815
+ > = (params: Merge<DitoContext<$Item>, $Params>) => $ReturnValue
1816
+
1817
+ export type DitoContext<$Item = any> = {
1818
+ /**
1819
+ * `true` when the data-path points to a value inside
1820
+ * an item, `false` when it points to the item itself.
1821
+ */
1822
+ nested: boolean
1823
+ /** The current value of the component. */
1824
+ value: any
1825
+ /** Full dot-separated path to the current data. */
1826
+ dataPath: string
1827
+ /** The property name of the current component. */
1828
+ name: string
1829
+ /** The index within a list, if applicable. */
1830
+ index: number | null
1831
+ /**
1832
+ * Data path of the closest item ancestor.
1833
+ */
1834
+ itemDataPath: string
1835
+ /**
1836
+ * Data path of the parent item ancestor.
1837
+ */
1838
+ parentItemDataPath: string
1839
+ /** Index of the closest item in its list. */
1840
+ itemIndex: number | null
1841
+ /** Index of the parent item in its list. */
1842
+ parentItemIndex: number | null
1843
+ /** The current data item. */
1844
+ item: OmitNever<$Item>
1845
+ /**
1846
+ * NOTE: `parentItem` isn't the closest data parent to `item`,
1847
+ * it's the closest parent that isn't an array, e.g. for
1848
+ * relations or nested JSON data. This is why the term `item`
1849
+ * was chosen over `data`, e.g. VS the use of `parentData` in
1850
+ * server-sided validation, which is the closest parent.
1851
+ */
1852
+ parentItem: any
1853
+ /** The top-level root data item. */
1854
+ rootItem: any
1855
+ /**
1856
+ * The cloned data being prepared for server
1857
+ * submission. Available during `process` callbacks,
1858
+ * allowing modification of sibling fields.
1859
+ */
1860
+ processedItem: any
1861
+ /**
1862
+ * The root-level cloned data being prepared for
1863
+ * server submission.
1864
+ */
1865
+ processedRootItem: any
1866
+ /**
1867
+ * The form's current data processed for clipboard
1868
+ * copy/paste operations.
1869
+ */
1870
+ clipboardItem: any
1871
+ /** The currently authenticated user. */
1872
+ user: {
1873
+ roles?: string[]
1874
+ hasRole(...roles: string[]): boolean
1875
+ }
1876
+ /** The admin API configuration. */
1877
+ api: ApiConfig
1878
+ /** The schema definition for the current component. */
1879
+ schema: Component | null
1880
+ /** All registered top-level views. */
1881
+ views: Record<string, View>
1882
+ /** All views flattened into a single record. */
1883
+ flattenedViews: Record<string, ViewSchema>
1884
+ /** Display label of the current item. */
1885
+ itemLabel: string | null
1886
+ /** Display label of the current form. */
1887
+ formLabel: string | null
1888
+ /** The current Vue component instance. */
1889
+ component: DitoComponentInstanceBase | null
1890
+ /**
1891
+ * The nearest ancestor `DitoSchema` component that
1892
+ * manages this field's layout.
1893
+ */
1894
+ schemaComponent: DitoSchemaInstance | null
1895
+ /** The nearest ancestor form component. */
1896
+ formComponent: DitoFormInstance
1897
+ /** The nearest ancestor view component. */
1898
+ viewComponent: DitoViewInstance | null
1899
+ /** The nearest ancestor dialog component. */
1900
+ dialogComponent: DitoComponentInstanceBase | null
1901
+ /** The nearest ancestor panel component. */
1902
+ panelComponent: DitoComponentInstanceBase | null
1903
+ /** The nearest ancestor resource component. */
1904
+ resourceComponent:
1905
+ | DitoFormInstance
1906
+ | DitoSourceInstance
1907
+ | null
1908
+ /** The nearest ancestor source component. */
1909
+ sourceComponent: DitoSourceInstance | null
1910
+ /** The currently focused option in a select. */
1911
+ option: any
1912
+ /** All available options in a select. */
1913
+ options: any
1914
+ /**
1915
+ * Whether a pulldown/select is currently open.
1916
+ */
1917
+ open: boolean | undefined
1918
+ /**
1919
+ * The current search term in select components.
1920
+ */
1921
+ searchTerm: string | undefined
1922
+ /**
1923
+ * Whether a button request is currently running.
1924
+ */
1925
+ isRunning: boolean
1926
+ /** Current URL query parameters. */
1927
+ query: Record<string, string | (string | null)[]>
1928
+ /**
1929
+ * The error object, populated in button `error`
1930
+ * event handler contexts.
1931
+ */
1932
+ error: unknown
1933
+ /**
1934
+ * Whether the event handler already called
1935
+ * `context.notify()`, used to suppress the default
1936
+ * notification for button events.
1937
+ */
1938
+ wasNotified: boolean
1939
+
1940
+ // Helper Methods
1941
+
1942
+ /** Performs an API request with optional caching. */
1943
+ request<T>(options: {
1944
+ /**
1945
+ * Allows caching of loaded data on two levels:
1946
+ * - 'global': cache globally, for the entire admin session
1947
+ * - 'local': cache locally within the closest route
1948
+ * component that is associated with a resource and loads
1949
+ * its own data.
1950
+ */
1951
+ cache?: 'local' | 'global'
1952
+ url: string
1953
+ /**
1954
+ * @default 'get'
1955
+ */
1956
+ method?: HTTPMethod
1957
+ query?:
1958
+ | Record<string, string | number | (string | number)[]>
1959
+ | [string, string | number][]
1960
+ data?: unknown
1961
+ resource?: Resource
1962
+ }): Promise<T>
1963
+ /** Formats values using locale-aware formatters. */
1964
+ format: typeof utilsFormat
1965
+ /** Navigates to a route programmatically. */
1966
+ navigate: VueRouter['push']
1967
+ /**
1968
+ * Triggers a file download from the given URL or
1969
+ * options.
1970
+ */
1971
+ download: {
1972
+ (url: string): void
1973
+ (options: { url: string; filename: string }): void
1974
+ }
1975
+ /** Returns the full URL for a given resource. */
1976
+ getResourceUrl(resource: Resource): string
1977
+ /** Displays a notification to the user. */
1978
+ notify(options: {
1979
+ type?: LiteralUnion<'warning' | 'error' | 'info' | 'success'>
1980
+ title?: string
1981
+ text: OrArrayOf<string>
1982
+ }): void
1983
+ }
1984
+
1985
+ /**
1986
+ * The `this` type inside schema `methods`, `computed`,
1987
+ * and `watch` handlers. Unlike the context passed to
1988
+ * schema accessors like `if` and `label`, this is the
1989
+ * live component instance.
1990
+ *
1991
+ * @template $Item The data item type.
1992
+ * @template $Members Additional schema-defined methods
1993
+ * and computed properties available on `this`.
1994
+ */
1995
+ export type DitoComponentInstance<
1996
+ $Item = any,
1997
+ $Members extends Record<string, any> = {}
1998
+ > = DitoComponentInstanceBase<$Item> & $Members
1999
+
2000
+ export interface DitoComponentInstanceBase<$Item = any> extends EmitterMixin {
2001
+ // -- Data access (ValueMixin, ContextMixin, TypeMixin) --
2002
+
2003
+ /** The current value of the component (getter/setter). */
2004
+ value: any
2005
+ /** The current data item. */
2006
+ item: OmitNever<$Item>
2007
+ /**
2008
+ * The closest parent item that isn't an array (e.g.
2009
+ * for relations or nested JSON data).
2010
+ */
2011
+ parentItem: any
2012
+ /** The top-level root data item. */
2013
+ rootItem: any
2014
+ /**
2015
+ * The cloned data being prepared for server
2016
+ * submission. Available during `process` callbacks.
2017
+ */
2018
+ processedItem: any
2019
+ /** The root-level cloned data for server submission. */
2020
+ processedRootItem: any
2021
+ /** The component's data object. */
2022
+ data: Record<string, any>
2023
+ /** Parent data object, or `null` if same as data. */
2024
+ parentData: Record<string, any> | null
2025
+ /** The property name of the current component. */
2026
+ name: string
2027
+ /** Full dot-separated path to the current data. */
2028
+ dataPath: string
2029
+ /** The schema definition for the current component. */
2030
+ schema: Component
2031
+ /** The component type from the schema. */
2032
+ type: string
2033
+
2034
+ // -- State (TypeMixin, ValidationMixin) --
2035
+
2036
+ /** Whether the component currently has focus. */
2037
+ focused: boolean
2038
+ /** The value after applying `schema.parse()`. */
2039
+ parsedValue: any
2040
+ /** Whether the field has been focused at least once. */
2041
+ isTouched: boolean
2042
+ /** Whether the field value has been modified. */
2043
+ isDirty: boolean
2044
+ /** Whether the field is currently valid. */
2045
+ isValid: boolean
2046
+ /** Whether validation has been run on the field. */
2047
+ isValidated: boolean
2048
+ /** Validation error messages, or `null`. */
2049
+ errors: string[] | null
2050
+ /** Whether the field has validation errors. */
2051
+ hasErrors: boolean
2052
+ /** Whether async data is currently being loaded. */
2053
+ isLoading: boolean
2054
+ /**
2055
+ * Sets the loading state. Optionally propagates
2056
+ * to the root or view component.
2057
+ */
2058
+ setLoading(
2059
+ isLoading: boolean,
2060
+ options?: { updateRoot?: boolean; updateView?: boolean }
2061
+ ): void
2062
+ /**
2063
+ * Whether the component works with data not yet
2064
+ * persisted to the server.
2065
+ */
2066
+ isTransient: boolean
2067
+ /** Whether the component is mounted. */
2068
+ isMounted: boolean
2069
+ /** Whether the component tree is populated. */
2070
+ isPopulated: boolean
2071
+ /**
2072
+ * Whether this component loads its own data from
2073
+ * a resource.
2074
+ */
2075
+ providesData: boolean
2076
+ /** The schema of the source component. */
2077
+ sourceSchema: Component | null
2078
+ /** Action verb labels (create, save, delete, etc.). */
2079
+ verbs: Record<string, string>
2080
+
2081
+ // -- Resolved schema accessors (TypeMixin) --
2082
+
2083
+ /** Resolved `schema.visible` value. */
2084
+ visible: boolean
2085
+ /** Resolved `schema.exclude` value. */
2086
+ exclude: boolean
2087
+ /** Resolved `schema.required` value. */
2088
+ required: boolean
2089
+ /** Resolved `schema.readonly` value. */
2090
+ readonly: boolean
2091
+ /** Resolved `schema.disabled` value. */
2092
+ disabled: boolean
2093
+ /** Resolved `schema.clearable` value. */
2094
+ clearable: boolean
2095
+ /** Resolved `schema.autofocus` value. */
2096
+ autofocus: boolean
2097
+ /** Resolved `schema.placeholder` value. */
2098
+ placeholder: string | undefined
2099
+ /** Resolved `schema.info` value. */
2100
+ info: string | null
2101
+ /** Resolved `schema.maxLength` value. */
2102
+ maxLength: number | undefined
2103
+ /** Resolved `schema.autocomplete` value. */
2104
+ autocomplete: string | undefined
2105
+
2106
+ // -- Component hierarchy (DitoMixin) --
2107
+
2108
+ /** The `DitoContext` for this component. */
2109
+ context: DitoContext<$Item>
2110
+ /** The nearest `DitoSchema` managing layout. */
2111
+ schemaComponent: DitoSchemaInstance
2112
+ /** The nearest ancestor form component. */
2113
+ formComponent: DitoFormInstance
2114
+ /** The nearest ancestor view component. */
2115
+ viewComponent: DitoViewInstance | null
2116
+ /** The nearest ancestor dialog component. */
2117
+ dialogComponent: DitoComponentInstanceBase | null
2118
+ /** The nearest ancestor panel component. */
2119
+ panelComponent: DitoComponentInstanceBase | null
2120
+ /** The nearest ancestor resource component. */
2121
+ resourceComponent: DitoFormInstance | DitoSourceInstance
2122
+ /** The nearest ancestor source component. */
2123
+ sourceComponent: DitoSourceInstance
2124
+ /**
2125
+ * The nearest route component (form or view) in the
2126
+ * ancestor chain.
2127
+ */
2128
+ routeComponent: DitoFormInstance | DitoViewInstance | null
2129
+ /**
2130
+ * The first parent route component that provides and
2131
+ * loads its own data from the API.
2132
+ */
2133
+ dataComponent: DitoFormInstance | DitoViewInstance | null
2134
+ /** The parent schema component. */
2135
+ parentSchemaComponent: DitoComponentInstanceBase | null
2136
+ /** The parent form component. */
2137
+ parentFormComponent: DitoComponentInstanceBase | null
2138
+ /** The root component instance. */
2139
+ rootComponent: DitoComponentInstanceBase | null
2140
+ /** The nearest ancestor tab component. */
2141
+ tabComponent: DitoComponentInstanceBase | null
2142
+ /** The parent route component. */
2143
+ parentRouteComponent:
2144
+ | DitoFormInstance
2145
+ | DitoViewInstance
2146
+ | null
2147
+ /** The parent resource component. */
2148
+ parentResourceComponent:
2149
+ | DitoFormInstance
2150
+ | DitoSourceInstance
2151
+ | null
2152
+
2153
+ // -- Environment (DitoMixin) --
2154
+
2155
+ /** The currently authenticated user. */
2156
+ user: DitoContext['user']
2157
+ /** The admin API configuration. */
2158
+ api: ApiConfig
2159
+ /** Current locale from the API config. */
2160
+ locale: string
2161
+ /** All registered top-level views. */
2162
+ views: Record<string, View>
2163
+ /** All views flattened into a single record. */
2164
+ flattenedViews: Record<string, ViewSchema>
2165
+ /** Data from the first parent route that loads data. */
2166
+ rootData: any
2167
+
2168
+ // -- Actions (DitoMixin) --
2169
+
2170
+ /** Performs an API request with optional caching. */
2171
+ request: DitoContext['request']
2172
+ /** Formats values using locale-aware formatters. */
2173
+ format: DitoContext['format']
2174
+ /** Navigates to a route programmatically. */
2175
+ navigate: DitoContext['navigate']
2176
+ /** Triggers a file download. */
2177
+ download: DitoContext['download']
2178
+ /** Displays a notification to the user. */
2179
+ notify: DitoContext['notify']
2180
+ /** Returns the full URL for a given resource. */
2181
+ getResourceUrl: DitoContext['getResourceUrl']
2182
+ /**
2183
+ * Sends an HTTP request to the API.
2184
+ */
2185
+ sendRequest(options: {
2186
+ method?: HTTPMethod
2187
+ url?: string
2188
+ resource?: Resource
2189
+ query?:
2190
+ | Record<string, string | number | (string | number)[]>
2191
+ | [string, string | number][]
2192
+ data?: unknown
2193
+ signal?: AbortSignal
2194
+ internal?: boolean
2195
+ }): Promise<unknown>
2196
+ /**
2197
+ * Shows a modal dialog and returns a promise that
2198
+ * resolves with the dialog result.
2199
+ */
2200
+ showDialog(options: {
2201
+ components?: Components
2202
+ buttons?: Buttons<any>
2203
+ data?: Record<string, any>
2204
+ settings?: Record<string, any>
2205
+ }): Promise<unknown>
2206
+ /**
2207
+ * Resolves a schema value by key or data-path,
2208
+ * with optional type coercion and default.
2209
+ */
2210
+ getSchemaValue(
2211
+ keyOrDataPath: string,
2212
+ options?: {
2213
+ type?: Function | Function[]
2214
+ default?: any
2215
+ schema?: Component
2216
+ context?: DitoContext
2217
+ callback?: boolean
2218
+ }
2219
+ ): any
2220
+ /** Returns a human-readable label for a schema. */
2221
+ getLabel(
2222
+ schema: Component | null,
2223
+ name?: string
2224
+ ): string
2225
+ /**
2226
+ * Returns a Vue Router location object with the
2227
+ * given query params and the current hash
2228
+ * preserved (for tab navigation).
2229
+ */
2230
+ getQueryLink(
2231
+ query: Record<string, any>
2232
+ ): { query: Record<string, any>; hash: string }
2233
+ /**
2234
+ * Returns `true` if the schema's `if` accessor
2235
+ * evaluates to `true` (or is absent).
2236
+ */
2237
+ shouldRenderSchema(
2238
+ schema?: Component | null
2239
+ ): boolean
2240
+ /**
2241
+ * Returns the resolved `visible` value for a
2242
+ * schema. Defaults to `true`.
2243
+ */
2244
+ shouldShowSchema(
2245
+ schema?: Component | null
2246
+ ): boolean
2247
+ /**
2248
+ * Returns the resolved `disabled` value for a
2249
+ * schema. Defaults to `false`.
2250
+ */
2251
+ shouldDisableSchema(
2252
+ schema?: Component | null
2253
+ ): boolean
2254
+ /**
2255
+ * Emits a schema event by name (e.g. `'change'`,
2256
+ * `'focus'`). Calls the matching `on[Event]`
2257
+ * handler and the `events[event]` handler on the
2258
+ * schema. Returns the handler result, or
2259
+ * `undefined` if no handler was found. The event
2260
+ * bubbles to parent schemas unless the handler
2261
+ * returns `false`.
2262
+ *
2263
+ * @param event The event name to emit.
2264
+ * @param options.context Custom context properties
2265
+ * merged into the `DitoContext` passed to the
2266
+ * event handler.
2267
+ */
2268
+ emitEvent(
2269
+ event: string,
2270
+ options?: {
2271
+ context?: DitoContext
2272
+ }
2273
+ ): Promise<any>
2274
+ /**
2275
+ * Emits a schema event on the nearest schema
2276
+ * component (rather than `this`). Used by form
2277
+ * and resource components to emit lifecycle
2278
+ * events like `'load'` and `'submit'`.
2279
+ */
2280
+ emitSchemaEvent(
2281
+ event: string,
2282
+ params?: Record<string, any>
2283
+ ): Promise<any>
2284
+ /** Converts a camelCase name to a human-readable label. */
2285
+ labelize(name: string): string
2286
+ /** Gets a value from the component store. */
2287
+ getStore(key: string): any
2288
+ /** Sets a value in the component store. */
2289
+ setStore(key: string, value: any): any
2290
+ /** Removes a value from the component store. */
2291
+ removeStore(key: string): void
2292
+
2293
+ // -- Actions (TypeMixin) --
2294
+
2295
+ /** Focuses the component and scrolls it into view. */
2296
+ focus(): Promise<void>
2297
+ /** Blurs the component. */
2298
+ blur(): void
2299
+ /** Clears the value, blurs, and triggers onChange. */
2300
+ clear(): void
2301
+ /** Scrolls the component into view. */
2302
+ scrollIntoView(): Promise<void>
2303
+
2304
+ // -- Actions (ValidationMixin) --
2305
+
2306
+ /**
2307
+ * Validates the field. Returns `true` if valid.
2308
+ * When `notify` is `true` (default), updates state
2309
+ * and emits errors.
2310
+ */
2311
+ validate(notify?: boolean): boolean
2312
+ /** Validates without notifying (shorthand). */
2313
+ verify(): boolean
2314
+ /** Marks the field as touched and clears errors. */
2315
+ markTouched(): void
2316
+ /** Marks the field as dirty and resets validation. */
2317
+ markDirty(): void
2318
+ /** Resets all validation state. */
2319
+ resetValidation(): void
2320
+ /** Adds an error message to the errors array. */
2321
+ addError(error: string, addLabel?: boolean): void
2322
+ /**
2323
+ * Shows server-side validation errors on the
2324
+ * component. Returns `true` if errors were shown.
2325
+ */
2326
+ showValidationErrors(
2327
+ errors: { message: string }[],
2328
+ focus: boolean
2329
+ ): boolean
2330
+ /** Returns a copy of the current errors, or `null`. */
2331
+ getErrors(): string[] | null
2332
+ /** Clears all validation errors. */
2333
+ clearErrors(): void
2334
+ /** Closes all notification toasts. */
2335
+ closeNotifications(): void
2336
+ }
2337
+
2338
+ export interface EmitterMixin {
2339
+ /** Registers one or more event listeners. */
2340
+ on(
2341
+ event:
2342
+ | string
2343
+ | string[]
2344
+ | Record<string, Function>,
2345
+ callback?: Function
2346
+ ): this
2347
+ /** Registers a one-time event listener. */
2348
+ once(event: string, callback: Function): this
2349
+ /** Removes event listener(s). */
2350
+ off(
2351
+ event?:
2352
+ | string
2353
+ | string[]
2354
+ | Record<string, Function>,
2355
+ callback?: Function
2356
+ ): this
2357
+ /** Emits an event asynchronously (queued). */
2358
+ emit(event: string, ...args: any[]): Promise<any>
2359
+ /** Returns `true` if listeners exist for the event(s). */
2360
+ hasListeners(event: string | string[]): boolean
2361
+ /** Re-emits events from this component on the target. */
2362
+ delegate(
2363
+ event: string | string[],
2364
+ target: EmitterMixin
2365
+ ): this
2366
+ }
2367
+
2368
+ export interface DitoFormInstance<$Item = any>
2369
+ extends DitoComponentInstanceBase<$Item> {
2370
+ /**
2371
+ * Whether this form is creating a new item
2372
+ * (`true`) or editing an existing one (`false`).
2373
+ */
2374
+ isCreating: boolean
2375
+
2376
+ /**
2377
+ * Submits the form data to the API. Returns
2378
+ * `true` on success, `false` if validation
2379
+ * fails or the request errors.
2380
+ */
2381
+ submit(
2382
+ button?: DitoComponentInstanceBase,
2383
+ options?: {
2384
+ validate?: boolean
2385
+ closeForm?: boolean
2386
+ }
2387
+ ): Promise<boolean>
2388
+
2389
+ /**
2390
+ * Cancels the form and navigates to the parent
2391
+ * route.
2392
+ */
2393
+ cancel(): Promise<void>
2394
+
2395
+ /**
2396
+ * Closes the form and navigates to the parent
2397
+ * route.
2398
+ */
2399
+ close(): Promise<void>
2400
+
2401
+ /**
2402
+ * Validates all fields in the form. Optionally
2403
+ * filter fields with a match pattern. Returns
2404
+ * `true` if all matched fields are valid.
2405
+ */
2406
+ validateAll(
2407
+ match?:
2408
+ | string
2409
+ | string[]
2410
+ | RegExp
2411
+ | ((field: string) => boolean),
2412
+ notify?: boolean
2413
+ ): boolean
2414
+
2415
+ /**
2416
+ * Like {@link validateAll} but without
2417
+ * triggering error notifications.
2418
+ */
2419
+ verifyAll(
2420
+ match?:
2421
+ | string
2422
+ | string[]
2423
+ | RegExp
2424
+ | ((field: string) => boolean)
2425
+ ): boolean
2426
+
2427
+ // -- Resource & route (ResourceMixin, RouteMixin) --
2428
+
2429
+ /** Display label for this form. */
2430
+ label: string
2431
+ /** Breadcrumb text for navigation. */
2432
+ breadcrumb: string
2433
+ /** Prefix prepended to the breadcrumb label. */
2434
+ breadcrumbPrefix: string
2435
+ /** Whether this is the last route in the hierarchy. */
2436
+ isLastRoute: boolean
2437
+ /** Whether this route is nested inside another route. */
2438
+ isNestedRoute: boolean
2439
+ /** Zero-based depth of this route in the hierarchy. */
2440
+ routeLevel: number
2441
+
2442
+ /**
2443
+ * The resolved API resource for this component,
2444
+ * or `null` if none is configured.
2445
+ */
2446
+ resource: Resource | null
2447
+ /**
2448
+ * Whether loaded data is available on this
2449
+ * component.
2450
+ */
2451
+ hasData: boolean
2452
+ /**
2453
+ * Reloads data from the API without clearing
2454
+ * the existing data first.
2455
+ */
2456
+ reloadData(): void
2457
+ /**
2458
+ * Ensures data is loaded: reloads if data
2459
+ * exists, otherwise loads fresh.
2460
+ */
2461
+ ensureData(): void
2462
+ /** Clears the loaded data. */
2463
+ clearData(): void
2464
+ /** Sets the component's loaded data directly. */
2465
+ setData(data: any): void
2466
+ /**
2467
+ * Creates a new data object with default values
2468
+ * from the schema. Optionally sets a `type`
2469
+ * property for polymorphic forms.
2470
+ */
2471
+ createData(
2472
+ schema: Component,
2473
+ type?: string
2474
+ ): Record<string, any>
2475
+ /**
2476
+ * The route parameter value for this route
2477
+ * component (e.g. an item id or `'create'`).
2478
+ */
2479
+ param: string | number | null
2480
+ /**
2481
+ * Whether the form directly mutates the
2482
+ * parent's data instead of working on a copy.
2483
+ */
2484
+ isMutating: boolean
2485
+ /**
2486
+ * Builds a child route path relative to this
2487
+ * route component's path.
2488
+ */
2489
+ getChildPath(path: string): string
2490
+ }
2491
+
2492
+ export interface DitoViewInstance<$Item = any>
2493
+ extends DitoComponentInstanceBase<$Item> {
2494
+ /** Always `true` for view components. */
2495
+ isView: true
2496
+
2497
+ // -- Route (RouteMixin) --
2498
+
2499
+ /** Display label for this view. */
2500
+ label: string
2501
+ /** Breadcrumb text for navigation. */
2502
+ breadcrumb: string
2503
+ /** Prefix prepended to the breadcrumb label. */
2504
+ breadcrumbPrefix: string
2505
+ /** Whether this is the last route in the hierarchy. */
2506
+ isLastRoute: boolean
2507
+ /** Whether this route is nested inside another route. */
2508
+ isNestedRoute: boolean
2509
+ /** Zero-based depth of this route in the hierarchy. */
2510
+ routeLevel: number
2511
+ /**
2512
+ * The route parameter value for this route
2513
+ * component (e.g. an item id or `'create'`).
2514
+ */
2515
+ param: string | number | null
2516
+ /**
2517
+ * Whether the view directly mutates the
2518
+ * parent's data instead of working on a copy.
2519
+ */
2520
+ isMutating: boolean
2521
+ /**
2522
+ * Builds a child route path relative to this
2523
+ * route component's path.
2524
+ */
2525
+ getChildPath(path: string): string
2526
+
2527
+ // -- Data & schema (DitoView) --
2528
+
2529
+ /** The view's reactive data object. */
2530
+ data: Record<string, any>
2531
+ /** The resolved view schema definition. */
2532
+ viewSchema: ViewSchema
2533
+ /**
2534
+ * Whether this view contains a single inlined
2535
+ * source component (renders without a table header).
2536
+ */
2537
+ isSingleComponentView: boolean
2538
+ /**
2539
+ * Whether this view loads its own data from
2540
+ * a resource.
2541
+ */
2542
+ providesData: boolean
2543
+ /** Sets the view's data directly. */
2544
+ setData(data: any): void
2545
+
2546
+ // -- Validation (ValidatorMixin) --
2547
+
2548
+ /**
2549
+ * Validates all fields in the view.
2550
+ * Optionally filter fields with a match pattern.
2551
+ * Returns `true` if all matched fields are valid.
2552
+ */
2553
+ validateAll(
2554
+ match?:
2555
+ | string
2556
+ | string[]
2557
+ | RegExp
2558
+ | ((field: string) => boolean),
2559
+ notify?: boolean
2560
+ ): boolean
2561
+
2562
+ /**
2563
+ * Like {@link validateAll} but without
2564
+ * triggering error notifications.
2565
+ */
2566
+ verifyAll(
2567
+ match?:
2568
+ | string
2569
+ | string[]
2570
+ | RegExp
2571
+ | ((field: string) => boolean)
2572
+ ): boolean
2573
+ }
2574
+
2575
+ export interface DitoSchemaInstance<$Item = any>
2576
+ extends DitoComponentInstanceBase<$Item> {
2577
+ /**
2578
+ * Validates all fields in the schema.
2579
+ * Optionally filter fields with a match pattern
2580
+ * (string, string[], RegExp, or function).
2581
+ * Returns `true` if all matched fields are
2582
+ * valid.
2583
+ */
2584
+ validateAll(
2585
+ match?:
2586
+ | string
2587
+ | string[]
2588
+ | RegExp
2589
+ | ((field: string) => boolean),
2590
+ notify?: boolean
2591
+ ): boolean
2592
+
2593
+ /**
2594
+ * Like {@link validateAll} but without
2595
+ * triggering error notifications.
2596
+ */
2597
+ verifyAll(
2598
+ match?:
2599
+ | string
2600
+ | string[]
2601
+ | RegExp
2602
+ | ((field: string) => boolean)
2603
+ ): boolean
2604
+ }
2605
+
2606
+ export interface DitoSourceInstance<$Item = any>
2607
+ extends DitoComponentInstanceBase<$Item> {
2608
+ // -- Data access (SourceMixin) --
2609
+
2610
+ /** The list data array (getter/setter). */
2611
+ listData: any[]
2612
+ /** The object data (getter/setter). */
2613
+ objectData: Record<string, any> | null
2614
+ /** Total number of items (for pagination). */
2615
+ total: number
2616
+ /** Current query parameters (getter/setter). */
2617
+ query: Record<string, any>
2618
+ /** Whether this source manages a list. */
2619
+ isListSource: boolean
2620
+ /** Whether this source manages an object. */
2621
+ isObjectSource: boolean
2622
+ /** Whether the source renders inline. */
2623
+ isInlined: boolean
2624
+ /**
2625
+ * Nesting depth of sources (0 for top-level,
2626
+ * increments for nested sources).
2627
+ */
2628
+ sourceDepth: number
2629
+ /** The URL path for this source. */
2630
+ path: string
2631
+
2632
+ // -- Resolved schema accessors (SourceMixin) --
2633
+
2634
+ /** Whether new items can be created. */
2635
+ creatable: boolean
2636
+ /** Whether existing items can be edited. */
2637
+ editable: boolean
2638
+ /** Whether items can be deleted. */
2639
+ deletable: boolean
2640
+ /** Whether items can be reordered by dragging. */
2641
+ draggable: boolean
2642
+ /** Whether inlined forms are collapsible. */
2643
+ collapsible: boolean
2644
+ /** Whether inlined forms are collapsed. */
2645
+ collapsed: boolean
2646
+ /** Resolved pagination page size. */
2647
+ paginate: number | undefined
2648
+ /** Maximum nesting depth for nested sources. */
2649
+ maxDepth: number
2650
+ /** Whether the source renders in compact mode. */
2651
+ isCompact: boolean
2652
+
2653
+ // -- Schema introspection (SourceMixin) --
2654
+
2655
+ /** Resolved column definitions. */
2656
+ columns: Record<string, ColumnSchema> | null
2657
+ /** Resolved scope definitions. */
2658
+ scopes: Record<string, any> | null
2659
+ /** Resolved form definitions. */
2660
+ forms: Form[]
2661
+ /** Resolved button schemas. */
2662
+ buttonSchemas: Record<string, ButtonSchema<any>>
2663
+
2664
+ // -- Item operations (SourceMixin) --
2665
+
2666
+ /**
2667
+ * Creates a new data item with defaults from the
2668
+ * schema. Optionally sets a `type` property for
2669
+ * polymorphic forms.
2670
+ */
2671
+ createItem(
2672
+ schema: Component,
2673
+ type?: string
2674
+ ): Record<string, any>
2675
+ /** Removes an item from the list data locally. */
2676
+ removeItem(item: any, index: number): void
2677
+ /**
2678
+ * Deletes an item via the API and removes it
2679
+ * from the list.
2680
+ */
2681
+ deleteItem(item: any, index: number): void
2682
+ /**
2683
+ * Navigates to a component identified by its
2684
+ * data path.
2685
+ */
2686
+ navigateToComponent(
2687
+ dataPath: string,
2688
+ onComplete?: Function
2689
+ ): Promise<boolean>
2690
+ /**
2691
+ * Navigates to the route component associated
2692
+ * with a data path.
2693
+ */
2694
+ navigateToRouteComponent(
2695
+ dataPath: string,
2696
+ onComplete?: Function
2697
+ ): Promise<boolean>
2698
+
2699
+ // -- Resource (ResourceMixin) --
2700
+
2701
+ /**
2702
+ * The resolved API resource for this component,
2703
+ * or `null` if none is configured.
2704
+ */
2705
+ resource: Resource | null
2706
+ /**
2707
+ * Whether loaded data is available on this
2708
+ * component.
2709
+ */
2710
+ hasData: boolean
2711
+ /**
2712
+ * Reloads data from the API without clearing
2713
+ * the existing data first.
2714
+ */
2715
+ reloadData(): void
2716
+ /**
2717
+ * Ensures data is loaded: reloads if data
2718
+ * exists, otherwise loads fresh.
2719
+ */
2720
+ ensureData(): void
2721
+ /** Clears the loaded data. */
2722
+ clearData(): void
2723
+ /** Sets the component's loaded data directly. */
2724
+ setData(data: any): void
2725
+ /**
2726
+ * Creates a new data object with default values
2727
+ * from the schema. Optionally sets a `type`
2728
+ * property for polymorphic forms.
2729
+ */
2730
+ createData(
2731
+ schema: Component,
2732
+ type?: string
2733
+ ): Record<string, any>
2734
+ }
2735
+
2736
+ export interface MenuSchema<$Item = any> {
2737
+ type: 'menu'
2738
+ /**
2739
+ * The label shown in the navigation menu.
2740
+ */
2741
+ label?: string
2742
+ /**
2743
+ * The name of the menu group.
2744
+ *
2745
+ * @defaultValue Camelized from `label`.
2746
+ */
2747
+ name?: string
2748
+ /** Sub-views shown as menu items under this group. */
2749
+ items: Record<string, OrPromiseOf<View<$Item>>>
2750
+ }
2751
+
2752
+ export type ClipboardConfig =
2753
+ | boolean
2754
+ | {
2755
+ copy?: (context: DitoContext) => unknown
2756
+ paste?: (context: DitoContext) => unknown
2757
+ }
2758
+
2759
+ export type View<$Item = any> =
2760
+ | ViewSchema<$Item>
2761
+ | MenuSchema<$Item>
2762
+
2763
+ export interface ViewSchema<$Item = any> extends SchemaRoute<$Item> {
2764
+ type: 'view'
2765
+ /**
2766
+ * The label shown in the navigation menu.
2767
+ *
2768
+ * @defaultValue The title-cased view name.
2769
+ */
2770
+ label?: string
2771
+ /**
2772
+ * The URL path for the view.
2773
+ */
2774
+ path?: string
2775
+ /**
2776
+ * The name of the view.
2777
+ */
2778
+ name?: string
2779
+ /**
2780
+ * Display several schemas in different tabs within
2781
+ * the view.
2782
+ */
2783
+ tabs?: Record<
2784
+ string,
2785
+ Omit<ViewSchema<$Item>, 'tabs' | 'type'> & {
2786
+ type: 'tab'
2787
+ /**
2788
+ * Whether this tab is selected by default.
2789
+ */
2790
+ defaultTab?: OrItemAccessor<$Item, {}, boolean>
2791
+ }
2792
+ >
2793
+ /**
2794
+ * Grouped event handlers, equivalent to the
2795
+ * `on[A-Z]`-style callbacks on the view schema
2796
+ * (e.g. {@link ViewSchema.onOpen}).
2797
+ *
2798
+ * @see {@link SchemaFields.onInitialize} and
2799
+ * other `on`-prefixed properties for per-event
2800
+ * documentation.
2801
+ */
2802
+ events?: SchemaEvents<$Item> & {
2803
+ /**
2804
+ * Called when a collapsible schema section is
2805
+ * toggled open or closed.
2806
+ */
2807
+ open?: OpenEventHandler<$Item>
2808
+ }
2809
+ component?: Component<$Item>
2810
+ components?: Components<$Item>
2811
+ }
2812
+
2813
+ /**
2814
+ * A non-visible component that computes a value and
2815
+ * stores it in the form data.
2816
+ */
2817
+ export interface ComputedSchema<$Item = any>
2818
+ extends BaseSchema<$Item>,
2819
+ SchemaDataMixin<$Item> {
2820
+ /**
2821
+ * The type of the component.
2822
+ */
2823
+ type: 'computed'
2824
+ }
2825
+
2826
+ /**
2827
+ * A non-visible component that fetches external data
2828
+ * and stores it in the form data.
2829
+ */
2830
+ export interface DataSchema<$Item = any>
2831
+ extends BaseSchema<$Item>,
2832
+ SchemaDataMixin<$Item> {
2833
+ /**
2834
+ * The type of the component.
2835
+ */
2836
+ type: 'data'
2837
+ }
2838
+
2839
+ export interface ObjectSchema<$Item = { [key: string]: any }>
2840
+ extends SchemaSourceMixin<$Item>,
2841
+ BaseSchema<$Item>,
2842
+ SchemaOpen<$Item> {
2843
+ /**
2844
+ * The type of the component.
2845
+ */
2846
+ type: 'object'
2847
+ /**
2848
+ * Grouped event handlers.
2849
+ */
2850
+ events?: {
2851
+ /**
2852
+ * Called when a collapsible inlined object is
2853
+ * toggled open or closed.
2854
+ */
2855
+ open?: OpenEventHandler<$Item>
2856
+ }
2857
+ }
2858
+
2859
+ interface TreeSchema<$Item, $Type extends 'tree-list' | 'tree-object'>
2860
+ extends SchemaSourceMixin<$Item>,
2861
+ BaseSchema<$Item> {
2862
+ /**
2863
+ * The type of the component.
2864
+ */
2865
+ type: $Type
2866
+ /**
2867
+ * Nested tree schema describing the recursive
2868
+ * children of each node. The `name` property
2869
+ * identifies which data property holds the
2870
+ * children array.
2871
+ */
2872
+ children?: Omit<TreeListSchema<$Item>, 'type'> & {
2873
+ name: string
2874
+ }
2875
+ /**
2876
+ * Properties schema for tree nodes.
2877
+ */
2878
+ properties?: Record<string, Component<$Item>>
2879
+ /**
2880
+ * Whether child nodes are expanded by default.
2881
+ */
2882
+ open?: boolean
2883
+ }
2884
+
2885
+ export type TreeListSchema<$Item = any> = TreeSchema<$Item, 'tree-list'>
2886
+ export type TreeObjectSchema<$Item = any> = TreeSchema<$Item, 'tree-object'>
2887
+ export type PanelSchema<$Item = any> = BaseSchema<$Item> & {
2888
+ /**
2889
+ * The type of the component.
2890
+ */
2891
+ type: 'panel'
2892
+ /**
2893
+ * The components within the panel.
2894
+ */
2895
+ components?: Components<$Item>
2896
+ /** Buttons rendered at the bottom of the panel. */
2897
+ buttons?: Buttons<$Item>
2898
+ /**
2899
+ * Buttons rendered in the panel header, next to the
2900
+ * title. Displayed at a smaller size.
2901
+ */
2902
+ panelButtons?: Buttons<$Item>
2903
+ /**
2904
+ * Whether the panel header sticks to the top of the
2905
+ * scroll container.
2906
+ *
2907
+ * @defaultValue `false`
2908
+ */
2909
+ sticky?: OrItemAccessor<$Item, {}, boolean>
2910
+ }
2911
+
2912
+ export interface SpacerSchema<$Item = any> extends BaseSchema<$Item> {
2913
+ /**
2914
+ * The type of the component.
2915
+ */
2916
+ type: 'spacer'
2917
+ }
2918
+
2919
+ export interface ProgressSchema<$Item = any>
2920
+ extends SchemaNumberMixin<$Item>,
2921
+ BaseSchema<$Item> {
2922
+ /**
2923
+ * The type of the component.
2924
+ */
2925
+ type: 'progress'
2926
+ }
2927
+
2928
+ type NonSectionComponent<$Item = any> =
2929
+ | InputSchema<$Item>
2930
+ | RadioSchema<$Item>
2931
+ | CheckboxSchema<$Item>
2932
+ | CheckboxesSchema<$Item>
2933
+ | ColorSchema<$Item>
2934
+ | SelectSchema<$Item>
2935
+ | MultiselectSchema<$Item>
2936
+ | ListSchema<$Item>
2937
+ | TextareaSchema<$Item>
2938
+ | CodeSchema<$Item>
2939
+ | NumberSchema<$Item>
2940
+ | SliderSchema<$Item>
2941
+ | UploadSchema<$Item>
2942
+ | MarkupSchema<$Item>
2943
+ | ButtonSchema<$Item>
2944
+ | SwitchSchema<$Item>
2945
+ | DateSchema<$Item>
2946
+ | ComponentSchema<$Item>
2947
+ | LabelSchema<$Item>
2948
+ | HiddenSchema<$Item>
2949
+ | ObjectSchema<$Item>
2950
+ | TreeListSchema<$Item>
2951
+ | TreeObjectSchema<$Item>
2952
+ | ComputedSchema<$Item>
2953
+ | DataSchema<$Item>
2954
+ | SpacerSchema<$Item>
2955
+ | ProgressSchema<$Item>
2956
+
2957
+ export type Component<$Item = any> =
2958
+ | NonSectionComponent<$Item>
2959
+ | SectionSchema<$Item>
2960
+
2961
+ /**
2962
+ * Source components (list, object, tree) that contain nested
2963
+ * items with their own item type.
2964
+ */
2965
+ export type SourceComponent<$Item = any> =
2966
+ | ListSchema<$Item>
2967
+ | ObjectSchema<$Item>
2968
+ | TreeListSchema<$Item>
2969
+ | TreeObjectSchema<$Item>
2970
+
2971
+ /**
2972
+ * Strips properties with `never` values from a type.
2973
+ */
2974
+ type OmitNever<T> = {
2975
+ [K in keyof T as [T[K]] extends [never] ? never : K]: T[K]
2976
+ } & {}
2977
+
2978
+ /**
2979
+ * Defines the components for a form or view.
2980
+ *
2981
+ * When you provide an `$Item` type, each component key must match
2982
+ * a property on that type, and callbacks receive a typed `item`
2983
+ * whose type depends on that property:
2984
+ *
2985
+ * - **Regular data fields** (e.g. `title: string`): callbacks
2986
+ * receive the full parent item type.
2987
+ * - **Array fields** (e.g. `entries: Entry[]`): nested list or
2988
+ * tree components use the array element type (`Entry`).
2989
+ * - **UI-only keys** (e.g. `viewButton: never`): for components
2990
+ * like buttons, spacers, or sections that exist only in the UI
2991
+ * and are not actual data fields. Declare these keys as `never`.
2992
+ * They are omitted from `item` in callbacks.
2993
+ *
2994
+ * Only keys defined in `$Item` are allowed. Unknown keys are a
2995
+ * type error.
2996
+ *
2997
+ * @example
2998
+ * ```ts
2999
+ * type Entry = { id: number; title: string }
3000
+ *
3001
+ * type Item = {
3002
+ * title: string
3003
+ * entries: Entry[]
3004
+ * viewButton: never // UI-only key for a button
3005
+ * details: never // UI-only key for a section
3006
+ * }
3007
+ *
3008
+ * const components: Components<Item> = {
3009
+ * // regular data field — callbacks receive Item
3010
+ * title: { type: 'text' },
3011
+ *
3012
+ * // array field — callbacks receive Entry, not Item
3013
+ * entries: {
3014
+ * type: 'list',
3015
+ * form: {
3016
+ * type: 'form',
3017
+ * components: {
3018
+ * title: {
3019
+ * type: 'text',
3020
+ * // item is typed as Entry, not Item
3021
+ * onChange({ item }) { console.log(item.title) }
3022
+ * }
3023
+ * }
3024
+ * }
3025
+ * },
3026
+ *
3027
+ * // UI-only key — item omits viewButton and details
3028
+ * viewButton: {
3029
+ * type: 'button',
3030
+ * events: {
3031
+ * click({ item }) { ... }
3032
+ * }
3033
+ * },
3034
+ *
3035
+ * // UI-only key — sections group fields from the parent item
3036
+ * details: {
3037
+ * type: 'section',
3038
+ * components: {
3039
+ * title: { type: 'text' }
3040
+ * }
3041
+ * }
3042
+ * }
3043
+ * ```
3044
+ */
3045
+ export type Components<$Item = any> = 0 extends 1 & $Item
3046
+ ? Record<string, Component>
3047
+ : {
3048
+ [K in keyof $Item]?: [$Item[K]] extends [never]
3049
+ ? NonSectionComponent<$Item> | SectionSchema<$Item>
3050
+ : $Item[K] extends (infer E)[]
3051
+ ? E extends Record<string, any>
3052
+ ? NonSectionComponent<E>
3053
+ : NonSectionComponent<$Item>
3054
+ : $Item[K] extends Record<string, any>
3055
+ ?
3056
+ | NonSectionComponent<$Item>
3057
+ | SectionSchema<$Item, $Item[K]>
3058
+ :
3059
+ | NonSectionComponent<$Item>
3060
+ | SectionSchema<$Item>
3061
+ }
3062
+
3063
+ export type Columns<$Item = any> = 0 extends 1 & $Item
3064
+ ? { [key: string]: ColumnSchema | undefined }
3065
+ : {
3066
+ [K in keyof $Item]?: ColumnSchema<$Item, $Item[K]>
3067
+ } & {
3068
+ [key: string]: ColumnSchema<$Item> | undefined
3069
+ }
3070
+
3071
+ export type Buttons<$Item> = Record<
3072
+ string,
3073
+ SetOptional<ButtonSchema<$Item>, 'type'>
3074
+ >
3075
+
3076
+ export interface Form<$Item = any> extends SchemaRoute<$Item> {
3077
+ type: 'form'
3078
+
3079
+ /**
3080
+ * The name of the item model produced by the form.
3081
+ */
3082
+ name?: OrItemAccessor<$Item, {}, string>
3083
+ /**
3084
+ * The label of the form.
3085
+ */
3086
+ label?: OrItemAccessor<$Item, {}, string | boolean>
3087
+ /**
3088
+ * Whether the form directly mutates the parent data instead
3089
+ * of working on a copy.
3090
+ *
3091
+ * @defaultValue `false`
3092
+ */
3093
+ mutate?: boolean
3094
+ /**
3095
+ * The property name used as the item's unique identifier.
3096
+ *
3097
+ * @defaultValue `'id'`
3098
+ */
3099
+ idKey?: string
3100
+ /**
3101
+ * Display several forms in different tabs within the form.
3102
+ */
3103
+ tabs?: Record<
3104
+ string,
3105
+ Omit<Form<$Item>, 'tabs' | 'type'> & {
3106
+ type: 'tab'
3107
+ /**
3108
+ * Whether this tab is selected by default.
3109
+ */
3110
+ defaultTab?: OrItemAccessor<$Item, {}, boolean>
3111
+ }
3112
+ >
3113
+ /** The form's field components. */
3114
+ components?: Components<$Item>
3115
+ /**
3116
+ * Grouped event handlers, equivalent to the
3117
+ * `on[A-Z]`-style callbacks on the form schema
3118
+ * (e.g. {@link Form.onOpen}).
3119
+ *
3120
+ * @see {@link SchemaFields.onInitialize} and
3121
+ * other `on`-prefixed properties for per-event
3122
+ * documentation.
3123
+ */
3124
+ events?: SchemaEvents<$Item> & {
3125
+ /**
3126
+ * Called when a collapsible schema section is
3127
+ * toggled open or closed.
3128
+ */
3129
+ open?: OpenEventHandler<$Item>
3130
+ /**
3131
+ * Called after a new item is successfully
3132
+ * created and persisted.
3133
+ */
3134
+ create?: ItemEventHandler<$Item>
3135
+ /**
3136
+ * Called after an existing item is successfully
3137
+ * submitted and persisted.
3138
+ */
3139
+ submit?: ItemEventHandler<$Item>
3140
+ /**
3141
+ * Called when a submit request fails. The
3142
+ * `error` property on the context contains the
3143
+ * request error.
3144
+ */
3145
+ error?: ErrorEventHandler<$Item>
3146
+ }
3147
+ /**
3148
+ * Called after a new item is successfully
3149
+ * created and persisted.
3150
+ */
3151
+ onCreate?: ItemEventHandler<$Item>
3152
+ /**
3153
+ * Called after an existing item is successfully
3154
+ * submitted and persisted.
3155
+ */
3156
+ onSubmit?: ItemEventHandler<$Item>
3157
+ /**
3158
+ * Called when a submit request fails. The
3159
+ * `error` property on the context contains the
3160
+ * request error.
3161
+ */
3162
+ onError?: ErrorEventHandler<$Item>
3163
+ }
3164
+
3165
+ export type Resource =
3166
+ | string
3167
+ | RequireAtLeastOne<{
3168
+ path?: string
3169
+ method?: HTTPMethod
3170
+ data?: unknown
3171
+ }>
3172
+
3173
+ export class DitoAdmin<
3174
+ $Views extends Record<string, OrPromiseOf<View>> = Record<
3175
+ string,
3176
+ OrPromiseOf<View>
3177
+ >
3178
+ > {
3179
+ /** The DOM element the admin is mounted to. */
3180
+ el: Element
3181
+ /** The resolved API configuration. */
3182
+ api: ApiConfig
3183
+ /** The Vue application instance. */
3184
+ app: import('vue').App
3185
+ /** Additional options passed at construction. */
3186
+ options: Record<string, any>
3187
+
3188
+ constructor(
3189
+ element: Element | string,
3190
+ options?: {
3191
+ // `dito` contains the base and api settings passed from
3192
+ // `AdminController`
3193
+ dito?: DitoGlobal
3194
+ api?: ApiConfig
3195
+ views: OrFunctionReturning<OrPromiseOf<$Views>>
3196
+ login?: {
3197
+ additionalComponents?: Components
3198
+ redirectAfterLogin?: string
3199
+ }
3200
+ /**
3201
+ * Controls the loading spinner displayed in the
3202
+ * admin header. Set to `null` to disable it.
3203
+ */
3204
+ spinner?: {
3205
+ size?: string
3206
+ color?: string
3207
+ } | null
3208
+ [key: string]: any
3209
+ }
3210
+ )
3211
+
3212
+ /**
3213
+ * Registers a custom component type with the admin.
3214
+ */
3215
+ register(
3216
+ type: OrArrayOf<string>,
3217
+ options: Record<string, unknown>
3218
+ ): VueComponent
3219
+ }
3220
+ export type HTTPMethod =
3221
+ | 'get'
3222
+ | 'head'
3223
+ | 'post'
3224
+ | 'put'
3225
+ | 'delete'
3226
+ | 'patch'
3227
+ | 'options'
3228
+ | 'trace'
3229
+ | 'connect'
3230
+ /** @deprecated Use `HTTPMethod` instead. */
3231
+ export type HTTPVerb = HTTPMethod
3232
+
3233
+ export type SchemaByType<$Item = any> = {
3234
+ 'button': ButtonSchema<$Item>
3235
+ 'checkbox': CheckboxSchema<$Item>
3236
+ 'checkboxes': CheckboxesSchema<$Item>
3237
+ 'code': CodeSchema<$Item>
3238
+ 'color': ColorSchema<$Item>
3239
+ 'component': ComponentSchema<$Item>
3240
+ 'computed': ComputedSchema<$Item>
3241
+ 'creditcard': InputSchema<$Item>
3242
+ 'data': DataSchema<$Item>
3243
+ 'date': DateSchema<$Item>
3244
+ 'datetime': DateSchema<$Item>
3245
+ 'domain': InputSchema<$Item>
3246
+ 'email': InputSchema<$Item>
3247
+ 'hostname': InputSchema<$Item>
3248
+ 'integer': NumberSchema<$Item>
3249
+ 'list': ListSchema<$Item>
3250
+ 'markup': MarkupSchema<$Item>
3251
+ 'multiselect': MultiselectSchema<$Item>
3252
+ 'number': NumberSchema<$Item>
3253
+ 'object': ObjectSchema<$Item>
3254
+ 'password': InputSchema<$Item>
3255
+ 'progress': ProgressSchema<$Item>
3256
+ 'radio': RadioSchema<$Item>
3257
+ 'select': SelectSchema<$Item>
3258
+ 'slider': SliderSchema<$Item>
3259
+ 'spacer': SpacerSchema<$Item>
3260
+ 'submit': ButtonSchema<$Item>
3261
+ 'switch': SwitchSchema<$Item>
3262
+ 'tel': InputSchema<$Item>
3263
+ 'text': InputSchema<$Item>
3264
+ 'textarea': TextareaSchema<$Item>
3265
+ 'time': DateSchema<$Item>
3266
+ 'tree-list': TreeListSchema<$Item>
3267
+ 'tree-object': TreeObjectSchema<$Item>
3268
+ 'upload': UploadSchema<$Item>
3269
+ 'url': InputSchema<$Item>
3270
+ 'label': LabelSchema<$Item>
3271
+ 'section': SectionSchema<$Item>
3272
+ 'hidden': HiddenSchema<$Item>
3273
+ 'unknown': never
3274
+ }
3275
+
3276
+ export type OrRecordOf<T> = T | Record<string, T>
3277
+ export type OrPromiseOf<T> = T | Promise<T>
3278
+ export type OrFunctionReturning<T> = (() => T) | T
3279
+ export type OrArrayOf<T> = T | T[]
3280
+ export type Resolvable<T> = OrFunctionReturning<OrPromiseOf<OrRecordOf<T>>>
3281
+
3282
+ type WatchHandler<$Item> = (
3283
+ this: DitoComponentInstance<$Item>,
3284
+ value: any,
3285
+ oldValue: any
3286
+ ) => void
3287
+
3288
+ type WatchEntry<$Item> =
3289
+ | WatchHandler<$Item>
3290
+ | {
3291
+ handler: WatchHandler<$Item>
3292
+ deep?: boolean
3293
+ immediate?: boolean
3294
+ }
3295
+
3296
+ type WatchHandlers<$Item> = Record<string, WatchEntry<$Item>>
3297
+
3298
+ type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>)