@omnitend/dashboard-for-laravel 0.33.1 → 0.35.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 (57) 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/DXForm.vue.d.ts +28 -6
  14. package/dist/components/extended/DXNumericField.vue.d.ts +23 -0
  15. package/dist/components/extended/DXRepeater.vue.d.ts +4 -4
  16. package/dist/components/extended/DXRepeaterCards.vue.d.ts +45 -0
  17. package/dist/components/extended/DXTable.vue.d.ts +107 -2
  18. package/dist/components/extended/DXTableEditorModal.vue.d.ts +22 -2
  19. package/dist/components/extended/DXUserAvatar.vue.d.ts +1 -1
  20. package/dist/composables/useAsyncOptions.d.ts +20 -0
  21. package/dist/composables/useContainerWidth.d.ts +96 -0
  22. package/dist/composables/useResourceEditor.d.ts +2 -1
  23. package/dist/dashboard-for-laravel.js +10513 -10443
  24. package/dist/dashboard-for-laravel.js.map +1 -1
  25. package/dist/dashboard-for-laravel.umd.cjs +7 -7
  26. package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
  27. package/dist/index.d.ts +5 -2
  28. package/dist/style.css +1 -1
  29. package/dist/types/index.d.ts +146 -0
  30. package/dist/utils/formSchema.d.ts +59 -0
  31. package/docs/public/api-reference.json +494 -33
  32. package/docs/public/docs-map.md +1 -1
  33. package/docs/public/llms.txt +5 -2
  34. package/package.json +1 -1
  35. package/resources/css/theme.scss +80 -2
  36. package/resources/js/components/charts/DXBarChart.vue +4 -43
  37. package/resources/js/components/charts/DXLineChart.vue +4 -43
  38. package/resources/js/components/charts/useThemedChart.ts +69 -0
  39. package/resources/js/components/extended/DXChoiceField.vue +114 -0
  40. package/resources/js/components/extended/DXDashboardSidebar.vue +1 -1
  41. package/resources/js/components/extended/DXField.vue +328 -615
  42. package/resources/js/components/extended/DXFieldShell.vue +124 -0
  43. package/resources/js/components/extended/DXForm.vue +92 -14
  44. package/resources/js/components/extended/DXNumericField.vue +144 -0
  45. package/resources/js/components/extended/DXRepeater.vue +53 -175
  46. package/resources/js/components/extended/DXRepeaterCards.vue +133 -0
  47. package/resources/js/components/extended/DXTable.vue +418 -43
  48. package/resources/js/components/extended/DXTableEditorModal.vue +39 -2
  49. package/resources/js/components/extended/DXTablePagination.vue +19 -3
  50. package/resources/js/components/extended/DXTableShell.vue +70 -1
  51. package/resources/js/composables/defineForm.ts +8 -44
  52. package/resources/js/composables/useAsyncOptions.ts +61 -0
  53. package/resources/js/composables/useContainerWidth.ts +303 -0
  54. package/resources/js/composables/useResourceEditor.ts +24 -38
  55. package/resources/js/index.ts +40 -0
  56. package/resources/js/types/index.ts +231 -0
  57. package/resources/js/utils/formSchema.ts +126 -0
@@ -1,8 +1,8 @@
1
1
  {
2
- "generated": "2026-07-20T14:11:55.309Z",
2
+ "generated": "2026-07-21T12:16:47.073Z",
3
3
  "package": {
4
4
  "name": "@omnitend/dashboard-for-laravel",
5
- "version": "0.33.1"
5
+ "version": "0.35.0"
6
6
  },
7
7
  "components": {
8
8
  "base": [
@@ -351,6 +351,26 @@
351
351
  ],
352
352
  "methods": []
353
353
  },
354
+ {
355
+ "name": "DCarousel",
356
+ "category": "base",
357
+ "filePath": "resources/js/index.ts",
358
+ "description": "Bootstrap Vue Next Carousel (re-exported as DCarousel).",
359
+ "props": [],
360
+ "events": [],
361
+ "slots": [],
362
+ "methods": []
363
+ },
364
+ {
365
+ "name": "DCarouselSlide",
366
+ "category": "base",
367
+ "filePath": "resources/js/index.ts",
368
+ "description": "Bootstrap Vue Next CarouselSlide (re-exported as DCarouselSlide).",
369
+ "props": [],
370
+ "events": [],
371
+ "slots": [],
372
+ "methods": []
373
+ },
354
374
  {
355
375
  "name": "DCol",
356
376
  "category": "base",
@@ -1169,6 +1189,16 @@
1169
1189
  "slots": [],
1170
1190
  "methods": []
1171
1191
  },
1192
+ {
1193
+ "name": "DTab",
1194
+ "category": "base",
1195
+ "filePath": "resources/js/index.ts",
1196
+ "description": "Bootstrap Vue Next Tab (re-exported as DTab).",
1197
+ "props": [],
1198
+ "events": [],
1199
+ "slots": [],
1200
+ "methods": []
1201
+ },
1172
1202
  {
1173
1203
  "name": "DTable",
1174
1204
  "category": "base",
@@ -1329,7 +1359,7 @@
1329
1359
  },
1330
1360
  {
1331
1361
  "name": "options",
1332
- "type": "Record",
1362
+ "type": "ChartOptions",
1333
1363
  "required": false,
1334
1364
  "description": "Chart.js options; deep-merged over the themed defaults."
1335
1365
  },
@@ -1385,6 +1415,65 @@
1385
1415
  ],
