@omnitend/dashboard-for-laravel 0.33.1 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/charts.js +82 -90
  2. package/dist/charts.js.map +1 -1
  3. package/dist/charts.umd.cjs +1 -1
  4. package/dist/charts.umd.cjs.map +1 -1
  5. package/dist/components/base/DButton.vue.d.ts +1 -1
  6. package/dist/components/charts/DXBarChart.vue.d.ts +3 -18
  7. package/dist/components/charts/DXLineChart.vue.d.ts +3 -18
  8. package/dist/components/charts/useThemedChart.d.ts +35 -0
  9. package/dist/components/extended/DXChoiceField.vue.d.ts +26 -0
  10. package/dist/components/extended/DXDashboardSidebar.vue.d.ts +1 -1
  11. package/dist/components/extended/DXField.vue.d.ts +10 -113
  12. package/dist/components/extended/DXFieldShell.vue.d.ts +73 -0
  13. package/dist/components/extended/DXNumericField.vue.d.ts +23 -0
  14. package/dist/components/extended/DXRepeater.vue.d.ts +4 -4
  15. package/dist/components/extended/DXRepeaterCards.vue.d.ts +45 -0
  16. package/dist/components/extended/DXTable.vue.d.ts +69 -2
  17. package/dist/components/extended/DXTableEditorModal.vue.d.ts +17 -2
  18. package/dist/components/extended/DXUserAvatar.vue.d.ts +1 -1
  19. package/dist/composables/useAsyncOptions.d.ts +20 -0
  20. package/dist/composables/useResourceEditor.d.ts +2 -1
  21. package/dist/dashboard-for-laravel.js +9982 -10052
  22. package/dist/dashboard-for-laravel.js.map +1 -1
  23. package/dist/dashboard-for-laravel.umd.cjs +7 -7
  24. package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
  25. package/dist/index.d.ts +3 -2
  26. package/dist/style.css +1 -1
  27. package/dist/types/index.d.ts +146 -0
  28. package/dist/utils/formSchema.d.ts +59 -0
  29. package/docs/public/api-reference.json +458 -30
  30. package/docs/public/docs-map.md +1 -1
  31. package/docs/public/llms.txt +5 -2
  32. package/package.json +1 -1
  33. package/resources/js/components/charts/DXBarChart.vue +4 -43
  34. package/resources/js/components/charts/DXLineChart.vue +4 -43
  35. package/resources/js/components/charts/useThemedChart.ts +69 -0
  36. package/resources/js/components/extended/DXChoiceField.vue +114 -0
  37. package/resources/js/components/extended/DXField.vue +328 -615
  38. package/resources/js/components/extended/DXFieldShell.vue +124 -0
  39. package/resources/js/components/extended/DXForm.vue +9 -5
  40. package/resources/js/components/extended/DXNumericField.vue +144 -0
  41. package/resources/js/components/extended/DXRepeater.vue +53 -175
  42. package/resources/js/components/extended/DXRepeaterCards.vue +133 -0
  43. package/resources/js/components/extended/DXTable.vue +202 -32
  44. package/resources/js/components/extended/DXTableEditorModal.vue +34 -2
  45. package/resources/js/composables/defineForm.ts +8 -44
  46. package/resources/js/composables/useAsyncOptions.ts +61 -0
  47. package/resources/js/composables/useResourceEditor.ts +24 -38
  48. package/resources/js/index.ts +33 -0
  49. package/resources/js/types/index.ts +231 -0
  50. package/resources/js/utils/formSchema.ts +126 -0
