@omnitend/dashboard-for-laravel 0.27.0 → 0.29.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 (42) hide show
  1. package/dist/charts.d.ts +19 -0
  2. package/dist/charts.js +225 -0
  3. package/dist/charts.js.map +1 -0
  4. package/dist/charts.umd.cjs +2 -0
  5. package/dist/charts.umd.cjs.map +1 -0
  6. package/dist/components/base/DAlert.vue.d.ts +6 -1
  7. package/dist/components/base/DFormCheckboxGroup.vue.d.ts +12 -0
  8. package/dist/components/charts/chartTheme.d.ts +1 -0
  9. package/dist/components/extended/DXDashboardSidebar.vue.d.ts +2 -2
  10. package/dist/components/extended/DXField.vue.d.ts +4 -4
  11. package/dist/components/extended/DXForm.vue.d.ts +1 -1
  12. package/dist/components/extended/DXTable.vue.d.ts +9 -44
  13. package/dist/components/extended/DXTableEditorModal.vue.d.ts +80 -0
  14. package/dist/components/extended/DXTablePagination.vue.d.ts +27 -0
  15. package/dist/composables/useResourceEditor.d.ts +74 -0
  16. package/dist/dashboard-for-laravel.js +12463 -12819
  17. package/dist/dashboard-for-laravel.js.map +1 -1
  18. package/dist/dashboard-for-laravel.umd.cjs +8 -8
  19. package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
  20. package/dist/index.d.ts +1 -3
  21. package/dist/style.css +1 -1
  22. package/dist/types/index.d.ts +1 -1
  23. package/docs/public/api-reference.json +224 -9
  24. package/docs/public/docs-map.md +2 -2
  25. package/docs/public/llms.txt +3 -2
  26. package/package.json +12 -6
  27. package/resources/css/theme.scss +49 -7
  28. package/resources/js/charts.ts +19 -0
  29. package/resources/js/components/base/DAlert.vue +19 -1
  30. package/resources/js/components/base/DFormCheckboxGroup.vue +22 -0
  31. package/resources/js/components/charts/DXBarChart.vue +1 -10
  32. package/resources/js/components/charts/DXDoughnutChart.vue +1 -10
  33. package/resources/js/components/charts/DXLineChart.vue +1 -10
  34. package/resources/js/components/charts/chartTheme.ts +19 -16
  35. package/resources/js/components/extended/DXField.vue +12 -0
  36. package/resources/js/components/extended/DXTable.vue +161 -1034
  37. package/resources/js/components/extended/DXTableEditorModal.vue +247 -0
  38. package/resources/js/components/extended/DXTablePagination.vue +126 -0
  39. package/resources/js/composables/useForm.ts +10 -1
  40. package/resources/js/composables/useResourceEditor.ts +542 -0
  41. package/resources/js/index.ts +4 -3
  42. package/resources/js/types/index.ts +1 -0
