@omnitend/dashboard-for-laravel 0.45.0 → 0.47.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 (51) hide show
  1. package/dist/assets/IBMPlexSans-Bold-Latin1-914f1400.woff2 +0 -0
  2. package/dist/assets/IBMPlexSans-Medium-Latin1-b5610af0.woff2 +0 -0
  3. package/dist/assets/IBMPlexSans-Regular-Latin1-b5ad7bd3.woff2 +0 -0
  4. package/dist/assets/IBMPlexSans-SemiBold-Latin1-fff0ab3a.woff2 +0 -0
  5. package/dist/components/base/DFormFile.vue.d.ts +17 -0
  6. package/dist/components/base/DFormValidFeedback.vue.d.ts +12 -0
  7. package/dist/components/extended/DXDashboard.vue.d.ts +95 -111
  8. package/dist/components/extended/DXDashboardNavbar.vue.d.ts +2 -36
  9. package/dist/components/extended/DXDashboardSidebar.vue.d.ts +60 -79
  10. package/dist/components/extended/DXField.vue.d.ts +16 -0
  11. package/dist/components/extended/DXTable.vue.d.ts +10 -1
  12. package/dist/components/extended/DXTableEditorModal.vue.d.ts +13 -3
  13. package/dist/dashboard-for-laravel.js +11767 -11479
  14. package/dist/dashboard-for-laravel.js.map +1 -1
  15. package/dist/dashboard-for-laravel.umd.cjs +7 -7
  16. package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
  17. package/dist/index.d.ts +4 -2
  18. package/dist/style.css +2 -2
  19. package/dist/types/index.d.ts +60 -0
  20. package/dist/types/navigation.d.ts +153 -3
  21. package/dist/utils/formErrorTargets.d.ts +6 -2
  22. package/dist/utils/formSchema.d.ts +16 -0
  23. package/dist/utils/statCardFit.d.ts +19 -0
  24. package/docs/public/api-reference.json +171 -9
  25. package/docs/public/docs-map.md +4 -2
  26. package/docs/public/llms.txt +4 -2
  27. package/package.json +3 -2
  28. package/resources/css/theme.scss +339 -4
  29. package/resources/fonts/ibm-plex-sans/IBMPlexSans-Bold-Latin1.woff2 +0 -0
  30. package/resources/fonts/ibm-plex-sans/IBMPlexSans-Medium-Latin1.woff2 +0 -0
  31. package/resources/fonts/ibm-plex-sans/IBMPlexSans-Regular-Latin1.woff2 +0 -0
  32. package/resources/fonts/ibm-plex-sans/IBMPlexSans-SemiBold-Latin1.woff2 +0 -0
  33. package/resources/fonts/ibm-plex-sans/OFL.txt +93 -0
  34. package/resources/fonts/ibm-plex-sans/SOURCE.txt +18 -0
  35. package/resources/js/components/base/DFormFile.vue +103 -0
  36. package/resources/js/components/base/DFormValidFeedback.vue +16 -0
  37. package/resources/js/components/extended/DXDashboard.vue +41 -18
  38. package/resources/js/components/extended/DXDashboardNavbar.vue +9 -1
  39. package/resources/js/components/extended/DXDashboardSidebar.vue +25 -3
  40. package/resources/js/components/extended/DXField.vue +86 -23
  41. package/resources/js/components/extended/DXFormField.vue +3 -1
  42. package/resources/js/components/extended/DXStatCard.vue +154 -11
  43. package/resources/js/components/extended/DXTable.vue +62 -6
  44. package/resources/js/components/extended/DXTableEditorModal.vue +35 -2
  45. package/resources/js/composables/useResourceEditor.ts +64 -26
  46. package/resources/js/index.ts +11 -0
  47. package/resources/js/types/index.ts +64 -0
  48. package/resources/js/types/navigation.ts +175 -3
  49. package/resources/js/utils/formErrorTargets.ts +28 -2
  50. package/resources/js/utils/formSchema.ts +27 -0
  51. package/resources/js/utils/statCardFit.ts +210 -0
@@ -215,6 +215,19 @@ export interface FieldDefinition {
215
215
  * `FormFieldDefinition` re-declares this as required for inference.)
216
216
  */
217
217
  default?: any;
218
+ /**
219
+ * For a field whose value is a list of rows (a `repeater`, or a span
220
+ * field that renders its own rows and owns `key.N.*` error keys): the
221
+ * row's own name, called with the row (`model[key][index]`, or `{}` when
222
+ * the model has no such row) and its 0-based index. When it returns a
223
+ * non-empty string, the error summary lists that row's errors under it
224
+ * alone ("Chaucer Ale (Pint): Enter a price.") instead of
225
+ * "<sub-field label> (line N)". Returning `undefined`, `null` or `""`
226
+ * (a row with no name yet), or throwing, keeps the line-number label.
227
+ * Only labels: which field owns the error, and what a click on the
228
+ * summary row focuses, are unchanged.
229
+ */
230
+ rowLabel?: (row: Record<string, any>, index: number) => string | null | undefined;
218
231
  /** Label for a repeater's "add row" button (default: "Add"). */