1386
1416
  "methods": []
1387
1417
  },
1418
+ {
1419
+ "name": "DXChoiceField",
1420
+ "category": "extended",
1421
+ "filePath": "resources/js/components/extended/DXChoiceField.vue",
1422
+ "description": "The choice control family for DXField: `select` (plain or `searchable`), `radio`, and `checkbox-group`. Extracted from DXField (#135) unchanged. These share the \"no native readonly\" convention (read-only is expressed as `disabled`, hence the pre-merged `disabled` + `controlProps`). The parent DXField still owns the value/options/guards and the `setValue` coercion; this component only renders the control and emits the edited value up. Plain-text `autocomplete` (a text input + datalist) stays in DXField itself, with the text-family controls, because it uses the native-readonly guard path rather than this disabled-only convention.",
1423
+ "props": [
1424
+ {
1425
+ "name": "field",
1426
+ "type": "FieldDefinition",
1427
+ "required": true,
1428
+ "description": "Field definition (type select/radio/checkbox-group + `searchable`)."
1429
+ },
1430
+ {
1431
+ "name": "modelValue",
1432
+ "type": "any",
1433
+ "required": true,
1434
+ "description": "Current model value."
1435
+ },
1436
+ {
1437
+ "name": "options",
1438
+ "type": "Array",
1439
+ "required": false,
1440
+ "description": "Resolved options (async-loaded or static)."
1441
+ },
1442
+ {
1443
+ "name": "state",
1444
+ "type": "union",
1445
+ "required": false,
1446
+ "description": "Validation state passed to the control."
1447
+ },
1448
+ {
1449
+ "name": "disabled",
1450
+ "type": "boolean",
1451
+ "required": false,
1452
+ "description": "Pre-merged disabled state (`isDisabled || isReadonly || isPlaintext`)."
1453
+ },
1454
+ {
1455
+ "name": "controlProps",
1456
+ "type": "Record",
1457
+ "required": false,
1458
+ "description": "Escape-hatch control props, already guard-merged by DXField."
1459
+ },
1460
+ {
1461
+ "name": "optionsReady",
1462
+ "type": "boolean",
1463
+ "required": false,
1464
+ "description": "Whether async options have resolved (a searchable select must not render\nbefore its options load, or it shows the raw id instead of the label)."
1465
+ }
1466
+ ],
1467
+ "events": [
1468
+ {
1469
+ "name": "update:modelValue",
1470
+ "description": "",
1471
+ "properties": []
1472
+ }
1473
+ ],
1474
+ "slots": [],
1475
+ "methods": []
1476
+ },
1388
1477
  {
1389
1478
  "name": "DXCurrencyInput",
1390
1479
  "category": "extended",
@@ -1912,7 +2001,7 @@
1912
2001
  "name": "DXField",
1913
2002
  "category": "extended",
1914
2003
  "filePath": "resources/js/components/extended/DXField.vue",
1915
- "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.",
2004
+ "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.",
1916
2005
  "props": [
1917
2006
  {
1918
2007
  "name": "field",
@@ -2005,7 +2094,7 @@
2005
2094
  },
2006
2095
  {
2007
2096
  "name": "hint",
2008
- "description": "Overrides the field's hint text shown below the control.",
2097
+ "description": "Overrides the field's hint text shown below the control (or, in horizontal layout, in the label column).",
2009
2098
  "bindings": [
2010
2099
  {
2011
2100
  "title": "binding",
@@ -2026,8 +2115,8 @@
2026
2115
  ]
2027
2116
  },
2028
2117
  {
2029
- "name": "value",
2030
- "description": "Replaces the built-in control with a custom value editor.",
2118
+ "name": "info",
2119
+ "description": "Rich info block rendered below the control.",
2031
2120
  "bindings": [
2032
2121
  {
2033
2122
  "title": "binding",
@@ -2044,28 +2133,12 @@
2044
2133
  },
2045
2134
  "name": "model",
2046
2135
  "description": "The model passed to field predicates (defaults to the live form data)."
2047
- },
2048
- {
2049
- "title": "binding",
2050
- "type": {
2051
- "name": "any"
2052
- },
2053
- "name": "value",
2054
- "description": "The current field value."
2055
- },
2056
- {
2057
- "title": "binding",
2058
- "type": {
2059
- "name": "(value: any) => void"
2060
- },
2061
- "name": "update",
2062
- "description": "Setter that writes the value back and clears the field's validation error."
2063
2136
  }
2064
2137
  ]
2065
2138
  },
2066
2139
  {
2067
- "name": "info",
2068
- "description": "Rich info block rendered below the control.",
2140
+ "name": "value",
2141
+ "description": "Replaces the built-in control with a custom value editor.",
2069
2142
  "bindings": [
2070
2143
  {
2071
2144
  "title": "binding",
@@ -2082,6 +2155,22 @@
2082
2155
  },
2083
2156
  "name": "model",
2084
2157
  "description": "The model passed to field predicates (defaults to the live form data)."
2158
+ },
2159
+ {
2160
+ "title": "binding",
2161
+ "type": {
2162
+ "name": "any"
2163
+ },
2164
+ "name": "value",
2165
+ "description": "The current field value."
2166
+ },
2167
+ {
2168
+ "title": "binding",
2169
+ "type": {
2170
+ "name": "(value: any) => void"
2171
+ },
2172
+ "name": "update",
2173
+ "description": "Setter that writes the value back and clears the field's validation error."
2085
2174
  }
2086
2175
  ]
2087
2176
  },
@@ -2144,6 +2233,123 @@
2144
2233
  ],