@@ -1,8 +1,8 @@
1
1
  {
2
- "generated": "2026-07-18T05:05:36.998Z",
2
+ "generated": "2026-07-19T09:16:53.630Z",
3
3
  "package": {
4
4
  "name": "@omnitend/dashboard-for-laravel",
5
- "version": "0.26.0"
5
+ "version": "0.28.0"
6
6
  },
7
7
  "components": {
8
8
  "base": [
@@ -53,7 +53,15 @@
53
53
  "category": "base",
54
54
  "filePath": "resources/js/components/base/DAlert.vue",
55
55
  "description": "",
56
- "props": [],
56
+ "props": [
57
+ {
58
+ "name": "modelValue",
59
+ "type": "union",
60
+ "required": false,
61
+ "default": "true",
62
+ "description": ""
63
+ }
64
+ ],
57
65
  "events": [],
58
66
  "slots": [
59
67
  {
@@ -481,6 +489,27 @@
481
489
  ],
482
490
  "methods": []
483
491
  },
492
+ {
493
+ "name": "DFormCheckboxGroup",
494
+ "category": "base",
495
+ "filePath": "resources/js/components/base/DFormCheckboxGroup.vue",
496
+ "description": "Type-safe wrapper around Bootstrap Vue Next BFormCheckboxGroup component. Renders a group of checkboxes from an `options` array (or slot content); the `v-model` is the ARRAY of checked option values (\"pick any of N\").",
497
+ "props": [],
498
+ "events": [],
499
+ "slots": [
500
+ {
501
+ "name": "name",
502
+ "description": "",
503
+ "bindings": [
504
+ {
505
+ "name": "name",
506
+ "title": "binding"
507
+ }
508
+ ]
509
+ }
510
+ ],
511
+ "methods": []
512
+ },
484
513
  {
485
514
  "name": "DFormGroup",
486
515
  "category": "base",
@@ -1265,7 +1294,7 @@
1265
1294
  "name": "DXBarChart",
1266
1295
  "category": "extended",
1267
1296
  "filePath": "resources/js/components/charts/DXBarChart.vue",
1268
- "description": "A themed bar chart. Thin wrapper around vue-chartjs (chart.js) with the Bootstrap palette applied and dashboard-friendly defaults (no x gridlines, formatted value ticks, responsive, legend hidden for a single series). Pass `labels` + `datasets`; `options` deep-merges over the defaults. Requires the optional peer deps `chart.js` and `vue-chartjs`.",
1297
+ "description": "A themed bar chart. Thin wrapper around vue-chartjs (chart.js) with the theme's dedicated chart palette (--dx-chart-1..8) applied and dashboard-friendly defaults (no x gridlines, formatted value ticks, responsive, legend hidden for a single series). Pass `labels` + `datasets`; `options` deep-merges over the defaults. Requires the optional peer deps `chart.js` and `vue-chartjs`.",
1269
1298
  "props": [
1270
1299
  {
1271
1300
  "name": "labels",
@@ -1751,7 +1780,7 @@
1751
1780
  "name": "DXDoughnutChart",
1752
1781
  "category": "extended",
1753
1782
  "filePath": "resources/js/components/charts/DXDoughnutChart.vue",
1754
- "description": "A themed doughnut chart. Thin wrapper around vue-chartjs (chart.js) with one Bootstrap palette colour per slice and dashboard-friendly defaults. Pass `labels` + either `data` (a number array) or full `datasets`; `options` deep-merges over the defaults. Requires the optional peer deps `chart.js` and `vue-chartjs`.",
1783
+ "description": "A themed doughnut chart. Thin wrapper around vue-chartjs (chart.js) with one chart-palette colour (--dx-chart-1..8) per slice and dashboard-friendly defaults. Pass `labels` + either `data` (a number array) or full `datasets`; `options` deep-merges over the defaults. Requires the optional peer deps `chart.js` and `vue-chartjs`.",
1755
1784
  "props": [
1756
1785
  {
1757
1786
  "name": "labels",
@@ -2324,7 +2353,7 @@
2324
2353
  "name": "DXLineChart",
2325
2354
  "category": "extended",
2326
2355
  "filePath": "resources/js/components/charts/DXLineChart.vue",
2327
- "description": "A themed line chart. Thin wrapper around vue-chartjs (chart.js) with the Bootstrap palette applied (themed stroke + translucent fill, smoothed line) and dashboard-friendly defaults. Pass `labels` + `datasets`; `options` deep-merges over the defaults. Requires the optional peer deps `chart.js` and `vue-chartjs`.",
2356
+ "description": "A themed line chart. Thin wrapper around vue-chartjs (chart.js) with the theme's dedicated chart palette applied (--dx-chart-1..8 stroke + translucent fill, smoothed line) and dashboard-friendly defaults. Pass `labels` + `datasets`; `options` deep-merges over the defaults. Requires the optional peer deps `chart.js` and `vue-chartjs`.",
2328
2357
  "props": [
2329
2358
  {
2330
2359
  "name": "labels",
@@ -3045,7 +3074,123 @@
3045
3074
  "title": "binding"
3046
3075
  }
3047
3076
  ]
3077
+ }
3078
+ ],
3079
+ "methods": []
3080
+ },
3081
+ {
3082
+ "name": "DXTableEditorModal",
3083
+ "category": "extended",
3084
+ "filePath": "resources/js/components/extended/DXTableEditorModal.vue",
3085
+ "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.",
3086
+ "props": [
3087
+ {
3088
+ "name": "show",
3089
+ "type": "boolean",
3090
+ "required": true,
3091
+ "description": "Whether the modal is open (v-model:show)."
3092
+ },
3093
+ {
3094
+ "name": "title",
3095
+ "type": "string",
3096
+ "required": true,
3097
+ "description": "Modal title."
3098
+ },
3099
+ {
3100
+ "name": "size",
3101
+ "type": "union",
3102
+ "required": false,
3103
+ "description": "Modal size."
3104
+ },
3105
+ {
3106
+ "name": "loading",
3107
+ "type": "boolean",
3108
+ "required": true,
3109
+ "description": "True while the full record is loading via showUrl."
3110
+ },
3111
+ {
3112
+ "name": "form",
3113
+ "type": "any",
3114
+ "required": true,
3115
+ "description": "The edit/create form (a useForm instance), or null before first open."
3116
+ },
3117
+ {
3118
+ "name": "formInstanceKey",
3119
+ "type": "number",
3120
+ "required": true,
3121
+ "description": "Bumped per modal open to remount the DXForm subtree (fresh DXField state)."
3122
+ },
3123
+ {
3124
+ "name": "activeTab",
3125
+ "type": "number",
3126
+ "required": true,
3127
+ "description": "Active tab index (v-model:active-tab)."
3128
+ },
3129
+ {
3130
+ "name": "fields",
3131
+ "type": "Array",
3132
+ "required": true,
3133
+ "description": "Field definitions passed to DXForm."
3134
+ },
3135
+ {
3136
+ "name": "tabs",
3137
+ "type": "Array",
3138
+ "required": false,
3139
+ "description": "Tab definitions passed to DXForm."
3140
+ },
3141
+ {
3142
+ "name": "item",
3143
+ "type": "any",
3144
+ "required": true,
3145
+ "description": "The row being edited (null in create mode) — the slot/context row."
3146
+ },
3147
+ {
3148
+ "name": "isCreateMode",
3149
+ "type": "boolean",
3150
+ "required": true,
3151
+ "description": "Whether the modal is in create mode (vs edit)."
3152
+ },
3153
+ {
3154
+ "name": "pendingAction",
3155
+ "type": "union",
3156
+ "required": true,
3157
+ "description": "Which action is in flight, so Save/Delete show their own loading label."
3048
3158
  },
3159
+ {
3160
+ "name": "deleteUrl",
3161
+ "type": "string",
3162
+ "required": false,
3163
+ "description": "Delete endpoint — gates the Delete button."
3164
+ }
3165
+ ],
3166
+ "events": [
3167
+ {
3168
+ "name": "update:show",
3169
+ "description": "v-model:show — the modal open state changed.",
3170
+ "properties": []
3171
+ },
3172
+ {
3173
+ "name": "update:activeTab",
3174
+ "description": "v-model:active-tab — the active tab changed.",
3175
+ "properties": []
3176
+ },
3177
+ {
3178
+ "name": "save",
3179
+ "description": "Save was requested (footer button or DXForm submit).",
3180
+ "properties": []
3181
+ },
3182
+ {
3183
+ "name": "cancel",
3184
+ "description": "Cancel/close was requested.",
3185
+ "properties": []
3186
+ },
3187
+ {
3188
+ "name": "delete",
3189
+ "description": "Delete was requested.",
3190
+ "properties": []
3191
+ }
3192
+ ],
3193
+ "slots": [
3049
3194
  {
3050
3195
  "name": "`edit-value(${key})`",
3051
3196
  "description": "Custom input for field `<key>` in the edit/create modal, forwarded to DXForm. Name it `edit-value(<fieldKey>)`.",
@@ -3211,6 +3356,76 @@
3211
3356
  ],
3212
3357
  "methods": []
3213
3358
  },
3359
+ {
3360
+ "name": "DXTablePagination",
3361
+ "category": "extended",
3362
+ "filePath": "resources/js/components/extended/DXTablePagination.vue",
3363
+ "description": "Internal pagination + per-page footer for `DXTable`. Renders the pager, the per-page selector, and the \"X to Y out of Z items\" info line (with the \"Filtered from N\" note when a column filter is active). Extracted because `DXTable` used to carry three byte-identical copies of this footer — one per data mode (client-side / inertia / provider) — that differed only in which `PaginationData` object and page-change handler they used, so every footer fix had to be written three times (#123). `DXTable` now derives the active pagination + handler and renders this once. It owns its own `:deep(.pagination …)` styling (rather than leaving it in `DXTable`), because a scoped `:deep()` in `DXTable` would not reach the pager once it lives in a child component — the scope-id doesn't cross the boundary. Anchoring the rules on this component's own `.dx-table-pagination` root (a plain element it owns) gives the scope-id a deterministic host.",
3364
+ "props": [
3365
+ {
3366
+ "name": "pagination",
3367
+ "type": "PaginationData",
3368
+ "required": true,
3369
+ "description": "The active pagination metadata (client-side / inertia / provider)."
3370
+ },
3371
+ {
3372
+ "name": "perPage",
3373
+ "type": "number",
3374
+ "required": true,
3375
+ "description": "The effective page size, shown in the selector."
3376
+ },
3377
+ {
3378
+ "name": "perPageOptions",
3379
+ "type": "Array",
3380
+ "required": true,
3381
+ "description": "Page sizes offered by the selector."
3382
+ },
3383
+ {
3384
+ "name": "showPagination",
3385
+ "type": "boolean",
3386
+ "required": true,
3387
+ "description": "Whether to render the pager (still hidden when there is only one page)."
3388
+ },
3389
+ {
3390
+ "name": "showPerPageSelector",
3391
+ "type": "boolean",
3392
+ "required": true,
3393
+ "description": "Whether to render the per-page selector."
3394
+ },
3395
+ {
3396
+ "name": "singularItemName",
3397
+ "type": "string",
3398
+ "required": true,
3399
+ "description": "Singular item noun for the info line (e.g. \"product\")."
3400
+ },
3401
+ {
3402
+ "name": "pluralItemName",
3403
+ "type": "string",
3404
+ "required": true,
3405
+ "description": "Plural item noun for the info line (e.g. \"products\")."
3406
+ },
3407
+ {
3408
+ "name": "hasActiveFilters",
3409
+ "type": "boolean",
3410
+ "required": true,
3411
+ "description": "Whether a column filter is active — gates the \"Filtered from N\" note."
3412
+ }
3413
+ ],
3414
+ "events": [
3415
+ {
3416
+ "name": "page-change",
3417
+ "description": "The user picked a page. Payload is the new 1-based page number.",
3418
+ "properties": []
3419
+ },
3420
+ {
3421
+ "name": "per-page-change",
3422
+ "description": "The per-page selector changed. Payload is the raw DFormSelect model value\n(the parent's `handlePerPageChange` narrows it — DFormSelect mirrors BVN's\nmodel, which can be a scalar, null, or array).",
3423
+ "properties": []
3424
+ }
3425
+ ],
3426
+ "slots": [],
3427
+ "methods": []
3428
+ },
3214
3429
  {
3215
3430
  "name": "DXTableShell",
3216
3431
  "category": "extended",
@@ -3295,8 +3510,8 @@
3295
3510
  ]
3296
3511
  },
3297
3512
  "stats": {
3298
- "totalComponents": 73,
3299
- "baseComponents": 56,
3300
- "extendedComponents": 17
3513
+ "totalComponents": 76,
3514
+ "baseComponents": 57,
3515
+ "extendedComponents": 19
3301
3516
  }
3302
3517
  }
@@ -1,7 +1,7 @@
1
1
  # Documentation Map
2
2
 
3
3
  > Auto-generated hierarchical overview of all documentation
4
- > Last updated: 2026-07-18T05:05:37.057Z
4
+ > Last updated: 2026-07-19T09:16:53.689Z
5
5
 
6
6
  This file provides a complete map of all available documentation for AI agents and developers.
7
7
 
@@ -95,7 +95,7 @@ This file provides a complete map of all available documentation for AI agents a
95
95
  - [Forms](/guide/forms): The library includes a type-safe form system with validation, auto-generated forms, and composables.
96
96
  - [Getting Started](/guide/getting-started): > **Alpha Notice:** v0.x — expect changes between minor versions.
97
97
  - [Installation](/guide/installation): ```bash
98
- - [Theming](/guide/theming): The library includes a custom Bootstrap 5 theme that can be easily customised using CSS variables an
98
+ - [Theming](/guide/theming): The library ships a custom Bootstrap 5 theme built around a **soft-first
99
99
  - [TypeScript](/guide/typescript): The library is written in TypeScript and includes full type definitions for all components, composab
100
100
 
101
101
 
@@ -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 68 Vue 3 components for building Laravel dashboards with Bootstrap Vue Next.
5
+ > A dual-package library (NPM + Composer) providing 69 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 (56 components)
22
+ ## Base Components (57 components)
23
23
 
24
24
  Lightweight type-safe wrappers around Bootstrap Vue Next components providing API stability and consistent theming.
25
25
 
@@ -43,6 +43,7 @@ Lightweight type-safe wrappers around Bootstrap Vue Next components providing AP
43
43
  - [DDropdownItem](/components/base/ddropdownitem): Bootstrap Vue Next DropdownItem wrapper
44
44
  - [DForm](/components/base/dform): Bootstrap Vue Next Form wrapper
45
45
  - [DFormCheckbox](/components/base/dformcheckbox): Bootstrap Vue Next FormCheckbox wrapper
46
+ - [DFormCheckboxGroup](/components/base/dformcheckboxgroup): Bootstrap Vue Next FormCheckboxGroup wrapper
46
47
  - [DFormGroup](/components/base/dformgroup): Bootstrap Vue Next FormGroup wrapper
47
48
  - [DFormInput](/components/base/dforminput): Bootstrap Vue Next FormInput wrapper
48
49
  - [DFormInvalidFeedback](/components/base/dforminvalidfeedback): Bootstrap Vue Next FormInvalidFeedback wrapper
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnitend/dashboard-for-laravel",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "description": "Vue 3 dashboard components for Laravel with Bootstrap Vue Next",
5
5
  "type": "module",
6
6
  "main": "./dist/dashboard-for-laravel.umd.cjs",
@@ -15,6 +15,11 @@
15
15
  "import": "./dist/dashboard-for-laravel.js",
16
16
  "require": "./dist/dashboard-for-laravel.umd.cjs"
17
17
  },
18
+ "./charts": {
19
+ "types": "./dist/charts.d.ts",
20
+ "import": "./dist/charts.js",
21
+ "require": "./dist/charts.umd.cjs"
22
+ },
18
23
  "./style.css": "./dist/style.css",
19
24
  "./theme.css": "./dist/style.css",
20
25
  "./theme.scss": "./resources/css/theme.scss"
@@ -29,16 +34,17 @@
29
34
  ],
30
35
  "scripts": {
31
36
  "dev": "vite build --watch",
32
- "build": "vite build && node scripts/extract-icon-font.mjs && vue-tsc --declaration --emitDeclarationOnly --outDir dist",
37
+ "build:lib": "vite build && vite build --config vite.config.charts.ts && node scripts/extract-icon-font.mjs",
38
+ "build": "npm run build:lib && vue-tsc --declaration --emitDeclarationOnly --outDir dist",
33
39
  "typecheck": "vue-tsc --noEmit",
34
- "pretest": "vite build",
40
+ "pretest": "npm run build:lib",
35
41
  "test": "vitest",
36
- "pretest:ui": "vite build",
42
+ "pretest:ui": "npm run build:lib",
37
43
  "test:ui": "vitest --ui",
38
- "pretest:headless": "vite build",
44
+ "pretest:headless": "npm run build:lib",
39
45
  "test:headless": "vitest --run --browser.headless",
40
46
  "docs:dev": "astro dev",
41
- "docs:build": "npm run docs:generate:ai && astro build",
47
+ "docs:build": "npm run docs:generate:ai && astro build && node scripts/check-docs-base-links.mjs",
42
48
  "docs:preview": "astro preview",
43
49
  "docs:generate": "node scripts/generate-component-docs.mjs",
44
50
  "docs:generate:ai": "node scripts/generate-llms-txt.mjs && node scripts/generate-api-manifest.mjs && node scripts/generate-docs-map.mjs",
@@ -7,6 +7,7 @@
7
7
  // The Sass module for `color.mix()` etc. `@use` must precede all other
8
8
  // statements (variable overrides, `@import`), so it stays at the very top.
9
9
  @use "sass:color";
10
+ @use "sass:list";
10
11
  @use "sass:map";
11
12
 
12
13
  // ----------------------------------------------------------------------------
@@ -435,14 +436,17 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
435
436
 
436
437
  // Semantic variants: subtle tinted surface, driven through the CSS variable
437
438
  // the base `.toast` rule (above, and Bootstrap's own) already reads.
438
- @each $name, $color in (
439
- "success": $success,
440
- "danger": $danger,
441
- "warning": $warning,
442
- "info": $info
443
- ) {
439
+ //
440
+ // Sourced from each variant's `soft-bg` in $dx-variants (#143) — the same
441
+ // vivid-derived soft family badges/alerts use — so the toast hue tracks the
442
+ // palette and editing a `soft-bg` moves toasts too. Previously these mixed the
443
+ // dark *emphasis* base colours (greyer success/warning) and danger's saturated
444
+ // red (a pink, not the soft system's plum). Mixed 50% with white so a large
445
+ // toast surface stays fainter than a small badge while keeping the hue.
446
+ @each $name in ("success", "danger", "warning", "info") {
447
+ $variant: map.get($dx-variants, $name);
444
448
  &.toast-#{$name} {
445
- --bs-toast-bg: #{color.mix($color, $white, 8%)};
449
+ --bs-toast-bg: #{color.mix(map.get($variant, "soft-bg"), $white, 50%)};
446
450
  }
447
451
  }
448
452
  }
@@ -553,6 +557,44 @@ $bootstrap-icons-font-src: url("bootstrap-icons/font/fonts/bootstrap-icons.woff2
553
557
  }
554
558
  }
555
559
 
560
+ // ----------------------------------------------------------------------------
561
+ // Chart palette (data-viz)
562
+ // ----------------------------------------------------------------------------
563
+ // Dedicated categorical palette for the DX*Chart components — deliberately NOT
564
+ // the semantic UI colours (#141). Two reasons: the base $theme-colors carry
565
+ // dark "emphasis" shades (AA text/link colours, too muted for data series), and
566
+ // status colours (success/danger) shouldn't impersonate "series 2" — a green or
567
+ // red series should mean something.
568
+ //
569
+ // Eight vivid mid-lightness hues in a FIXED order. The order is load-bearing:
570
+ // it was derived by exhaustively permuting the hues (slot 1 pinned to the brand
571
+ // info-blue) to maximise the minimum adjacent-pair colour-vision-deficiency
572
+ // separation — validated at min adjacent ΔE 13.8 (OKLab ×100, protan/deutan
573
+ // simulated), min normal-vision ΔE 20.3, every hue ≥ 3:1 contrast on white.
574
+ // Reordering or swapping a hue needs that validation re-run, not an eyeball.
575
+ //
576
+ // Published as --dx-chart-1..8 so consumers can retheme charts by overriding
577
+ // the variables; chartTheme.ts reads them at runtime (with these hexes as
578
+ // fallbacks for SSR / missing-CSS cases — keep the two lists in sync).
579
+ $dx-chart-palette: (#2563eb, #65a30d, #7c3aed, #0d9488, #ea580c, #0891b2, #d97706, #db2777);
580
+
581
+ :root {
582
+ @for $i from 1 through list.length($dx-chart-palette) {
583
+ --dx-chart-#{$i}: #{list.nth($dx-chart-palette, $i)};
584
+ }
585
+ }
586
+
587
+ // The chart container used by DXBarChart/DXLineChart/DXDoughnutChart (shipped
588
+ // from the `@omnitend/dashboard-for-laravel/charts` entry, #142). Global rather
589
+ // than a component scoped style so the charts entry emits NO CSS — chart
590
+ // consumers already import this stylesheet for the theme + palette variables.
591
+ .dx-chart {
592
+ position: relative;
593
+ width: 100%;
594
+ height: 100%;
595
+ min-height: 240px;
596
+ }
597
+
556
598
  // ----------------------------------------------------------------------------
557
599
  // Autocomplete
558
600
  // ----------------------------------------------------------------------------
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Chart entry point — `@omnitend/dashboard-for-laravel/charts` (#142).
3
+ *
4
+ * The chart components are the ONLY ones that need `chart.js` / `vue-chartjs`,
5
+ * so they live behind this separate subpath entry. The main entry
6
+ * (`@omnitend/dashboard-for-laravel`) never references the chart libraries, so
7
+ * they are genuinely OPTIONAL peers: a consumer that renders no charts installs
8
+ * neither and their build no longer fails resolving them.
9
+ *
10
+ * import { DXBarChart } from '@omnitend/dashboard-for-laravel/charts';
11
+ *
12
+ * Chart containers are styled by `.dx-chart` in the main stylesheet
13
+ * (`@omnitend/dashboard-for-laravel/style.css`), which chart consumers already
14
+ * import for the theme and the `--dx-chart-*` palette variables — so this entry
15
+ * ships no CSS of its own.
16
+ */
17
+ export { default as DXBarChart } from "./components/charts/DXBarChart.vue";
18
+ export { default as DXLineChart } from "./components/charts/DXLineChart.vue";
19
+ export { default as DXDoughnutChart } from "./components/charts/DXDoughnutChart.vue";
@@ -2,11 +2,29 @@
2
2
  import { BAlert } from "bootstrap-vue-next";
3
3
  import { useSlots } from "vue";
4
4
 
5
+ /*
6
+ * bootstrap-vue-next's BAlert defaults `modelValue` to `false`, so a bare static
7
+ * `<DAlert variant="info">…</DAlert>` silently renders NOTHING — a footgun that
8
+ * bit our own docs repeatedly (#144). Default it to `true` (visible) at the
9
+ * wrapper; every call site that already passes `v-model`/`:model-value` is
10
+ * unaffected — only the bare-static case (which was always a bug) changes.
11
+ *
12
+ * Care (see DIVERGENCES.md): declaring `modelValue` as a prop strips it from
13
+ * `$attrs`, so it is re-bound explicitly below. `emits` is left UNDECLARED so an
14
+ * `update:modelValue` listener keeps flowing through `$attrs` to BAlert — that's
15
+ * what lets `v-model` dismissal (and the auto-dismiss countdown) still
16
+ * round-trip. The type stays `boolean | number` (a number is the auto-dismiss
17
+ * duration in ms) — don't narrow it.
18
+ */
19
+ const props = withDefaults(defineProps<{ modelValue?: boolean | number }>(), {
20
+ modelValue: true,
21
+ });
22
+
5
23
  const slots = useSlots();
6
24
  </script>
7
25
 
8
26
  <template>
9
- <BAlert v-bind="$attrs">
27
+ <BAlert :model-value="props.modelValue" v-bind="$attrs">
10
28
  <template v-for="(_, name) in slots" :key="name" #[name]>
11
29
  <slot :name="name" />
12
30
  </template>
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @component
3
+ * Type-safe wrapper around Bootstrap Vue Next BFormCheckboxGroup component.
4
+ * Renders a group of checkboxes from an `options` array (or slot content); the
5
+ * `v-model` is the ARRAY of checked option values ("pick any of N").
6
+ */
7
+ <script setup lang="ts">
8
+ import { BFormCheckboxGroup } from "bootstrap-vue-next";
9
+
10
+ defineOptions({
11
+ inheritAttrs: false,
12
+ });
13
+ </script>
14
+
15
+ <template>
16
+ <BFormCheckboxGroup v-bind="$attrs">
17
+ <!-- Dynamically pass through all named slots with their props -->
18
+ <template v-for="(_, name) in $slots" :key="name" #[name]="slotProps">
19
+ <slot :name="name" v-bind="slotProps" />
20
+ </template>
21
+ </BFormCheckboxGroup>
22
+ </template>
@@ -1,7 +1,7 @@
1
1
  <!--
2
2
  @component
3
3
  A themed bar chart. Thin wrapper around vue-chartjs (chart.js) with the
4
- Bootstrap palette applied and dashboard-friendly defaults (no x gridlines,
4
+ theme's dedicated chart palette (--dx-chart-1..8) applied and dashboard-friendly defaults (no x gridlines,
5
5
  formatted value ticks, responsive, legend hidden for a single series). Pass
6
6
  `labels` + `datasets`; `options` deep-merges over the defaults.
7
7
 
@@ -68,12 +68,3 @@ const mergedOptions = computed(() =>
68
68
  ),
69
69
  );
70
70
  </script>
71
-
72
- <style scoped>
73
- .dx-chart {
74
- position: relative;
75
- width: 100%;
76
- height: 100%;
77
- min-height: 240px;
78
- }
79
- </style>
@@ -1,7 +1,7 @@
1
1
  <!--
2
2
  @component
3
3
  A themed doughnut chart. Thin wrapper around vue-chartjs (chart.js) with one
4
- Bootstrap palette colour per slice and dashboard-friendly defaults. Pass
4
+ chart-palette colour (--dx-chart-1..8) per slice and dashboard-friendly defaults. Pass
5
5
  `labels` + either `data` (a number array) or full `datasets`; `options`
6
6
  deep-merges over the defaults.
7
7
 
@@ -74,12 +74,3 @@ const mergedOptions = computed(() =>
74
74
  ),
75
75
  );
76
76
  </script>
77
-
78
- <style scoped>
79
- .dx-chart {
80
- position: relative;
81
- width: 100%;
82
- height: 100%;
83
- min-height: 240px;
84
- }
85
- </style>
@@ -1,7 +1,7 @@
1
1
  <!--
2
2
  @component
3
3
  A themed line chart. Thin wrapper around vue-chartjs (chart.js) with the
4
- Bootstrap palette applied (themed stroke + translucent fill, smoothed line)
4
+ theme's dedicated chart palette applied (--dx-chart-1..8 stroke + translucent fill, smoothed line)
5
5
  and dashboard-friendly defaults. Pass `labels` + `datasets`; `options`
6
6
  deep-merges over the defaults.
7
7
 
@@ -68,12 +68,3 @@ const mergedOptions = computed(() =>
68
68
  ),
69
69
  );
70
70
  </script>
71
-
72
- <style scoped>
73
- .dx-chart {
74
- position: relative;
75
- width: 100%;
76
- height: 100%;
77
- min-height: 240px;
78
- }
79
- </style>
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Shared theming for the DX*Chart wrappers: a categorical palette pulled from
3
- * the live Bootstrap theme, dashboard-friendly default options (no gridlines /
2
+ * Shared theming for the DX*Chart wrappers: the dedicated categorical chart
3
+ * palette (--dx-chart-* from the live theme), dashboard-friendly default options (no gridlines /
4
4
  * legend clutter, responsive, formatted ticks), and a one-time Chart.js
5
5
  * registration. chart.js / vue-chartjs are OPTIONAL peer deps.
6
6
  */
@@ -40,20 +40,23 @@ export function registerCharts(): void {
40
40
  registered = true;
41
41
  }
42
42
 
43
- // Bootstrap CSS variables to read, in a sensible categorical order. Fallbacks
44
- // mirror Bootstrap 5 defaults so charts still render without the theme (SSR /
45
- // tests / a consumer who didn't import the CSS).
46
- const PALETTE_VARS: Array<[string, string]> = [
47
- ["--bs-primary", "#0d6efd"],
48
- ["--bs-success", "#198754"],
49
- ["--bs-info", "#0dcaf0"],
50
- ["--bs-warning", "#ffc107"],
51
- ["--bs-danger", "#dc3545"],
52
- ["--bs-purple", "#6f42c1"],
53
- ["--bs-teal", "#20c997"],
54
- ["--bs-orange", "#fd7e14"],
55
- ["--bs-pink", "#d63384"],
56
- ["--bs-secondary", "#6c757d"],
43
+ // The dedicated data-viz palette (`$dx-chart-palette` in theme.scss) — eight
44
+ // vivid hues in a fixed, CVD-validated order, published as --dx-chart-1..8.
45
+ // Deliberately NOT the semantic --bs-* colours (#141): the base theme colours
46
+ // are dark AA "emphasis" shades (too muted for series), and status colours
47
+ // shouldn't impersonate "series 2". Fallbacks mirror the shipped theme so
48
+ // charts still render without the CSS (SSR / tests / a consumer who didn't
49
+ // import it). Sync with theme.scss's $dx-chart-palette is enforced by a test
50
+ // that parses the Sass source (charts.test.ts), which is why this is exported.
51
+ export const PALETTE_VARS: Array<[string, string]> = [
52
+ ["--dx-chart-1", "#2563eb"], // blue
53
+ ["--dx-chart-2", "#65a30d"], // lime
54
+ ["--dx-chart-3", "#7c3aed"], // violet
55
+ ["--dx-chart-4", "#0d9488"], // teal
56
+ ["--dx-chart-5", "#ea580c"], // orange
57
+ ["--dx-chart-6", "#0891b2"], // cyan
58
+ ["--dx-chart-7", "#d97706"], // amber
59
+ ["--dx-chart-8", "#db2777"], // pink
57
60
  ];
58
61
 
59
62
  /** Resolve the themed categorical palette from the document root. */