@@ -0,0 +1,35 @@
1
+ import { type ComputedRef } from "vue";
2
+ import type { ChartData, ChartDataset, ChartOptions } from "chart.js";
3
+ import { type ChartValueFormat } from "./chartTheme";
4
+ /**
5
+ * Shared props for the value-axis chart wrappers (`DXBarChart`, `DXLineChart`).
6
+ * `DXBarChart` and `DXLineChart` differ ONLY in the chart.js component they
7
+ * render and the palette kind — everything else (theming, option-merge,
8
+ * legend-default) is identical, and lived duplicated in both SFCs (#135).
9
+ */
10
+ export interface ThemedChartProps<TType extends "bar" | "line"> {
11
+ /** X-axis category labels. */
12
+ labels: string[];
13
+ /** Chart.js datasets. Colours are themed when a dataset omits them. */
14
+ datasets: ChartDataset<TType>[];
15
+ /** Chart.js options; deep-merged over the themed defaults. */
16
+ options?: ChartOptions<TType>;
17
+ /** Format value-axis ticks and tooltips. */
18
+ valueFormat?: ChartValueFormat;
19
+ /** Currency symbol for valueFormat: "currency" (default "£"). */
20
+ currencySymbol?: string;
21
+ /** Locale for number formatting. */
22
+ locale?: string;
23
+ /** Show the legend (default: only when there is more than one dataset). */
24
+ showLegend?: boolean;
25
+ }
26
+ /**
27
+ * The themed-chart body shared by `DXBarChart` and `DXLineChart`: applies the
28
+ * data-viz palette to un-coloured datasets and deep-merges the consumer's
29
+ * `options` over the dashboard-friendly defaults. Pass the reactive `props`
30
+ * object (property access stays reactive inside the computeds).
31
+ */
32
+ export declare function useThemedChart<TType extends "bar" | "line">(type: TType, props: ThemedChartProps<TType>): {
33
+ chartData: ComputedRef<ChartData<TType>>;
34
+ mergedOptions: ComputedRef<ChartOptions<TType>>;
35
+ };
@@ -0,0 +1,26 @@
1
+ import type { FieldDefinition, FieldOption } from "../../types";
2
+ interface Props {
3
+ /** Field definition (type select/radio/checkbox-group + `searchable`). */
4
+ field: FieldDefinition;
5
+ /** Current model value. */
6
+ modelValue: any;
7
+ /** Resolved options (async-loaded or static). */
8
+ options?: FieldOption[];
9
+ /** Validation state passed to the control. */
10
+ state?: boolean | null;
11
+ /** Pre-merged disabled state (`isDisabled || isReadonly || isPlaintext`). */
12
+ disabled?: boolean;
13
+ /** Escape-hatch control props, already guard-merged by DXField. */
14
+ controlProps?: Record<string, any>;
15
+ /**
16
+ * Whether async options have resolved (a searchable select must not render
17
+ * before its options load, or it shows the raw id instead of the label).
18
+ */
19
+ optionsReady?: boolean;
20
+ }
21
+ declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
22
+ "update:modelValue": (value: any) => any;
23
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
24
+ "onUpdate:modelValue"?: ((value: any) => any) | undefined;
25
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
+ export default _default;
@@ -46,8 +46,8 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}
46
46
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
47
47
  onToggle?: (() => any) | undefined;