2145
2234
  "methods": []
2146
2235
  },
2236
+ {
2237
+ "name": "DXFieldShell",
2238
+ "category": "extended",
2239
+ "filePath": "resources/js/components/extended/DXFieldShell.vue",
2240
+ "description": "The chrome every DXField branch shares: the optional label (with its info affordance and, in horizontal layout, its hint), the control (default slot), and the trailing validation feedback + info block + hint + static help. Before #135 this markup was re-rendered separately in each of DXField's ~7 branches; it now lives here once. Two shapes: - `mode=\"group\"` — root is a `DFormGroup` that owns the `#label` column and holds the control + trailing block inside it (standard / horizontal checkbox / horizontal switch). - `mode=\"plain\"` — root is a plain `div`; the control renders its own inline label (vertical checkbox/switch), or a heading/rows (switch-list), or a nested group (repeater). The trailing block follows the control in the div. The `hint` and `info` slots are forwarded down from DXField (content AND slot props). `hint` falls back to `{{ resolvedHint }}` when no slot is supplied.",
2241
+ "props": [
2242
+ {
2243
+ "name": "field",
2244
+ "type": "FieldDefinition",
2245
+ "required": true,
2246
+ "description": "The field definition (for `field.help` and slot props)."
2247
+ },
2248
+ {
2249
+ "name": "form",
2250
+ "type": "UseFormReturn",
2251
+ "required": true,
2252
+ "description": "Form instance owning the field's errors."
2253
+ },
2254
+ {
2255
+ "name": "errorKey",
2256
+ "type": "string",
2257
+ "required": true,
2258
+ "description": "Error key for validation lookups."
2259
+ },
2260
+ {
2261
+ "name": "model",
2262
+ "type": "any",
2263
+ "required": false,
2264
+ "description": "Model passed to `hint`/`info` slot props."
2265
+ },
2266
+ {
2267
+ "name": "mode",
2268
+ "type": "union",
2269
+ "required": true,
2270
+ "description": "Layout shape. `group` = DFormGroup root with a label column; `plain` =\nplain div, the control owning its own inline label/heading."
2271
+ },
2272
+ {
2273
+ "name": "wrapperClass",
2274
+ "type": "string",
2275
+ "required": false,
2276
+ "description": "Wrapper class (`field.class || 'mb-3'`)."
2277
+ },
2278
+ {
2279
+ "name": "groupAttrs",
2280
+ "type": "Record",
2281
+ "required": false,
2282
+ "description": "BFormGroup attrs (horizontal label-cols etc.); group mode only."
2283
+ },
2284
+ {
2285
+ "name": "label",
2286
+ "type": "string",
2287
+ "required": true,
2288
+ "description": "Resolved label text (group mode). Always supplied by DXField."
2289
+ },
2290
+ {
2291
+ "name": "info",
2292
+ "type": "string",
2293
+ "required": false,
2294
+ "description": "Resolved info text for the label popover (group mode)."
2295
+ },
2296
+ {
2297
+ "name": "hideLabel",
2298
+ "type": "boolean",
2299
+ "required": false,
2300
+ "description": "Skip the label column entirely (group mode)."
2301
+ },
2302
+ {
2303
+ "name": "hintInLabel",
2304
+ "type": "boolean",
2305
+ "required": false,
2306
+ "description": "Whether the hint sits in the label column (horizontal) rather than below\nthe control. Group mode only; plain mode always renders the hint below."
2307
+ },
2308
+ {
2309
+ "name": "resolvedHint",
2310
+ "type": "string",
2311
+ "required": false,
2312
+ "description": "Resolved hint text (fallback when no `hint` slot is supplied)."
2313
+ }
2314
+ ],
2315
+ "events": [],
2316
+ "slots": [
2317
+ {
2318
+ "name": "hint",
2319
+ "description": "",
2320
+ "bindings": [
2321
+ {
2322
+ "name": "field",
2323
+ "title": "binding"
2324
+ },
2325
+ {
2326
+ "name": "model",
2327
+ "title": "binding"
2328
+ }
2329
+ ]
2330
+ },
2331
+ {
2332
+ "name": "default",
2333
+ "description": "",
2334
+ "bindings": []
2335
+ },
2336
+ {
2337
+ "name": "info",
2338
+ "description": "",
2339
+ "bindings": [
2340
+ {
2341
+ "name": "field",
2342
+ "title": "binding"
2343
+ },
2344
+ {
2345
+ "name": "model",
2346
+ "title": "binding"
2347
+ }
2348
+ ]
2349
+ }
2350
+ ],
2351
+ "methods": []
2352
+ },
2147
2353
  {
2148
2354
  "name": "DXForm",
2149
2355
  "category": "extended",
@@ -2221,7 +2427,14 @@
2221
2427
  "type": "union",
2222
2428
  "required": false,
2223
2429
  "default": "\"vertical\"",
2224
- "description": "Form-wide field layout: \"vertical\" (default, label above input) or\n\"horizontal\" (label left, input right). Overridable per-field via\n`field.layout`. A field with `span: true` always renders full-width,\nregardless of layout."
2430
+ "description": "Form-wide field layout:\n\n- `\"vertical\"` (default) — label above input, always.\n- `\"horizontal\"` — label left, input right, always.\n- `\"auto\"` — horizontal when the form's **own container** is at least\n `layoutThreshold` px wide, vertical below that. Container-driven, not\n viewport-driven: a page narrowed by the dashboard sidebar, or a form\n inside a modal, stacks even though the window is wide (which no\n Bootstrap media query can see).\n\nOverridable per-field via `field.layout`. A field with `span: true`\nalways renders full-width, regardless of layout."
2431
+ },
2432
+ {
2433
+ "name": "layoutThreshold",
2434
+ "type": "number",
2435
+ "required": false,
2436
+ "default": "640",
2437
+ "description": "Container width (px) at or above which `layout: \"auto\"` goes horizontal.\nIgnored for the explicit `\"vertical\"`/`\"horizontal\"` layouts.\n\nDefault 640, measured rather than guessed: with the default 3-column\nlabel the label's text area is `containerWidth / 4 - 18` px, so 640 gives\nit 142px — enough for a ~20-character label (\"Unit price (ex VAT)\"\nmeasures 128px at the theme's label font) to stay on one line, with the\ncontrol column still 474px. Below ~584px that label starts wrapping,\nwhich is the cramped-label symptom this exists to avoid. Raise it if your\nlabels run longer, or lower `labelCols` instead."
2225
2438
  },