219
232
  addLabel?: string;
220
233
  /** Minimum / maximum number of repeater rows. */
@@ -295,6 +308,10 @@ export interface FieldDefinition {
295
308
  * every `editFields` key, so those decorative fields are POSTed alongside
296
309
  * the real ones (an empty string, an empty array) purely because they were
297
310
  * declared.
311
+ *
312
+ * Applies per KEY (#228): DXTable drops a key only when no field with that
313
+ * key is both submitting and visible, so a `submit: false` display twin
314
+ * does not strip the value of a visible editable field sharing its key.
298
315
  */
299
316
  submit?: boolean;
300
317
  /**
@@ -444,6 +461,7 @@ export interface ComponentFieldDef extends BaseFieldDef {
444
461
  export interface RepeaterFieldDef extends BaseFieldDef {
445
462
  type: "repeater";
446
463
  fields?: FieldDef[];
464
+ rowLabel?: (row: Record<string, any>, index: number) => string | null | undefined;
447
465
  addLabel?: string;
448
466
  minItems?: number;
449
467
  maxItems?: number;
@@ -488,6 +506,48 @@ export interface FormTab {
488
506
  /** Lazily mount tab content until first activated */
489
507
  lazy?: boolean;
490
508
  }
509
+ /**
510
+ * Slot props of DXField's `password-actions` slot (DXForm:
511
+ * `password-actions(<key>)`): content placed beside a password input, inside
512
+ * its input group after the reveal (eye) toggle, such as a "Generate password"
513
+ * button. `setRevealed` drives the same state the eye toggles.
514
+ *
515
+ * ```vue
516
+ * <template #password-actions(password)="{ update, setRevealed, disabled }">
517
+ * <DButton variant="outline-secondary" :disabled="disabled"
518
+ * @click="update(generatePassword()); setRevealed(true)">Generate</DButton>
519
+ * </template>
520
+ * ```
521
+ */
522
+ export interface PasswordActionsSlotProps {
523
+ /** The field definition being rendered. */
524
+ field: FieldDefinition;
525
+ /** The model passed to field predicates (defaults to the live form data). */
526
+ model: any;
527
+ /** The current field value. */
528
+ value: any;
529
+ /** Write a new value (also marks the field touched and clears its error). */
530
+ update: (value: any) => void;
531
+ /** Whether the password is currently shown as plain text. */
532
+ revealed: boolean;
533
+ /**
534
+ * Show (`true`) or mask (`false`) the password, exactly as the eye does.
535
+ * A no-op on a `revealable: false` field, which never unmasks.
536
+ */
537
+ setRevealed: (revealed: boolean) => void;
538
+ /** Whether the field is disabled or read-only. */
539
+ disabled: boolean;
540
+ }
541
+ /**
542
+ * Slot props of DXTable's `edit-password-actions(<key>)` slot, the edit/create
543
+ * modal's form of {@link PasswordActionsSlotProps}. `item` is the row being
544
+ * edited, `null` in create mode. (`model` is not passed, as with the modal's
545
+ * other field slots.)
546
+ */
547
+ export interface EditPasswordActionsSlotProps extends Omit<PasswordActionsSlotProps, "model"> {
548
+ /** The row being edited; `null` in create mode. */
549
+ item: any;
550
+ }
491
551
  /**
492
552
  * The theme's extra colour variant, `pending`: waiting, and the next move is
493
553
  * not yours ("awaiting payment", "sent to printer, not yet confirmed").
@@ -7,7 +7,13 @@ export interface NavigationItem {
7
7
  active?: boolean;
8
8
  visible?: boolean;
9
9
  }
10
- export interface NavigationGroup {
10
+ /**
11
+ * A group of sidebar links. `TItem` is the app's own item type, for menus whose
12
+ * items carry extra keys (a permission, a route name): DXDashboard and
13
+ * DXDashboardSidebar infer it from the `navigation` prop, so the `link` slot's
14
+ * `item` has those keys too. Defaults to `NavigationItem`.
15
+ */
16
+ export interface NavigationGroup<TItem extends NavigationItem = NavigationItem> {
11
17
  label?: string;
12
18
  /**
13
19
  * Stable identifier for the group's collapsible open/closed state. Defaults
@@ -16,7 +22,7 @@ export interface NavigationGroup {
16
22
  * state attached to the right group.
17
23
  */
18
24
  key?: string;
19
- items: NavigationItem[];
25
+ items: TItem[];
20
26
  /**
21
27
  * Per-group override for the sidebar's `collapsibleGroups` behaviour.
22
28
  * Set to `false` to keep a group permanently expanded (no toggle header)
@@ -27,7 +33,23 @@ export interface NavigationGroup {
27
33
  collapsed?: boolean;
28
34
  visible?: boolean;
29
35
  }
30
- export type Navigation = NavigationGroup[];
36
+ /** The sidebar's navigation: its groups, in order. See `NavigationGroup` for `TItem`. */
37
+ export type Navigation<TItem extends NavigationItem = NavigationItem> = NavigationGroup<TItem>[];
38
+ /**
39
+ * The item type of a navigation, as the `link` slot's `item` receives it:
40
+ * `NavigationItemOf<Navigation<AppItem>>` is `AppItem`. An `any` navigation
41
+ * (untyped page props) gives `any`, and an empty `[]` gives `NavigationItem`.
42
+ *
43
+ * DXDashboard and DXDashboardSidebar are generic over the whole navigation
44
+ * (`TNavigation`) and derive the item from it, rather than generic over the
45
+ * item: TypeScript infers `any` for a type parameter that IS the prop's type,
46
+ * but not for one nested inside it (`{ items: TItem[] }[]`), where an `any`
47
+ * navigation would have fallen back to `NavigationItem` and rejected the app's
48
+ * extra keys.
49
+ */
50
+ export type NavigationItemOf<TNavigation extends Navigation> = [
51
+ TNavigation[number]["items"][number]
52
+ ] extends [never] ? NavigationItem : TNavigation[number]["items"][number];
31
53
  /**
32
54
  * Horizontal alignment of the navbar search slot content within its region:
33
55
  * `"start"` = flush left (after the title from `md` up), `"center"` = centred.
@@ -49,3 +71,131 @@ export type SidebarVariant = "light" | "dark";
49
71
  * Shared by DXDashboard (which forwards it) and DXDashboardNavbar.
50
72
  */
51
73
  export type NavbarActionsOnMobile = "wrap" | "hide";
74
+ /**
75
+ * The signed-in user DXDashboardNavbar (and DXDashboard, which forwards it)
76
+ * shows in the avatar dropdown. Extra keys are allowed and reach the
77
+ * user-menu slots.
78
+ */
79
+ export interface DashboardUser {
80
+ name: string;
81
+ email: string;
82
+ [key: string]: any;
83
+ }
84
+ /** A slot that receives no props. */
85
+ type NoSlotProps = Record<never, never>;
86
+ /** Slots of DXDashboardNavbar, with their slot props. All are optional. */
87
+ export interface DashboardNavbarSlots {
88
+ /** Custom hamburger/menu icon. Defaults to a three-line SVG. */
89
+ "menu-icon"?(props: NoSlotProps): any;
90
+ /**
91
+ * Search input or component. Fills the middle of the bar at every width,
92
+ * aligned per `searchAlign`. The region is a size container named
93
+ * `dx-navbar-search`; a `<kbd>` hint inside it is hidden when it is
94
+ * narrower than 16rem.
95
+ */
96
+ "search"?(props: NoSlotProps): any;
97
+ /**
98
+ * Page-level primary actions (e.g. a Create button). Right-aligned next to
99
+ * the user menu from `md` up; below, wraps to its own full-width row or is
100
+ * hidden entirely per `actionsOnMobile`.
101
+ */
102
+ "actions"?(props: {
103
+ /** The current page title, for context. */
104
+ pageTitle: string;
105
+ }): any;
106
+ /** Replaces the entire user menu (the default avatar dropdown). */
107
+ "user-menu"?(props: {
108
+ /** The signed-in user; `null` for a guest. */
109
+ user: DashboardUser | null;
110
+ }): any;
111
+ /**
112
+ * Custom user avatar/icon in the dropdown trigger. To decorate the default
113
+ * avatar (e.g. add a notification dot) rather than replace it, render
114
+ * `DXUserAvatar`. Only rendered for a signed-in user.
115
+ */
116
+ "user-icon"?(props: {
117
+ /** The first letter of the user's name. */
118
+ initial: string;
119
+ /** The signed-in user. */
120
+ user: DashboardUser;
121
+ }): any;
122
+ /** Items for the default user dropdown menu. Only rendered for a signed-in user. */
123
+ "user-menu-items"?(props: {
124
+ /** The signed-in user. */
125
+ user: DashboardUser;
126
+ }): any;
127
+ }
128
+ /**
129
+ * Slots of DXDashboardSidebar, with their slot props. All are optional.
130
+ * `TItem` is the navigation's item type (see `NavigationGroup`).
131
+ */
132
+ export interface DashboardSidebarSlots<TItem extends NavigationItem = NavigationItem> {
133
+ /**
134
+ * Brand/logo area in the sidebar header. Defaults to the title's initial
135
+ * plus the full title (hidden when collapsed).
136
+ */
137
+ "brand"?(props: {
138
+ /** Whether the sidebar rail is collapsed to icons only. */
139
+ collapsed: boolean;
140
+ /** The sidebar title text. */
141
+ title: string;
142
+ }): any;
143
+ /**
144
+ * Renders a single navigation item link. Defaults to an anchor with
145
+ * optional icon, label, and badge.
146
+ */
147
+ "link"?(props: {
148
+ /**
149
+ * The navigation item (label, url, icon, badge, badgeColor), typed as the
150
+ * app's own item type when its items carry extra keys.
151
+ */
152
+ item: TItem;
153
+ /** Whether this item matches the current route. */
154
+ isActive: boolean;
155
+ /** Whether the sidebar rail is collapsed to icons only. */
156
+ collapsed: boolean;
157
+ /** Whether the item's group is currently expanded. */
158
+ isExpanded: boolean;
159
+ }): any;
160
+ /**
161
+ * Utility/secondary links pinned to the bottom of the sidebar (help,
162
+ * changelog, sign-out, …), below the nav groups.
163
+ */
164
+ "footer"?(props: {
165
+ /** Whether the sidebar rail is collapsed to icons only. */
166
+ collapsed: boolean;
167
+ }): any;
168
+ }
169
+ /**
170
+ * The two bindings DXDashboard adds to every forwarded `sidebar-*` and
171
+ * `navbar-*` slot. They are bound after the child's own slot props, so they
172
+ * win a name clash.
173
+ */
174
+ export interface DashboardSlotExtras {
175
+ /** Shows/hides the sidebar. */
176
+ toggleSidebar: () => void;
177
+ /** Whether the sidebar is currently hidden. */
178
+ sidebarHidden: boolean;
179
+ }
180
+ /** The props a (possibly optional) slot function receives. */
181
+ type SlotPropsOf<Slot> = NonNullable<Slot> extends (props: infer Props) => any ? Props : never;
182
+ /**
183
+ * A child component's slots renamed with `Prefix` and given the dashboard's
184
+ * extra bindings: `{ brand(props: P) }` becomes
185
+ * `{ "sidebar-brand"(props: P & DashboardSlotExtras) }`. Derived from the
186
+ * child's slot types, so a slot added to the child is typed here for free.
187
+ */
188
+ export type PrefixedDashboardSlots<Slots, Prefix extends string> = {
189
+ [Name in keyof Slots as `${Prefix}${Name & string}`]?: (props: Omit<SlotPropsOf<Slots[Name]>, keyof DashboardSlotExtras> & DashboardSlotExtras) => any;
190
+ };
191
+ /**
192
+ * Slots of DXDashboard: the page content (`default`), every
193
+ * DXDashboardSidebar slot as `sidebar-<name>` and every DXDashboardNavbar
194
+ * slot as `navbar-<name>`. An unprefixed name (`#search`) is not forwarded.
195
+ * `TItem` is the navigation's item type (see `NavigationGroup`).
196
+ */
197
+ export type DashboardSlots<TItem extends NavigationItem = NavigationItem> = {
198
+ /** The main page content. */
199
+ default?(props: NoSlotProps): any;
200
+ } & PrefixedDashboardSlots<DashboardSidebarSlots<TItem>, "sidebar-"> & PrefixedDashboardSlots<DashboardNavbarSlots, "navbar-">;
201
+ export {};
@@ -25,7 +25,10 @@ export interface ErrorTarget {
25
25
  fieldKey: string | null;
26
26
  /** The tab holding the owning field, or `null` (flat form, or unowned). */
27
27
  tabKey: string | null;
28
- /** A readable name for the key: "Price (line 1)", "Delivery date". */
28
+ /**
29
+ * A readable name for the key: "Price (line 1)", "Delivery date", or a
30
+ * row's own name from the field's `rowLabel`.
31
+ */
29
32
  label: string;
30
33
  }
31
34
  export interface ResolveErrorTargetsOptions {
@@ -75,7 +78,8 @@ export declare function humaniseErrorKey(key: string): string;
75
78
  *
76
79
  * Labels: the owning field's label; for `field.N.sub` the sub-field's label
77
80
  * (when the field defines `fields` and one has that key) or the field's own,
78
- * plus "(line N+1)"; for any other nested key (a media map's
81
+ * plus "(line N+1)" — unless the field's `rowLabel` names that row, when
82
+ * the row's name is the whole label; for any other nested key (a media map's
79
83
  * `image_media.<uuid>`) the field's label. An unowned key is humanised.
80
84
  *
81
85
  * Display lines: "Label: message", except that the label is left off when
@@ -57,3 +57,19 @@ export declare function isFieldVisible(field: {
57
57
  export declare function isSubmittableField(field: {
58
58
  submit?: boolean;
59
59
  }): boolean;
60
+ /**
61
+ * The payload keys to drop on submit: every field key for which NO field with
62
+ * that key is both submittable (`submit !== false`) and visible (#228).
63
+ *
64
+ * Decided per KEY, across all the fields that share it, never per field. Two
65
+ * fields may share a key: an editable select plus a read-only display twin
66
+ * (`submit: false`) that shows instead for system-created rows. Stripping a
67
+ * key because ONE of its fields is presentational or hidden removed it from
68
+ * every save, including while the select was the visible field in use. A key
69
+ * whose fields are all presentational (#110) or all hidden (#117) is still
70
+ * dropped.
71
+ */
72
+ export declare function nonSubmittedFieldKeys<TField extends {
73
+ key: string;
74
+ submit?: boolean;
75
+ }>(fields: readonly TField[], isVisible: (field: TField) => boolean): Set<string>;
@@ -0,0 +1,19 @@
1
+ /** One card's fit: its elements, and the box width it was last fitted to. */
2
+ export interface FitTarget {
3
+ box: HTMLElement;
4
+ value: HTMLElement;
5
+ /** Only numeric values are fitted; text wraps instead. */
6
+ isNumeric: () => boolean;
7
+ /** -1 when the next resize entry must refit whatever its width. */
8
+ fittedBoxWidth: number;
9
+ }
10
+ /**
11
+ * Queue a fit. "microtask" runs before the next paint, for mounts, content
12
+ * changes, reactivation and font loads. "frame" is for ResizeObserver
13
+ * callbacks: a fit inside the observer's delivery (microtasks run there
14
+ * too) changes the box's HEIGHT, which the browser reports as a
15
+ * "ResizeObserver loop" error, so a resize refits in the next frame.
16
+ */
17
+ export declare function queueFit(target: FitTarget, timing: "microtask" | "frame"): void;
18
+ export declare function registerTarget(target: FitTarget): void;
19
+ export declare function unregisterTarget(target: FitTarget): void;
@@ -1,8 +1,8 @@
1
1
  {
2
- "generated": "2026-10-11T09:08:08.777Z",
2
+ "generated": "2026-10-21T10:08:54.451Z",
3
3
  "package": {
4
4
  "name": "@omnitend/dashboard-for-laravel",
5
- "version": "0.45.0"
5
+ "version": "0.47.0"
6
6
  },
7
7
  "components": {
8
8
  "base": [
@@ -556,6 +556,27 @@
556
556
  ],
557
557
  "methods": []
558
558
  },
559
+ {
560
+ "name": "DFormFile",
561
+ "category": "base",
562
+ "filePath": "resources/js/components/base/DFormFile.vue",
563
+ "description": "Type-safe wrapper around Bootstrap Vue Next BFormFile component. File picker with a browse button, file-name display and drag-and-drop zone. `v-model` is a `File` (single), `File[]` (`multiple`/`directory`) or `null`; setting it to `null` (or `[]`) also clears the native input. A disabled control (the prop, or a disabled fieldset) ignores dropped files. Slots: `label`, `placeholder`, `file-name` (`{ files, names }`) and `drop-placeholder`. Exposes BFormFile's `focus`, `blur` and `reset`.",
564
+ "props": [],
565
+ "events": [],
566
+ "slots": [
567
+ {
568
+ "name": "name",
569
+ "description": "",
570
+ "bindings": [
571
+ {
572
+ "name": "name",
573
+ "title": "binding"
574
+ }
575
+ ]
576
+ }
577
+ ],
578
+ "methods": []
579
+ },
559
580
  {
560
581
  "name": "DFormGroup",
561
582
  "category": "base",
@@ -798,6 +819,27 @@
798
819
  "slots": [],
799
820
  "methods": []
800
821
  },
822
+ {
823
+ "name": "DFormValidFeedback",
824
+ "category": "base",
825
+ "filePath": "resources/js/components/base/DFormValidFeedback.vue",
826
+ "description": "",
827
+ "props": [],
828
+ "events": [],
829
+ "slots": [
830
+ {
831
+ "name": "name",
832
+ "description": "",
833
+ "bindings": [
834
+ {
835
+ "name": "name",
836
+ "title": "binding"
837
+ }
838
+ ]
839
+ }
840
+ ],
841
+ "methods": []
842
+ },
801
843
  {
802
844
  "name": "DImage",
803
845
  "category": "base",
@@ -1564,7 +1606,7 @@
1564
1606
  "props": [
1565
1607
  {
1566
1608
  "name": "navigation",
1567
- "type": "Navigation",
1609
+ "type": "TNavigation",
1568
1610
  "required": true,
1569
1611
  "description": "Navigation structure for sidebar"
1570
1612
  },
@@ -1856,7 +1898,7 @@
1856
1898
  "props": [
1857
1899
  {
1858
1900
  "name": "navigation",
1859
- "type": "Navigation",
1901
+ "type": "TNavigation",
1860
1902
  "required": true,
1861
1903
  "description": "Grouped navigation to render: an array of groups, each with a label and items."
1862
1904
  },
@@ -2076,7 +2118,7 @@
2076
2118
  "name": "DXField",
2077
2119
  "category": "extended",
2078
2120
  "filePath": "resources/js/components/extended/DXField.vue",
2079
- "description": "Renders a single `FieldDefinition` of any type (text, select, autocomplete, checkbox, switch, repeater, currency, percentage, file/image, component, etc.) with its label, validation error, hint and help. Used by `DXForm` and `DXTable`'s edit modal; exposes `value`, `span`, `info`, `info-popover`, `hint` and `repeater-row` slots for per-field customisation. Structure (#135): a thin DISPATCHER. The shared chrome (label + validation feedback + hint + help + info) lives in `DXFieldShell`; the numeric controls (currency/percentage/number) in `DXNumericField`; the choice controls (select/searchable/radio/checkbox-group) in `DXChoiceField`; and the async option loading in the `useAsyncOptions` composable. This file decides which control to render inside the shell by `field.type`. None of those pieces are exported — they exist only to keep this component factored.",
2121
+ "description": "Renders a single `FieldDefinition` of any type (text, select, autocomplete, checkbox, switch, repeater, currency, percentage, file/image, component, etc.) with its label, validation error, hint and help. Used by `DXForm` and `DXTable`'s edit modal; exposes `value`, `span`, `info`, `info-popover`, `hint`, `repeater-row` and `password-actions` slots for per-field customisation. Structure (#135): a thin DISPATCHER. The shared chrome (label + validation feedback + hint + help + info) lives in `DXFieldShell`; the numeric controls (currency/percentage/number) in `DXNumericField`; the choice controls (select/searchable/radio/checkbox-group) in `DXChoiceField`; and the async option loading in the `useAsyncOptions` composable. This file decides which control to render inside the shell by `field.type`. None of those pieces are exported — they exist only to keep this component factored.",
2080
2122
  "props": [
2081
2123
  {
2082
2124
  "name": "field",
@@ -2275,6 +2317,64 @@
2275
2317
  "name": "repeater-row",
2276
2318
  "description": "Custom layout for a single repeater row, forwarded to `DXRepeater`'s `row` slot with its row props (row index, item, remove handler, etc.).",
2277
2319
  "bindings": []
2320
+ },
2321
+ {
2322
+ "name": "password-actions",
2323
+ "description": "Extra controls beside a password input, after its input group (the input and the reveal (eye) toggle), e.g. a \"Generate password\" button. They sit on the input's row while it keeps `--dx-password-input-min-width`, and wrap below it when the row is too narrow. Use an ordinary button (a `secondary` `DButton` matches the form's other buttons). Not rendered on a `plaintext` field.",
2324
+ "bindings": [
2325
+ {
2326
+ "title": "binding",
2327
+ "type": {
2328
+ "name": "FieldDefinition"
2329
+ },
2330
+ "name": "field",
2331
+ "description": "The field definition being rendered."
2332
+ },
2333
+ {
2334
+ "title": "binding",
2335
+ "type": {
2336
+ "name": "any"
2337
+ },
2338
+ "name": "model",
2339
+ "description": "The model passed to field predicates (defaults to the live form data)."
2340
+ },
2341
+ {
2342
+ "title": "binding",
2343
+ "type": {
2344
+ "name": "any"
2345
+ },
2346
+ "name": "value",
2347
+ "description": "The current field value."
2348
+ },
2349
+ {
2350
+ "title": "binding",
2351
+ "type": {
2352
+ "name": "(value: any) => void"
2353
+ },
2354
+ "name": "update",
2355
+ "description": "Setter that writes the value back and clears the field's validation error."
2356
+ },
2357
+ {
2358
+ "title": "binding",
2359
+ "type": {
2360
+ "name": "boolean"
2361
+ },
2362
+ "name": "revealed",
2363
+ "description": "Whether the password is currently shown as plain text."
2364
+ },
2365
+ {
2366
+ "name": "set-revealed",
2367
+ "title": "binding"
2368
+ },
2369
+ {
2370
+ "title": "binding",
2371
+ "type": {
2372
+ "name": "boolean"
2373
+ },
2374
+ "name": "disabled",
2375
+ "description": "Whether the field is disabled or read-only, so actions that change the value can disable themselves."
2376
+ }
2377
+ ]
2278
2378
  }
2279
2379
  ],
2280
2380
  "methods": []
@@ -2754,7 +2854,7 @@
2754
2854
  "name": "DXFormField",
2755
2855
  "category": "extended",
2756
2856
  "filePath": "resources/js/components/extended/DXFormField.vue",
2757
- "description": "DXFormField — internal per-field renderer for DXForm. Owns the single per-field render block that DXForm's tabbed and flat layouts both need: the `field(<key>)` full-replacement slot, the `field-before(<key>)`/`field-after(<key>)` wrapper slots, and the `<DXField>` element with its `value`/`span`/`info`/`hint`/`repeater-row` slot forwarding. Extracted so those per-field props/slots are wired in ONE place — before this, DXForm carried two near-identical copies (tabbed + flat) and a new per-field prop had to be added to both, which was easy to miss (see #78/#83). DXForm forwards all of its slots into each instance; this component only reads the ones matching its field's key. Internal: not exported from the package index — consumers use DXForm.",
2857
+ "description": "DXFormField — internal per-field renderer for DXForm. Owns the single per-field render block that DXForm's tabbed and flat layouts both need: the `field(<key>)` full-replacement slot, the `field-before(<key>)`/`field-after(<key>)` wrapper slots, and the `<DXField>` element with its `value`/`span`/`info`/`hint`/`repeater-row`/ `switch-list-item`/`password-actions` slot forwarding. Extracted so those per-field props/slots are wired in ONE place — before this, DXForm carried two near-identical copies (tabbed + flat) and a new per-field prop had to be added to both, which was easy to miss (see #78/#83). DXForm forwards all of its slots into each instance; this component only reads the ones matching its field's key. Internal: not exported from the package index — consumers use DXForm.",
2758
2858
  "props": [
2759
2859
  {
2760
2860
  "name": "field",
@@ -4084,7 +4184,7 @@
4084
4184
  "name": "DXTableEditorModal",
4085
4185
  "category": "extended",
4086
4186
  "filePath": "resources/js/components/extended/DXTableEditorModal.vue",
4087
- "description": "Internal edit/create modal for `DXTable` (#129). Renders the `DModal` + `DXForm` and maps DXTable's `edit-value`/`edit-span`/`tab-*` slots onto DXForm's `value`/`span`/`tab-*` slots, providing the row context and a `close` handle. Extracted so `DXTable` is a thin façade over the table render, the pagination, the editor logic (`useResourceEditor`) and this modal — rather than owning all four. The edit-modal slots reach here forwarded from DXTable (consumer → DXTable → here → DXForm). This component computes which keyed slots the consumer actually provided from its OWN `$slots`, so the slot-plumbing lives entirely with the modal, not the composable.",
4187
+ "description": "Internal edit/create modal for `DXTable` (#129). Renders the `DModal` + `DXForm` and maps DXTable's `edit-value`/`edit-span`/`edit-password-actions`/ `tab-*` slots onto DXForm's `value`/`span`/`password-actions`/`tab-*` slots, providing the row context and a `close` handle. Extracted so `DXTable` is a thin façade over the table render, the pagination, the editor logic (`useResourceEditor`) and this modal — rather than owning all four. The edit-modal slots reach here forwarded from DXTable (consumer → DXTable → here → DXForm). This component computes which keyed slots the consumer actually provided from its OWN `$slots`, so the slot-plumbing lives entirely with the modal, not the composable.",
4088
4188
  "props": [
4089
4189
  {
4090
4190
  "name": "show",
@@ -4331,6 +4431,68 @@
4331
4431
  }
4332
4432
  ]
4333
4433
  },
4434
+ {
4435
+ "name": "`edit-password-actions(${key})`",
4436
+ "description": "Extra controls beside password field `<key>`'s input in the edit/create modal, inside its input group after the reveal (eye) toggle — e.g. a \"Generate password\" button. Name it `edit-password-actions(<fieldKey>)`.",
4437
+ "bindings": [
4438
+ {
4439
+ "name": "name",
4440
+ "title": "binding"
4441
+ },
4442
+ {
4443
+ "title": "binding",
4444
+ "type": {
4445
+ "name": "object"
4446
+ },
4447
+ "name": "item",
4448
+ "description": "The row being edited (null in create mode)."
4449
+ },
4450
+ {
4451
+ "title": "binding",
4452
+ "type": {
4453
+ "name": "any"
4454
+ },
4455
+ "name": "value",
4456
+ "description": "The current field value."
4457
+ },
4458
+ {
4459
+ "title": "binding",
4460
+ "type": {
4461
+ "name": "Function"
4462
+ },
4463
+ "name": "update",
4464
+ "description": "Call with a new value to update the field."
4465
+ },
4466
+ {
4467
+ "title": "binding",
4468
+ "type": {
4469
+ "name": "boolean"
4470
+ },
4471
+ "name": "revealed",
4472
+ "description": "Whether the password is currently shown as plain text."
4473
+ },
4474
+ {
4475
+ "name": "set-revealed",
4476
+ "title": "binding"
4477
+ },
4478
+ {
4479
+ "title": "binding",
4480
+ "type": {
4481
+ "name": "boolean"
4482
+ },
4483
+ "name": "disabled",
4484
+ "description": "Whether the field is disabled or read-only."
4485
+ },
4486
+ {
4487
+ "title": "binding",
4488
+ "type": {
4489
+ "name": "object"
4490
+ },
4491
+ "name": "field",
4492
+ "description": "The field definition."
4493
+ }
4494
+ ]
4495
+ },
4334
4496
  {
4335
4497
  "name": "`tab-content(${key})`",
4336
4498
  "description": "Replaces the auto-rendered fields of edit-modal tab `<key>` with custom content. Name it `tab-content(<tabKey>)`.",
@@ -4579,8 +4741,8 @@
4579
4741
  ]
4580
4742
  },
4581
4743
  "stats": {
4582
- "totalComponents": 90,
4583
- "baseComponents": 60,
4744
+ "totalComponents": 92,
4745
+ "baseComponents": 62,
4584
4746
  "extendedComponents": 30
4585
4747
  }
4586
4748
  }
@@ -1,7 +1,7 @@
1
1
  # Documentation Map
2
2
 
3
3
  > Auto-generated hierarchical overview of all documentation
4
- > Last updated: 2026-10-11T09:08:08.837Z
4
+ > Last updated: 2026-10-21T10:08:54.546Z
5
5
 
6
6
  This file provides a complete map of all available documentation for AI agents and developers.
7
7
 
@@ -33,6 +33,7 @@ This file provides a complete map of all available documentation for AI agents a
33
33
  - [DDropdownItem](/components/base/DDropdownItem): Type-safe wrapper around Bootstrap Vue Next's BDropdownItem component
34
34
  - [DForm](/components/base/DForm): Type-safe wrapper around Bootstrap Vue Next's BForm component
35
35
  - [DFormCheckbox](/components/base/DFormCheckbox): Type-safe wrapper around Bootstrap Vue Next's BFormCheckbox component
36
+ - [DFormFile](/components/base/DFormFile): Type-safe wrapper around Bootstrap Vue Next's BFormFile component
36
37
  - [DFormGroup](/components/base/DFormGroup): Type-safe wrapper around Bootstrap Vue Next's BFormGroup component
37
38
  - [DFormInput](/components/base/DFormInput): Type-safe wrapper around Bootstrap Vue Next's BFormInput component
38
39
  - [DFormInvalidFeedback](/components/base/DFormInvalidFeedback): Type-safe wrapper around Bootstrap Vue Next's BFormInvalidFeedback component
@@ -43,6 +44,7 @@ This file provides a complete map of all available documentation for AI agents a
43
44
  - [DFormTags](/components/base/DFormTags): Type-safe wrapper around Bootstrap Vue Next's BFormTags component
44
45
  - [DFormText](/components/base/DFormText): Type-safe wrapper around Bootstrap Vue Next's BFormText component
45
46
  - [DFormTextarea](/components/base/DFormTextarea): Type-safe wrapper around Bootstrap Vue Next's BFormTextarea component
47
+ - [DFormValidFeedback](/components/base/DFormValidFeedback): Type-safe wrapper around Bootstrap Vue Next's BFormValidFeedback component
46
48
  - [DImage](/components/base/DImage): Type-safe wrapper around Bootstrap Vue Next's BImage component
47
49
  - [DInputGroup](/components/base/DInputGroup): Type-safe wrapper around Bootstrap Vue Next's BInputGroup component
48
50
  - [DLink](/components/base/DLink): Type-safe wrapper around Bootstrap Vue Next's BLink component
@@ -106,4 +108,4 @@ This file provides a complete map of all available documentation for AI agents a
106
108
 
107
109
  ---
108
110
 
109
- **Total Pages**: 82
111
+ **Total Pages**: 84
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Vue 3 dashboard components for Laravel with Bootstrap Vue Next
4
4
  >
5
- > A dual-package library (NPM + Composer) providing 80 Vue 3 components for building Laravel dashboards with Bootstrap Vue Next.
5
+ > A dual-package library (NPM + Composer) providing 82 Vue 3 components for building Laravel dashboards with Bootstrap Vue Next.
6
6
 
7
7
  ## Installation
8
8
 
@@ -19,7 +19,7 @@
19
19
  - [Theming](/guide/theming): Customize appearance with CSS variables
20
20
  - [TypeScript](/guide/typescript): TypeScript types and best practices
21
21
 
22
- ## Base Components (60 components)
22
+ ## Base Components (62 components)
23
23
 
24
24
  Lightweight type-safe wrappers around Bootstrap Vue Next components providing API stability and consistent theming.
25
25
 
@@ -46,6 +46,7 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
46
46
  - [DForm](/components/base/dform): Bootstrap Vue Next Form wrapper
47
47
  - [DFormCheckbox](/components/base/dformcheckbox): Bootstrap Vue Next FormCheckbox wrapper
48
48
  - [DFormCheckboxGroup](/components/base/dformcheckboxgroup): Bootstrap Vue Next FormCheckboxGroup wrapper
49
+ - [DFormFile](/components/base/dformfile): Bootstrap Vue Next FormFile wrapper
49
50
  - [DFormGroup](/components/base/dformgroup): Bootstrap Vue Next FormGroup wrapper
50
51
  - [DFormInput](/components/base/dforminput): Bootstrap Vue Next FormInput wrapper
51
52
  - [DFormInvalidFeedback](/components/base/dforminvalidfeedback): Bootstrap Vue Next FormInvalidFeedback wrapper
@@ -57,6 +58,7 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
57
58
  - [DFormTags](/components/base/dformtags): Bootstrap Vue Next FormTags wrapper
58
59
  - [DFormText](/components/base/dformtext): Bootstrap Vue Next FormText wrapper
59
60
  - [DFormTextarea](/components/base/dformtextarea): Bootstrap Vue Next FormTextarea wrapper
61
+ - [DFormValidFeedback](/components/base/dformvalidfeedback): Bootstrap Vue Next FormValidFeedback wrapper
60
62
  - [DImage](/components/base/dimage): Bootstrap Vue Next Image wrapper
61
63
  - [DInputGroup](/components/base/dinputgroup): Bootstrap Vue Next InputGroup wrapper
62
64
  - [DLink](/components/base/dlink): Bootstrap Vue Next Link wrapper