48
48
  }>, {
49
- title: string;
50
49
  hidden: boolean;
50
+ title: string;
51
51
  collapsed: boolean;
52
52
  collapsibleGroups: boolean;
53
53
  autoCollapseInactiveGroups: boolean;
@@ -42,142 +42,39 @@ declare var __VLS_1: {
42
42
  model: any;
43
43
  value: any;
44
44
  update: typeof setValue;
45
- }, __VLS_9: {
45
+ }, __VLS_6: {
46
46
  field: FieldDefinition;
47
47
  model: any;
48
- }, __VLS_11: {
48
+ }, __VLS_8: {
49
49
  field: FieldDefinition;
50
50
  model: any;
51
- value: any;
52
- update: typeof setValue;
53
- }, __VLS_22: {
54
- field: FieldDefinition;
55
- model: any;
56
- }, __VLS_27: {
57
- field: FieldDefinition;
58
- model: any;
59
- }, __VLS_32: {
51
+ }, __VLS_10: {
60
52
  field: FieldDefinition;
61
53
  model: any;
62
54
  value: any;
63
55
  update: typeof setValue;
64
- }, __VLS_43: {
65
- field: FieldDefinition;
66
- model: any;
67
- }, __VLS_48: {
68
- field: FieldDefinition;
69
- model: any;
70
- }, __VLS_59: {
71
- field: FieldDefinition;
72
- model: any;
73
- }, __VLS_61: {
74
- field: FieldDefinition;
75
- model: any;
76
- value: any;
77
- update: typeof setValue;
78
- }, __VLS_72: {
79
- field: FieldDefinition;
80
- model: any;
81
- }, __VLS_77: {
82
- field: FieldDefinition;
83
- model: any;
84
- }, __VLS_82: {
85
- field: FieldDefinition;
86
- model: any;
87
- value: any;
88
- update: typeof setValue;
89
- }, __VLS_93: {
90
- field: FieldDefinition;
91
- model: any;
92
- }, __VLS_98: {
93
- field: FieldDefinition;
94
- model: any;
95
- }, __VLS_119: {
56
+ }, __VLS_52: {
96
57
  option: FieldOption;
97
58
  on: boolean;
98
- }, __VLS_124: {
99
- field: FieldDefinition;
100
- model: any;
101
- }, __VLS_129: {
102
- field: FieldDefinition;
103
- model: any;
104
- }, __VLS_144: {
59
+ }, __VLS_64: {
105
60
  row: any;
106
61
  index: number;
107
62
  fields: FieldDefinition[];
108
63
  remove: () => void;
109
64
  path: string;
110
- }, __VLS_146: {
111
- field: FieldDefinition;
112
- model: any;
113
- }, __VLS_151: {
114
- field: FieldDefinition;
115
- model: any;
116
- }, __VLS_162: {
117
- field: FieldDefinition;
118
- model: any;
119
- }, __VLS_164: {
120
- field: FieldDefinition;
121
- model: any;
122
- value: any;
123
- update: typeof setValue;
124
- }, __VLS_230: {
125
- field: FieldDefinition;
126
- model: any;
127
- }, __VLS_235: {
128
- field: FieldDefinition;
129
- model: any;
130
65
  };
131
66
  type __VLS_Slots = {} & {
132
67
  span?: (props: typeof __VLS_1) => any;
133
68
  } & {
134
- hint?: (props: typeof __VLS_9) => any;
135
- } & {
136
- value?: (props: typeof __VLS_11) => any;
137
- } & {
138
- info?: (props: typeof __VLS_22) => any;
139
- } & {
140
- hint?: (props: typeof __VLS_27) => any;
141
- } & {
142
- value?: (props: typeof __VLS_32) => any;
143
- } & {
144
- info?: (props: typeof __VLS_43) => any;
145
- } & {
146
- hint?: (props: typeof __VLS_48) => any;
147
- } & {
148
- hint?: (props: typeof __VLS_59) => any;
149
- } & {
150
- value?: (props: typeof __VLS_61) => any;
151
- } & {
152
- info?: (props: typeof __VLS_72) => any;
153
- } & {
154
- hint?: (props: typeof __VLS_77) => any;
155
- } & {
156
- value?: (props: typeof __VLS_82) => any;
157
- } & {
158
- info?: (props: typeof __VLS_93) => any;
159
- } & {
160
- hint?: (props: typeof __VLS_98) => any;
161
- } & {
162
- 'switch-list-item'?: (props: typeof __VLS_119) => any;
163
- } & {
164
- info?: (props: typeof __VLS_124) => any;
165
- } & {
166
- hint?: (props: typeof __VLS_129) => any;
167
- } & {
168
- 'repeater-row'?: (props: typeof __VLS_144) => any;
169
- } & {
170
- info?: (props: typeof __VLS_146) => any;
171
- } & {
172
- hint?: (props: typeof __VLS_151) => any;
69
+ hint?: (props: typeof __VLS_6) => any;
173
70
  } & {
174
- hint?: (props: typeof __VLS_162) => any;
71
+ info?: (props: typeof __VLS_8) => any;
175
72
  } & {
176
- value?: (props: typeof __VLS_164) => any;
73
+ value?: (props: typeof __VLS_10) => any;
177
74
  } & {
178
- info?: (props: typeof __VLS_230) => any;
75
+ 'switch-list-item'?: (props: typeof __VLS_52) => any;
179
76
  } & {
180
- hint?: (props: typeof __VLS_235) => any;
77
+ 'repeater-row'?: (props: typeof __VLS_64) => any;
181
78
  };
182
79
  declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
183
80
  declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
@@ -0,0 +1,73 @@
1
+ import type { UseFormReturn } from "../../composables/useForm";
2
+ import type { FieldDefinition } from "../../types";
3
+ interface Props {
4
+ /** The field definition (for `field.help` and slot props). */
5
+ field: FieldDefinition;
6
+ /** Form instance owning the field's errors. */
7
+ form: UseFormReturn<any>;
8
+ /** Error key for validation lookups. */
9
+ errorKey: string;
10
+ /** Model passed to `hint`/`info` slot props. */
11
+ model?: any;
12
+ /**
13
+ * Layout shape. `group` = DFormGroup root with a label column; `plain` =
14
+ * plain div, the control owning its own inline label/heading.
15
+ */
16
+ mode: "group" | "plain";
17
+ /** Wrapper class (`field.class || 'mb-3'`). */
18
+ wrapperClass?: string;
19
+ /** BFormGroup attrs (horizontal label-cols etc.); group mode only. */
20
+ groupAttrs?: Record<string, any>;
21
+ /** Resolved label text (group mode). Always supplied by DXField. */
22
+ label: string;
23
+ /** Resolved info text for the label popover (group mode). */
24
+ info?: string;
25
+ /** Skip the label column entirely (group mode). */
26
+ hideLabel?: boolean;
27
+ /**
28
+ * Whether the hint sits in the label column (horizontal) rather than below
29
+ * the control. Group mode only; plain mode always renders the hint below.
30
+ */
31
+ hintInLabel?: boolean;
32
+ /** Resolved hint text (fallback when no `hint` slot is supplied). */
33
+ resolvedHint?: string;
34
+ }
35
+ declare var __VLS_8: {
36
+ field: FieldDefinition;
37
+ model: any;
38
+ }, __VLS_10: {}, __VLS_15: {
39
+ field: FieldDefinition;
40
+ model: any;
41
+ }, __VLS_20: {
42
+ field: FieldDefinition;
43
+ model: any;
44
+ }, __VLS_25: {}, __VLS_30: {
45
+ field: FieldDefinition;
46
+ model: any;
47
+ }, __VLS_35: {
48
+ field: FieldDefinition;
49
+ model: any;
50
+ };
51
+ type __VLS_Slots = {} & {
52
+ hint?: (props: typeof __VLS_8) => any;
53
+ } & {
54
+ default?: (props: typeof __VLS_10) => any;
55
+ } & {
56
+ info?: (props: typeof __VLS_15) => any;
57
+ } & {
58
+ hint?: (props: typeof __VLS_20) => any;
59
+ } & {
60
+ default?: (props: typeof __VLS_25) => any;
61
+ } & {
62
+ info?: (props: typeof __VLS_30) => any;
63
+ } & {
64
+ hint?: (props: typeof __VLS_35) => any;
65
+ };
66
+ declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
67
+ declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
68
+ export default _default;
69
+ type __VLS_WithSlots<T, S> = T & {
70
+ new (): {
71
+ $slots: S;
72
+ };
73
+ };
@@ -0,0 +1,23 @@
1
+ import type { FieldDefinition } from "../../types";
2
+ interface Props {
3
+ /** Field definition (type currency/percentage/number + numeric options). */
4
+ field: FieldDefinition;
5
+ /** Current model value. */
6
+ modelValue: any;
7
+ /** Validation state passed to the control. */
8
+ state?: boolean | null;
9
+ /** Disabled state (`isDisabled`). */
10
+ isDisabled?: boolean;
11
+ /** Readonly state (`isReadonly`). */
12
+ isReadonly?: boolean;
13
+ /** Plaintext (display-only) state (`isPlaintext`). */
14
+ isPlaintext?: boolean;
15
+ /** Escape-hatch input props, already guard-merged by DXField. */
16
+ inputProps?: Record<string, any>;
17
+ }
18
+ declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
19
+ "update:modelValue": (value: any) => any;
20
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
21
+ "onUpdate:modelValue"?: ((value: any) => any) | undefined;
22
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
23
+ export default _default;
@@ -16,13 +16,13 @@ declare var __VLS_1: {
16
16
  fields: FieldDefinition[];
17
17
  remove: () => void;
18
18
  path: string;
19
- }, __VLS_24: {
19
+ }, __VLS_27: {
20
20
  row: any;
21
21
  index: number;
22
22
  fields: FieldDefinition[];
23
23
  remove: () => void;
24
24
  path: string;
25
- }, __VLS_43: {
25
+ }, __VLS_32: {
26
26
  row: any;
27
27
  index: number;
28
28
  fields: FieldDefinition[];
@@ -32,9 +32,9 @@ declare var __VLS_1: {
32
32
  type __VLS_Slots = {} & {
33
33
  row?: (props: typeof __VLS_1) => any;
34
34
  } & {
35
- row?: (props: typeof __VLS_24) => any;
35
+ row?: (props: typeof __VLS_27) => any;
36
36
  } & {
37
- row?: (props: typeof __VLS_43) => any;
37
+ row?: (props: typeof __VLS_32) => any;
38
38
  };
39
39
  declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
40
40
  declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
@@ -0,0 +1,45 @@
1
+ import type { UseFormReturn } from "../../composables/useForm";
2
+ import type { FieldDefinition } from "../../types";
3
+ interface Props {
4
+ /** Rows shown in the UI, each paired with its real (unfiltered) array index. */
5
+ visibleRows: Array<{
6
+ row: any;
7
+ index: number;
8
+ }>;
9
+ /** Sub-field definitions for a row. */
10
+ subFields: FieldDefinition[];
11
+ /** Form instance owning the repeater array. */
12
+ form: UseFormReturn<any>;
13
+ /** The repeater field definition (for `showRowIndex` and `addLabel`). */
14
+ field: FieldDefinition;
15
+ /** Minimum rows — the Remove button disables at this count. */
16
+ minItems: number;
17
+ /** Maximum rows — the Add button disables at this count. */
18
+ maxItems: number | undefined;
19
+ /** Stable v-for key for a row (owned by DXRepeater — row identity, not index). */
20
+ rowKey: (row: any, fallbackPosition: number) => string | number;
21
+ /** Dot path into form.data for a row at the given true index. */
22
+ rowPath: (index: number) => string;
23
+ /** Remove the row at the given true index (respects minItems / soft-delete). */
24
+ removeRow: (index: number) => void;
25
+ /** Append a fresh row (respects maxItems). */
26
+ addRow: () => void;
27
+ }
28
+ declare var __VLS_1: {
29
+ row: any;
30
+ index: number;
31
+ fields: FieldDefinition[];
32
+ remove: () => void;
33
+ path: string;
34
+ };
35
+ type __VLS_Slots = {} & {
36
+ row?: (props: typeof __VLS_1) => any;
37
+ };
38
+ declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
39
+ declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
40
+ export default _default;
41
+ type __VLS_WithSlots<T, S> = T & {
42
+ new (): {
43
+ $slots: S;
44
+ };
45
+ };
@@ -1,3 +1,4 @@
1
+ import type { FieldDefinition, LabelCols } from "../../types";
1
2
  export type FilterType = 'text' | 'select' | 'number' | 'date' | false;
2
3
  export interface FilterOption {
3
4
  value: string;
@@ -117,6 +118,35 @@ export interface EditTab {
117
118
  /** Lazy load tab content (optional, default false) */
118
119
  lazy?: boolean;
119
120
  }
121
+ /**
122
+ * Discriminated data-source descriptor (#130). The additive, type-safe
123
+ * replacement for the legacy `items` / `provider` / `apiUrl` / `inertiaUrl` /
124
+ * `clientSide` prop matrix, in which every prop was independently optional and
125
+ * the mode was inferred by precedence — so invalid combinations compiled and
126
+ * some were silently ignored.
127
+ *
128
+ * Pass ONE `source`: the mode is explicit and its required companion prop is
129
+ * enforced by the compiler (`{ mode: 'provider' }` without a `provider` won't
130
+ * type-check). The legacy props still work and take over when `source` is
131
+ * omitted; a future major removes them with a codemod (#130 Phase 3).
132
+ *
133
+ * `apiAdapter` (transport translation) and `pagination` (server-supplied page
134
+ * metadata) stay sibling props — they're orthogonal to which mode is active.
135
+ */
136
+ export type DXTableSource<TItem = any> = {
137
+ mode: 'client';
138
+ items: TItem[];
139
+ } | {
140
+ mode: 'provider';
141
+ provider: BTableProvider<TItem>;
142
+ } | {
143
+ mode: 'api';
144
+ url: string;
145
+ } | {
146
+ mode: 'inertia';
147
+ items: TItem[];
148
+ url?: string;
149
+ };
120
150
  export interface Props<TItem = any> {
121
151
  /** Table title */
122
152
  title?: string;
@@ -131,6 +161,13 @@ export interface Props<TItem = any> {
131
161
  /** Adapts the built-in provider's request params / response body to a
132
162
  * backend convention that differs from dfl's (see DXTableApiAdapter). */
133
163
  apiAdapter?: DXTableApiAdapter;
164
+ /**
165
+ * Discriminated data-source (#130) — the type-safe alternative to the
166
+ * legacy `items` / `provider` / `apiUrl` / `inertiaUrl` / `clientSide`
167
+ * props. When set it WINS over those props; when omitted, the legacy props
168
+ * apply unchanged. See `DXTableSource`.
169
+ */
170
+ source?: DXTableSource<TItem>;
134
171
  /** Table field definitions */
135
172
  fields: TableField[];
136
173
  /** Sort configuration (v-model support) */
@@ -198,14 +235,44 @@ export interface Props<TItem = any> {
198
235
  * data-heavy admin index pages that read as busy inside a card.
199
236
  */
200
237
  card?: boolean;
201
- /** Form field definitions for edit modal (if provided, enables edit on row click) */
202
- editFields?: any[];
238
+ /**
239
+ * Form field definitions for edit modal (if provided, enables edit on row
240
+ * click). `import type` is erased at compile time, so this creates no
241
+ * runtime import cycle (#131).
242
+ */
243
+ editFields?: FieldDefinition[];
203
244
  /** Tab definitions for organizing edit modal content */
204
245
  editTabs?: EditTab[];
205
246
  /** Edit modal title (can be function for dynamic titles) */
206
247
  editModalTitle?: string | ((item: any) => string);
207
248
  /** Edit modal size */
208
249
  editModalSize?: 'sm' | 'md' | 'lg' | 'xl';
250
+ /**
251
+ * Field layout for the edit/create modal's form, forwarded to its `DXForm`
252
+ * ("vertical" = label above input, "horizontal" = label left). Defaults to
253
+ * **"horizontal"** to match the Omni Tend form convention (a raw modal form
254
+ * previously fell back to DXForm's vertical default, which looked out of
255
+ * place next to horizontal page forms). Pass `"vertical"` to opt out.
256
+ */
257
+ editLayout?: 'vertical' | 'horizontal';
258
+ /**
259
+ * Label column width for the edit modal's horizontal layout, forwarded to
260
+ * `DXForm`'s `labelCols` (a single width or a per-breakpoint object). Only
261
+ * meaningful when `editLayout` is "horizontal".
262
+ */
263
+ editLabelCols?: LabelCols;
264
+ /**
265
+ * Wrap the edit/create modal's form in a bordered card. Off by default (the
266
+ * modal body already provides a boundary); opt in for a more contained,
267
+ * panelled look around a tabbed edit form.
268
+ */
269
+ editCard?: boolean;
270
+ /** Override the modal's Save button label (default: "Save {item}"). */
271
+ saveText?: string;
272
+ /** Override the modal's Create button label (default: "Create {item}"). */
273
+ createText?: string;
274
+ /** Override the modal's Delete button label (default: "Delete {item}"). */
275
+ deleteText?: string;
209
276
  /** API endpoint pattern for updates (e.g., "/api/products/:id") */
210
277
  editUrl?: string;
211
278
  /**
@@ -1,4 +1,5 @@
1
1
  import type { EditTab } from "./DXTable.vue";
2
+ import type { LabelCols } from "../../types";
2
3
  interface Props {
3
4
  /** Whether the modal is open (v-model:show). */
4
5
  show: boolean;
@@ -26,6 +27,20 @@ interface Props {
26
27
  pendingAction: 'save' | 'delete' | null;
27
28
  /** Delete endpoint — gates the Delete button. */
28
29
  deleteUrl?: string;
30
+ /** Field layout forwarded to the modal's DXForm (defaults handled upstream). */
31
+ layout?: 'vertical' | 'horizontal';
32
+ /** Label column width forwarded to DXForm (horizontal layout). */
33
+ labelCols?: LabelCols;
34
+ /** Wrap the modal form in a card (opt-in — off by default). */
35
+ card?: boolean;
36
+ /** Singular item noun for the default button labels (e.g. "customer"). */
37
+ itemName?: string;
38
+ /** Override the Save button label (edit mode). */
39
+ saveText?: string;
40
+ /** Override the Create button label (create mode). */
41
+ createText?: string;
42
+ /** Override the Delete button label. */
43
+ deleteText?: string;
29
44
  }
30
45
  declare var __VLS_21: `edit-value(${string})`, __VLS_22: {
31
46
  item: any;
@@ -59,16 +74,16 @@ type __VLS_Slots = {} & {
59
74
  [K in NonNullable<typeof __VLS_37>]?: (props: typeof __VLS_38) => any;
60
75
  };
61
76
  declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
77
+ cancel: () => any;
62
78
  delete: () => any;
63
79
  "update:activeTab": (value: number) => any;
64
80
  save: () => any;
65
- cancel: () => any;
66
81
  "update:show": (value: boolean) => any;
67
82
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
83
+ onCancel?: (() => any) | undefined;
68
84
  onDelete?: (() => any) | undefined;
69
85
  "onUpdate:activeTab"?: ((value: number) => any) | undefined;
70
86
  onSave?: (() => any) | undefined;
71
- onCancel?: (() => any) | undefined;
72
87
  "onUpdate:show"?: ((value: boolean) => any) | undefined;
73
88
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
74
89
  declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
@@ -22,11 +22,11 @@ type __VLS_Slots = {} & {
22
22
  default?: (props: typeof __VLS_1) => any;
23
23
  };
24
24
  declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
25
+ initial: string;
25
26
  user: {
26
27
  name: string;
27
28
  [key: string]: any;
28
29
  } | null;
29
- initial: string;
30
30
  badge: boolean;
31
31
  badgeVariant: ColorVariant;
32
32
  badgeLabel: string;
@@ -0,0 +1,20 @@
1
+ import { type ComputedRef, type Ref } from "vue";
2
+ import type { FieldDefinition, FieldOption } from "../types";
3
+ /**
4
+ * Async option loading for a `DXField`: runs `field.optionsLoader` on mount and
5
+ * (when `field.reloadOptionsOnChange` is set) whenever the model changes,
6
+ * exposing the loaded options. A monotonic request token guards against
7
+ * out-of-order responses clobbering newer ones; loader failures are swallowed
8
+ * so the last good options (or the static `field.options` fallback) stay put.
9
+ *
10
+ * Extracted verbatim from DXField's inline logic (#135) — behaviour unchanged.
11
+ * `getField` is an accessor (props aren't destructurable without losing
12
+ * reactivity); `effectiveModel` is the model passed to the loader.
13
+ */
14
+ export interface UseAsyncOptionsReturn {
15
+ /** Options returned by the most recent successful load, or null if none yet. */
16
+ loadedOptions: Ref<FieldOption[] | null>;
17
+ /** Trigger a load (no-op when the field has no `optionsLoader`). */
18
+ loadOptions: () => Promise<void>;
19
+ }
20
+ export declare function useAsyncOptions(getField: () => FieldDefinition, effectiveModel: ComputedRef<any> | Ref<any>): UseAsyncOptionsReturn;
@@ -1,4 +1,5 @@
1
1
  import { type Ref } from "vue";
2
+ import type { FieldDefinition } from "../types";
2
3
  /**
3
4
  * The subset of `DXTable`'s props the resource editor reads. Declared
4
5
  * structurally (not imported from DXTable.vue) so the composable stays a
@@ -7,7 +8,7 @@ import { type Ref } from "vue";
7
8
  */
8
9
  export interface ResourceEditorProps<T = any> {
9
10
  /** Field definitions for the edit/create modal (enables edit-on-row-click). */
10
- editFields?: any[];
11
+ editFields?: FieldDefinition[];
11
12
  /** Tab definitions — only their `key` is read here (DXForm consumes the rest). */
12
13
  editTabs?: Array<{
13
14
  key: string;