2226
2439
  {
2227
2440
  "name": "labelCols",
@@ -2469,7 +2682,7 @@
2469
2682
  },
2470
2683
  {
2471
2684
  "name": "options",
2472
- "type": "Record",
2685
+ "type": "ChartOptions",
2473
2686
  "required": false,
2474
2687
  "description": "Chart.js options; deep-merged over the themed defaults."
2475
2688
  },
@@ -2504,6 +2717,65 @@
2504
2717
  "slots": [],
2505
2718
  "methods": []
2506
2719
  },
2720
+ {
2721
+ "name": "DXNumericField",
2722
+ "category": "extended",
2723
+ "filePath": "resources/js/components/extended/DXNumericField.vue",
2724
+ "description": "The numeric control family for DXField: `currency`, `percentage`, `number`. Extracted from DXField (#135) unchanged. The parent DXField still owns the value/guards/`setValue` coercion — this component only renders the control and emits the raw edited value back up. The `percentage` `asFraction` display scaling (model holds a 0–1 fraction, input shows 0–100) lives here because it is purely presentational to this control.",
2725
+ "props": [
2726
+ {
2727
+ "name": "field",
2728
+ "type": "FieldDefinition",
2729
+ "required": true,
2730
+ "description": "Field definition (type currency/percentage/number + numeric options)."
2731
+ },
2732
+ {
2733
+ "name": "modelValue",
2734
+ "type": "any",
2735
+ "required": true,
2736
+ "description": "Current model value."
2737
+ },
2738
+ {
2739
+ "name": "state",
2740
+ "type": "union",
2741
+ "required": false,
2742
+ "description": "Validation state passed to the control."
2743
+ },
2744
+ {
2745
+ "name": "isDisabled",
2746
+ "type": "boolean",
2747
+ "required": false,
2748
+ "description": "Disabled state (`isDisabled`)."
2749
+ },
2750
+ {
2751
+ "name": "isReadonly",
2752
+ "type": "boolean",
2753
+ "required": false,
2754
+ "description": "Readonly state (`isReadonly`)."
2755
+ },
2756
+ {
2757
+ "name": "isPlaintext",
2758
+ "type": "boolean",
2759
+ "required": false,
2760
+ "description": "Plaintext (display-only) state (`isPlaintext`)."
2761
+ },
2762
+ {
2763
+ "name": "inputProps",
2764
+ "type": "Record",
2765
+ "required": false,
2766
+ "description": "Escape-hatch input props, already guard-merged by DXField."
2767
+ }
2768
+ ],
2769
+ "events": [
2770
+ {
2771
+ "name": "update:modelValue",
2772
+ "description": "",
2773
+ "properties": []
2774
+ }
2775
+ ],
2776
+ "slots": [],
2777
+ "methods": []
2778
+ },
2507
2779
  {
2508
2780
  "name": "DXRepeater",
2509
2781
  "category": "extended",
@@ -2540,6 +2812,83 @@
2540
2812
  {
2541
2813
  "name": "row",
2542
2814
  "description": "Custom layout for a single repeater row, replacing the default sub-field stack (including the built-in Remove control — call `remove()` yourself). In table layout, rendered as the `<tr>`'s children: supply one `<td>` per sub-field plus a trailing `<td>` to match the header's column count (the header always includes an empty column for the built-in remove button).",
2815
+ "bindings": []
2816
+ }
2817
+ ],
2818
+ "methods": []
2819
+ },
2820
+ {
2821
+ "name": "DXRepeaterCards",
2822
+ "category": "extended",
2823
+ "filePath": "resources/js/components/extended/DXRepeaterCards.vue",
2824
+ "description": "DXRepeaterCards — the cards layout for DXRepeater: each row is its own bordered card with sub-fields stacked vertically, plus the add-row button. Internal to DXRepeater (not exported). It exists because DXRepeater rendered this exact markup TWICE — as the default `repeaterLayout: \"cards\"` branch and as the responsive fallback when the `\"table\"` layout lacks room — and the two copies would drift (#135). DXRepeater owns all the row state and passes it in; this component is presentational. The `.dx-repeater-row*` scoped styles live here (a scoped rule can't reach markup in another component), so the cards chrome moves as one unit with the markup it styles.",
2825
+ "props": [
2826
+ {
2827
+ "name": "visibleRows",
2828
+ "type": "Array",
2829
+ "required": true,
2830
+ "description": "Rows shown in the UI, each paired with its real (unfiltered) array index."
2831
+ },
2832
+ {
2833
+ "name": "subFields",
2834
+ "type": "Array",
2835
+ "required": true,
2836
+ "description": "Sub-field definitions for a row."
2837
+ },
2838
+ {
2839
+ "name": "form",
2840
+ "type": "UseFormReturn",
2841
+ "required": true,
2842
+ "description": "Form instance owning the repeater array."
2843
+ },
2844
+ {
2845
+ "name": "field",
2846
+ "type": "FieldDefinition",
2847
+ "required": true,
2848
+ "description": "The repeater field definition (for `showRowIndex` and `addLabel`)."
2849
+ },
2850
+ {
2851
+ "name": "minItems",
2852
+ "type": "number",
2853
+ "required": true,
2854
+ "description": "Minimum rows — the Remove button disables at this count."
2855
+ },
2856
+ {
2857
+ "name": "maxItems",
2858
+ "type": "union",
2859
+ "required": true,
2860
+ "description": "Maximum rows — the Add button disables at this count."
2861
+ },
2862
+ {
2863
+ "name": "rowKey",
2864
+ "type": "TSFunctionType",
2865
+ "required": true,
2866
+ "description": "Stable v-for key for a row (owned by DXRepeater — row identity, not index)."
2867
+ },
2868
+ {
2869
+ "name": "rowPath",
2870
+ "type": "TSFunctionType",
2871
+ "required": true,
2872
+ "description": "Dot path into form.data for a row at the given true index."
2873
+ },
2874
+ {
2875
+ "name": "removeRow",
2876
+ "type": "TSFunctionType",
2877
+ "required": true,
2878
+ "description": "Remove the row at the given true index (respects minItems / soft-delete)."
2879
+ },
2880
+ {
2881
+ "name": "addRow",
2882
+ "type": "TSFunctionType",
2883
+ "required": true,
2884
+ "description": "Append a fresh row (respects maxItems)."
2885
+ }
2886
+ ],
2887
+ "events": [],
2888
+ "slots": [
2889
+ {
2890
+ "name": "row",
2891
+ "description": "Custom layout for a single repeater row, replacing the default sub-field stack (including the built-in Remove control — call `remove()` yourself).",
2543
2892
  "bindings": [
2544
2893
  {
2545
2894
  "title": "binding",
@@ -2813,6 +3162,12 @@
2813
3162
  "required": false,
2814
3163
  "description": "Adapts the built-in provider's request params / response body to a\n backend convention that differs from dfl's (see DXTableApiAdapter)."
2815
3164
  },
3165
+ {
3166
+ "name": "source",
3167
+ "type": "DXTableSource",
3168
+ "required": false,
3169
+ "description": "Discriminated data-source (#130) — the type-safe alternative to the\nlegacy `items` / `provider` / `apiUrl` / `inertiaUrl` / `clientSide`\nprops. When set it WINS over those props; when omitted, the legacy props\napply unchanged. See `DXTableSource`."
3170
+ },
2816
3171
  {
2817
3172
  "name": "fields",
2818
3173
  "type": "Array",
@@ -2966,13 +3321,13 @@
2966
3321
  "type": "boolean",
2967
3322
  "required": false,
2968
3323
  "default": "true",
2969
- "description": "Wrap the table in a `DCard`. Defaults to `true`. Set `false` for a plain,\nborderless variant — the same header, filter row, table and pagination\nrendered directly on the page background (no card border/shadow), for\ndata-heavy admin index pages that read as busy inside a card."
3324
+ "description": "Wrap the table in a `DCard`. Defaults to `true`. Set `false` for a plain,\nborderless variant — the same header, filter row, table and pagination\nrendered directly on the page background (no card border/shadow), for\ndata-heavy admin index pages that read as busy inside a card.\n\nThe table renders FLUSH to the card border (rows and stripes reach the\nedge) while the header and pagination stay padded, which requires the card\nto clip to its radius (`overflow: hidden`).\n\n**Consequence for slot content:** anything you render into a slot that\npositions itself OUTSIDE the card and does not teleport is clipped at the\ncard edge. Library components are unaffected — `DDropdown` teleports to\n`<body>` by default, and the column-filter menus position themselves\n`fixed` — so this only bites a hand-rolled `position: absolute` overlay\n(a custom popover in a `cell(<key>)` or `#header` slot). Teleport it, or\nuse `:card=\"false\"`. Narrowing the clip to the table region is tracked\nas #166."
2970
3325
  },
2971
3326
  {
2972
3327
  "name": "editFields",
2973
3328
  "type": "Array",
2974
3329
  "required": false,
2975
- "description": "Form field definitions for edit modal (if provided, enables edit on row click)"
3330
+ "description": "Form field definitions for edit modal (if provided, enables edit on row\nclick). `import type` is erased at compile time, so this creates no\nruntime import cycle (#131)."
2976
3331
  },
2977
3332
  {
2978
3333
  "name": "editTabs",
@@ -2993,6 +3348,44 @@
2993
3348
  "default": "\"lg\"",
2994
3349
  "description": "Edit modal size"
2995
3350
  },
3351
+ {
3352
+ "name": "editLayout",
3353
+ "type": "union",
3354
+ "required": false,
3355
+ "default": "\"horizontal\"",
3356
+ "description": "Field layout for the edit/create modal's form, forwarded to its `DXForm`\n(\"vertical\" = label above input, \"horizontal\" = label left). Defaults to\n**\"horizontal\"** to match the Omni Tend form convention (a raw modal form\npreviously fell back to DXForm's vertical default, which looked out of\nplace next to horizontal page forms). Pass `\"vertical\"` to opt out.\n\n`\"auto\"` hands the decision to `DXForm`'s container-width observer, which\nmeasures the FORM rather than the window — so a modal narrowed by its own\nbreakpoint stacks to vertical even on a wide viewport, where a media query\nwould still report \"plenty of room\". See `useContainerWidth`."
3357
+ },
3358
+ {
3359
+ "name": "editLabelCols",
3360
+ "type": "LabelCols",
3361
+ "required": false,
3362
+ "description": "Label column width for the edit modal's horizontal layout, forwarded to\n`DXForm`'s `labelCols` (a single width or a per-breakpoint object). Only\nmeaningful when `editLayout` is \"horizontal\"."
3363
+ },
3364
+ {
3365
+ "name": "editCard",
3366
+ "type": "boolean",
3367
+ "required": false,
3368
+ "default": "false",
3369
+ "description": "Wrap the edit/create modal's form in a bordered card. Off by default (the\nmodal body already provides a boundary); opt in for a more contained,\npanelled look around a tabbed edit form."
3370
+ },
3371
+ {
3372
+ "name": "saveText",
3373
+ "type": "string",
3374
+ "required": false,
3375
+ "description": "Override the modal's Save button label (default: \"Save {item}\")."
3376
+ },
3377
+ {
3378
+ "name": "createText",
3379
+ "type": "string",
3380
+ "required": false,
3381
+ "description": "Override the modal's Create button label (default: \"Create {item}\")."
3382
+ },
3383
+ {
3384
+ "name": "deleteText",
3385
+ "type": "string",
3386
+ "required": false,
3387
+ "description": "Override the modal's Delete button label (default: \"Delete {item}\")."
3388
+ },
2996
3389
  {
2997
3390
  "name": "editUrl",
2998
3391
  "type": "string",
@@ -3192,6 +3585,32 @@
3192
3585
  }
3193
3586
  ]
3194
3587
  },
3588
+ {
3589
+ "name": "`head-end(${field.key})`",
3590
+ "description": "head-end(<fieldKey>) Additive content at the end of a column's own header — a period total above a numeric column, a small badge — keeping DXTable's sort indicator and field hint. Not a `head()` override.",
3591
+ "bindings": [
3592
+ {
3593
+ "name": "name",
3594
+ "title": "binding"
3595
+ },
3596
+ {
3597
+ "title": "binding",
3598
+ "type": {
3599
+ "name": "object"
3600
+ },
3601
+ "name": "field",
3602
+ "description": "The column's field definition."
3603
+ },
3604
+ {
3605
+ "title": "binding",
3606
+ "type": {
3607
+ "name": "string"
3608
+ },
3609
+ "name": "label",
3610
+ "description": "The column's resolved header label."
3611
+ }
3612
+ ]
3613
+ },
3195
3614
  {
3196
3615
  "name": "name",
3197
3616
  "description": "Any slot the underlying table supports, forwarded with its scope: `cell(<fieldKey>)` for a cell, `foot(<fieldKey>)` for a footer cell (needs `footClone`), `empty` for the no-rows message, `row-expansion` for expandable row detail, plus `custom-foot`, `top-row`, `bottom-row`, `thead-sub` and the `table-*` slots.",
@@ -3288,6 +3707,48 @@
3288
3707
  "type": "string",
3289
3708
  "required": false,
3290
3709
  "description": "Delete endpoint — gates the Delete button."
3710
+ },
3711
+ {
3712
+ "name": "layout",
3713
+ "type": "union",
3714
+ "required": false,
3715
+ "description": "Field layout forwarded to the modal's DXForm (defaults handled upstream).\nIncludes `\"auto\"`, which lets the form stack to vertical when the MODAL is\nnarrow even though the viewport is wide — the container-query case a\nviewport media query cannot see."
3716
+ },
3717
+ {
3718
+ "name": "labelCols",
3719
+ "type": "LabelCols",
3720
+ "required": false,
3721
+ "description": "Label column width forwarded to DXForm (horizontal layout)."
3722
+ },
3723
+ {
3724
+ "name": "card",
3725
+ "type": "boolean",
3726
+ "required": false,
3727
+ "description": "Wrap the modal form in a card (opt-in — off by default)."
3728
+ },
3729
+ {
3730
+ "name": "itemName",
3731
+ "type": "string",
3732
+ "required": false,
3733
+ "description": "Singular item noun for the default button labels (e.g. \"customer\")."
3734
+ },
3735
+ {
3736
+ "name": "saveText",
3737
+ "type": "string",
3738
+ "required": false,
3739
+ "description": "Override the Save button label (edit mode)."
3740
+ },
3741
+ {
3742
+ "name": "createText",
3743
+ "type": "string",
3744
+ "required": false,
3745
+ "description": "Override the Create button label (create mode)."
3746
+ },
3747
+ {
3748
+ "name": "deleteText",
3749
+ "type": "string",
3750
+ "required": false,
3751
+ "description": "Override the Delete button label."
3291
3752
  }
3292
3753
  ],
3293
3754
  "events": [
@@ -3563,7 +4024,7 @@
3563
4024
  "name": "DXTableShell",
3564
4025
  "category": "extended",
3565
4026
  "filePath": "resources/js/components/extended/DXTableShell.vue",
3566
- "description": "Internal chrome wrapper for `DXTable`. Renders its content either inside a `DCard` (the default) or as a plain, borderless block on the page background (`:card=\"false\"`). Extracted so `DXTable`'s ~460-line body and all its slots aren't duplicated across a card/plain `v-if`. Slots: - `#header` — the title / action row. In card mode it fills `DCard`'s header; in plain mode it renders above the table with a subtle bottom rule. - default — the table body (spinner/error/table/pagination).",
4027
+ "description": "Internal chrome wrapper for `DXTable`. Renders its content either inside a `DCard` (the default) or as a plain, borderless block on the page background (`:card=\"false\"`). Extracted so `DXTable`'s ~460-line body and all its slots aren't duplicated across a card/plain `v-if`. Slots: - `#header` — the title / action row. In card mode it fills `DCard`'s header; in plain mode it renders above the table with a subtle bottom rule. - default — the table body (spinner/error/table/pagination). Card mode renders `DCard` in **`no-body`** mode so the table sits FLUSH against the card border. With a `.card-body` in between, a striped table's rows were inset by `--bs-card-spacer-x` (24px) and left a white gutter between the stripes and the border. Without it, DXTable's children — error alert, loading block, table, pagination — become direct children of `.card`, which is already a `flex-direction: column` container, so they still stack in order: .card (overflow: hidden) ├─ .card-header (padded by Bootstrap's card-cap padding) ├─ .table-responsive ← FLUSH │ └─ table └─ .dx-table-pagination (pads itself — see DXTablePagination.vue) Bootstrap 5 has no `.card > .table` rounding rules (that was BS4), so the clipping is done with `overflow: hidden` on the card: the flush table's square top corners then follow the card's radius whether or not a header is present. bvn's popups position `fixed` by default, so they are not clipped by it.",
3567
4028
  "props": [
3568
4029
  {
3569
4030
  "name": "card",
@@ -3643,8 +4104,8 @@
3643
4104
  ]
3644
4105
  },
3645
4106
  "stats": {
3646
- "totalComponents": 77,
3647
- "baseComponents": 57,
3648
- "extendedComponents": 20
4107
+ "totalComponents": 84,
4108
+ "baseComponents": 60,
4109
+ "extendedComponents": 24
3649
4110
  }
3650
4111
  }