nuxt-ui-tools 1.2.0 → 1.3.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 (179) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +10 -1
  3. package/dist/runtime/dashboard/components/block/dashboard-block-state.d.vue.ts +2 -0
  4. package/dist/runtime/dashboard/components/block/dashboard-block-state.vue +4 -1
  5. package/dist/runtime/dashboard/components/block/dashboard-block-state.vue.d.ts +2 -0
  6. package/dist/runtime/dashboard/components/block/dashboard-chips.d.vue.ts +20 -0
  7. package/dist/runtime/dashboard/components/block/dashboard-chips.vue +42 -0
  8. package/dist/runtime/dashboard/components/block/dashboard-chips.vue.d.ts +20 -0
  9. package/dist/runtime/dashboard/components/block/dashboard-series-picker.d.vue.ts +8 -0
  10. package/dist/runtime/dashboard/components/block/dashboard-series-picker.vue +29 -0
  11. package/dist/runtime/dashboard/components/block/dashboard-series-picker.vue.d.ts +8 -0
  12. package/dist/runtime/dashboard/components/block/dashboard-skeleton.d.vue.ts +1 -1
  13. package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue.d.ts +1 -1
  14. package/dist/runtime/dashboard/components/block/dashboard-view-scope.d.vue.ts +21 -0
  15. package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue +12 -0
  16. package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue.d.ts +21 -0
  17. package/dist/runtime/dashboard/components/dashboard-alerts.vue +3 -3
  18. package/dist/runtime/dashboard/components/dashboard-bar-chart.d.vue.ts +14 -3
  19. package/dist/runtime/dashboard/components/dashboard-bar-chart.vue +30 -9
  20. package/dist/runtime/dashboard/components/dashboard-bar-chart.vue.d.ts +14 -3
  21. package/dist/runtime/dashboard/components/dashboard-bars.vue +4 -4
  22. package/dist/runtime/dashboard/components/dashboard-card.vue +28 -6
  23. package/dist/runtime/dashboard/components/dashboard-combo-chart.d.vue.ts +6 -1
  24. package/dist/runtime/dashboard/components/dashboard-combo-chart.vue +13 -3
  25. package/dist/runtime/dashboard/components/dashboard-combo-chart.vue.d.ts +6 -1
  26. package/dist/runtime/dashboard/components/dashboard-donut-chart.vue +5 -5
  27. package/dist/runtime/dashboard/components/dashboard-feed.vue +1 -1
  28. package/dist/runtime/dashboard/components/dashboard-filter.d.vue.ts +67 -0
  29. package/dist/runtime/dashboard/components/dashboard-filter.vue +134 -0
  30. package/dist/runtime/dashboard/components/dashboard-filter.vue.d.ts +67 -0
  31. package/dist/runtime/dashboard/components/dashboard-filters.d.vue.ts +49 -0
  32. package/dist/runtime/dashboard/components/dashboard-filters.vue +96 -0
  33. package/dist/runtime/dashboard/components/dashboard-filters.vue.d.ts +49 -0
  34. package/dist/runtime/dashboard/components/dashboard-funnel.vue +5 -5
  35. package/dist/runtime/dashboard/components/dashboard-gauge.vue +3 -3
  36. package/dist/runtime/dashboard/components/dashboard-grid.d.vue.ts +10 -3
  37. package/dist/runtime/dashboard/components/dashboard-grid.vue +24 -9
  38. package/dist/runtime/dashboard/components/dashboard-grid.vue.d.ts +10 -3
  39. package/dist/runtime/dashboard/components/dashboard-line-chart.d.vue.ts +14 -3
  40. package/dist/runtime/dashboard/components/dashboard-line-chart.vue +30 -9
  41. package/dist/runtime/dashboard/components/dashboard-line-chart.vue.d.ts +14 -3
  42. package/dist/runtime/dashboard/components/dashboard-list.d.vue.ts +3 -0
  43. package/dist/runtime/dashboard/components/dashboard-list.vue +18 -6
  44. package/dist/runtime/dashboard/components/dashboard-list.vue.d.ts +3 -0
  45. package/dist/runtime/dashboard/components/dashboard-page.d.vue.ts +53 -0
  46. package/dist/runtime/dashboard/components/dashboard-page.vue +156 -0
  47. package/dist/runtime/dashboard/components/dashboard-page.vue.d.ts +53 -0
  48. package/dist/runtime/dashboard/components/dashboard-paired-bars.vue +4 -4
  49. package/dist/runtime/dashboard/components/dashboard-refresh.d.vue.ts +1 -1
  50. package/dist/runtime/dashboard/components/dashboard-refresh.vue +1 -0
  51. package/dist/runtime/dashboard/components/dashboard-refresh.vue.d.ts +1 -1
  52. package/dist/runtime/dashboard/components/dashboard-stack-bar.vue +4 -4
  53. package/dist/runtime/dashboard/components/dashboard-stat.d.vue.ts +14 -2
  54. package/dist/runtime/dashboard/components/dashboard-stat.vue +28 -10
  55. package/dist/runtime/dashboard/components/dashboard-stat.vue.d.ts +14 -2
  56. package/dist/runtime/dashboard/components/dashboard-stats.vue +3 -3
  57. package/dist/runtime/dashboard/components/dashboard-table.d.vue.ts +1 -1
  58. package/dist/runtime/dashboard/components/dashboard-table.vue +3 -3
  59. package/dist/runtime/dashboard/components/dashboard-table.vue.d.ts +1 -1
  60. package/dist/runtime/dashboard/components/dashboard-tabs.d.vue.ts +1 -1
  61. package/dist/runtime/dashboard/components/dashboard-tabs.vue.d.ts +1 -1
  62. package/dist/runtime/dashboard/components/dashboard-total.d.vue.ts +7 -2
  63. package/dist/runtime/dashboard/components/dashboard-total.vue +10 -2
  64. package/dist/runtime/dashboard/components/dashboard-total.vue.d.ts +7 -2
  65. package/dist/runtime/dashboard/components/dashboard-view-tabs.d.vue.ts +33 -0
  66. package/dist/runtime/dashboard/components/dashboard-view-tabs.vue +66 -0
  67. package/dist/runtime/dashboard/components/dashboard-view-tabs.vue.d.ts +33 -0
  68. package/dist/runtime/dashboard/components/dashboard-widget.vue +1 -1
  69. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.d.vue.ts +44 -0
  70. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue +220 -0
  71. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue.d.ts +44 -0
  72. package/dist/runtime/dashboard/composables/use-dashboard-api.d.ts +6 -1
  73. package/dist/runtime/dashboard/composables/use-dashboard-api.js +29 -6
  74. package/dist/runtime/dashboard/composables/use-dashboard-block.d.ts +5 -4
  75. package/dist/runtime/dashboard/composables/use-dashboard-block.js +32 -15
  76. package/dist/runtime/dashboard/composables/use-dashboard-chart.d.ts +8 -1
  77. package/dist/runtime/dashboard/composables/use-dashboard-chart.js +16 -4
  78. package/dist/runtime/dashboard/composables/use-dashboard-context.d.ts +50 -0
  79. package/dist/runtime/dashboard/composables/use-dashboard-context.js +56 -0
  80. package/dist/runtime/dashboard/composables/use-dashboard-derived.js +6 -1
  81. package/dist/runtime/dashboard/composables/use-dashboard-filter-control.d.ts +16 -0
  82. package/dist/runtime/dashboard/composables/use-dashboard-filter-control.js +161 -0
  83. package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.d.ts +37 -0
  84. package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.js +107 -0
  85. package/dist/runtime/dashboard/composables/use-dashboard-format.d.ts +46 -6
  86. package/dist/runtime/dashboard/composables/use-dashboard-format.js +51 -8
  87. package/dist/runtime/dashboard/composables/use-dashboard-options.d.ts +11 -4
  88. package/dist/runtime/dashboard/composables/use-dashboard-options.js +33 -47
  89. package/dist/runtime/dashboard/composables/use-dashboard-remote-options.d.ts +8 -5
  90. package/dist/runtime/dashboard/composables/use-dashboard-remote-options.js +59 -70
  91. package/dist/runtime/dashboard/composables/use-dashboard-resource.d.ts +15 -4
  92. package/dist/runtime/dashboard/composables/use-dashboard-resource.js +52 -17
  93. package/dist/runtime/dashboard/composables/use-dashboard-scope.d.ts +10 -7
  94. package/dist/runtime/dashboard/composables/use-dashboard-scope.js +26 -16
  95. package/dist/runtime/dashboard/composables/use-dashboard-series-picker.d.ts +20 -0
  96. package/dist/runtime/dashboard/composables/use-dashboard-series-picker.js +30 -0
  97. package/dist/runtime/dashboard/composables/use-dashboard-time.d.ts +2 -0
  98. package/dist/runtime/dashboard/composables/use-dashboard-time.js +4 -1
  99. package/dist/runtime/dashboard/composables/use-dashboard-ui.d.ts +12 -2
  100. package/dist/runtime/dashboard/composables/use-dashboard-ui.js +3 -0
  101. package/dist/runtime/dashboard/composables/use-dashboard-views.d.ts +15 -3
  102. package/dist/runtime/dashboard/composables/use-dashboard-views.js +33 -10
  103. package/dist/runtime/dashboard/composables/use-dashboard.d.ts +18 -12
  104. package/dist/runtime/dashboard/composables/use-dashboard.js +98 -9
  105. package/dist/runtime/dashboard/index.d.ts +3 -1
  106. package/dist/runtime/dashboard/index.js +3 -1
  107. package/dist/runtime/dashboard/schema/index.d.ts +62 -30
  108. package/dist/runtime/dashboard/schema/index.js +3 -0
  109. package/dist/runtime/dashboard/types/blocks.d.ts +30 -4
  110. package/dist/runtime/dashboard/types/charts.d.ts +2 -2
  111. package/dist/runtime/dashboard/types/controls.d.ts +123 -0
  112. package/dist/runtime/dashboard/types/filters.d.ts +236 -0
  113. package/dist/runtime/dashboard/types/index.d.ts +3 -2
  114. package/dist/runtime/dashboard/types/page.d.ts +17 -0
  115. package/dist/runtime/dashboard/types/page.js +0 -0
  116. package/dist/runtime/dashboard/types/resource.d.ts +66 -28
  117. package/dist/runtime/dashboard/types/runtime.d.ts +39 -8
  118. package/dist/runtime/dashboard/types/schema.d.ts +94 -54
  119. package/dist/runtime/dashboard/types/ui.d.ts +78 -0
  120. package/dist/runtime/dashboard/utils/builders/dashboard-filters.d.ts +142 -0
  121. package/dist/runtime/dashboard/utils/builders/dashboard-filters.js +135 -0
  122. package/dist/runtime/dashboard/utils/charts.d.ts +4 -15
  123. package/dist/runtime/dashboard/utils/charts.js +26 -28
  124. package/dist/runtime/dashboard/utils/{params/codecs.d.ts → codecs.d.ts} +2 -2
  125. package/dist/runtime/dashboard/utils/{params/codecs.js → codecs.js} +1 -1
  126. package/dist/runtime/dashboard/utils/environment.d.ts +36 -0
  127. package/dist/runtime/dashboard/utils/environment.js +30 -0
  128. package/dist/runtime/dashboard/utils/filters.d.ts +44 -0
  129. package/dist/runtime/dashboard/utils/filters.js +62 -0
  130. package/dist/runtime/dashboard/utils/format.d.ts +25 -0
  131. package/dist/runtime/dashboard/utils/format.js +66 -0
  132. package/dist/runtime/dashboard/utils/grid.d.ts +17 -0
  133. package/dist/runtime/dashboard/utils/grid.js +14 -0
  134. package/dist/runtime/dashboard/utils/options.d.ts +3 -1
  135. package/dist/runtime/dashboard/utils/options.js +6 -0
  136. package/dist/runtime/dashboard/utils/remote.d.ts +7 -0
  137. package/dist/runtime/dashboard/utils/remote.js +14 -0
  138. package/dist/runtime/dashboard/utils/resource.d.ts +16 -7
  139. package/dist/runtime/dashboard/utils/resource.js +15 -9
  140. package/dist/runtime/dashboard/utils/schema.d.ts +8 -3
  141. package/dist/runtime/dashboard/utils/schema.js +9 -4
  142. package/dist/runtime/dashboard/utils/state.d.ts +11 -6
  143. package/dist/runtime/dashboard/utils/state.js +10 -5
  144. package/dist/runtime/dashboard/utils/time.d.ts +2 -0
  145. package/dist/runtime/dashboard/utils/time.js +11 -1
  146. package/dist/runtime/dashboard/utils/ui.d.ts +1 -1
  147. package/dist/runtime/dashboard/utils/ui.js +1 -1
  148. package/dist/runtime/form/components/root/form.vue +1 -1
  149. package/dist/runtime/form/fields/card-selection.d.ts +1 -0
  150. package/dist/runtime/form/fields/card-selection.js +1 -0
  151. package/dist/runtime/form/fields/checkbox-card/component.vue +3 -1
  152. package/dist/runtime/form/fields/checkbox-group/component.vue +5 -0
  153. package/dist/runtime/form/fields/radio/component.vue +10 -0
  154. package/dist/runtime/form/fields/radio-card/component.vue +3 -1
  155. package/dist/runtime/form/types/options.d.ts +1 -11
  156. package/dist/runtime/form/utils/focus.js +1 -1
  157. package/dist/runtime/i18n/locales/en.js +29 -0
  158. package/dist/runtime/i18n/locales/fr.js +29 -0
  159. package/dist/runtime/i18n/types.d.ts +41 -0
  160. package/dist/runtime/shared/styles/tokens.css +1 -1
  161. package/dist/runtime/shared/types/query.d.ts +8 -0
  162. package/dist/runtime/table/types/index.d.ts +1 -0
  163. package/dist/runtime/table/types/remote-options.d.ts +64 -0
  164. package/dist/runtime/table/types/remote-options.js +0 -0
  165. package/dist/runtime/table/types/source.d.ts +10 -1
  166. package/dist/runtime/table/utils/builders/table-source.d.ts +2 -6
  167. package/dist/runtime/table/utils/index.d.ts +1 -0
  168. package/dist/runtime/table/utils/index.js +1 -0
  169. package/dist/runtime/table/utils/remote-table-options.d.ts +26 -0
  170. package/dist/runtime/table/utils/remote-table-options.js +88 -0
  171. package/package.json +4 -1
  172. package/dist/runtime/dashboard/composables/use-dashboard-param-scope.d.ts +0 -30
  173. package/dist/runtime/dashboard/composables/use-dashboard-param-scope.js +0 -71
  174. package/dist/runtime/dashboard/types/options.d.ts +0 -46
  175. package/dist/runtime/dashboard/types/params.d.ts +0 -115
  176. package/dist/runtime/dashboard/utils/builders/dashboard-params.d.ts +0 -85
  177. package/dist/runtime/dashboard/utils/builders/dashboard-params.js +0 -87
  178. /package/dist/runtime/dashboard/types/{options.js → controls.js} +0 -0
  179. /package/dist/runtime/dashboard/types/{params.js → filters.js} +0 -0
@@ -12,19 +12,26 @@ import { useDashboardGridContext, useDashboardUi } from "../composables/use-dash
12
12
  import { downloadDashboardFile, resolveDashboardFileName, toDashboardCsv } from "../utils/export";
13
13
  import { resolveDashboardClasses } from "../utils/ui";
14
14
  import DashboardBlockState from "./block/dashboard-block-state.vue";
15
+ import DashboardChips from "./block/dashboard-chips.vue";
15
16
  import DashboardDataTableView from "./block/dashboard-data-table.vue";
16
17
  import DashboardSkeleton from "./block/dashboard-skeleton.vue";
17
18
  import DashboardLegend from "./dashboard-legend.vue";
19
+ const HEADER_LINK = {
20
+ class: "h-auto p-0 font-medium",
21
+ color: "neutral",
22
+ trailingIcon: "i-lucide-chevron-right",
23
+ variant: "link"
24
+ };
18
25
  const props = defineProps({
19
26
  title: { type: [String, Number, Function], required: false },
20
27
  subtitle: { type: [String, Number, Function], required: false },
21
28
  size: { type: String, required: false },
22
- rows: { type: String, required: false },
23
29
  card: { type: Boolean, required: false, default: true },
24
30
  activation: { type: String, required: false },
25
31
  empty: { type: Object, required: false },
26
32
  menu: { type: [Boolean, Array, Function], required: false, default: void 0 },
27
33
  actions: { type: Array, required: false },
34
+ filters: { type: Array, required: false },
28
35
  freshness: { type: Boolean, required: false, default: void 0 },
29
36
  ui: { type: Object, required: false },
30
37
  source: { type: Object, required: false },
@@ -43,7 +50,6 @@ const block = useDashboardBlock({
43
50
  activation: () => props.activation,
44
51
  empty: () => props.isEmpty,
45
52
  root,
46
- rows: () => props.rows,
47
53
  size: () => props.size,
48
54
  source: () => props.source
49
55
  });
@@ -84,7 +90,7 @@ const title = computed(() => resolveTextValue(props.title));
84
90
  const subtitle = computed(() => resolveTextValue(props.subtitle));
85
91
  const phase = computed(() => block.phase.value);
86
92
  const pending = computed(() => phase.value === "loading" || phase.value === "idle");
87
- const busy = computed(() => phase.value === "loading" || block.refreshing.value);
93
+ const busy = computed(() => phase.value === "loading" || block.fetching.value);
88
94
  const builtInActions = ["table", "csv", "expand"];
89
95
  const tableView = shallowRef(false);
90
96
  const expanded = shallowRef(false);
@@ -112,10 +118,13 @@ const actionButtons = computed(() => {
112
118
  const footer = [];
113
119
  for (const { placement, ...button } of props.actions ?? []) {
114
120
  if (placement === "footer") footer.push(button);
115
- else header.push(button);
121
+ else header.push(isPlainLink(button) ? { ...HEADER_LINK, ...button } : button);
116
122
  }
117
123
  return { footer, header };
118
124
  });
125
+ function isPlainLink(button) {
126
+ return button.to !== void 0 && button.variant === void 0 && button.icon === void 0 && button.trailingIcon === void 0;
127
+ }
119
128
  const showTable = computed(
120
129
  () => tableView.value && props.viewAsTable && phase.value === "content" && props.tabulate !== void 0
121
130
  );
@@ -172,6 +181,15 @@ const updatedAt = computed(() => {
172
181
  const freshness = props.freshness ?? grid?.freshness.value ?? false;
173
182
  return freshness && phase.value === "content" ? props.source?.updatedAt : void 0;
174
183
  });
184
+ const filterChips = computed(
185
+ () => (props.filters ?? []).filter((filter) => filter.enabled && filter.changed).map((filter) => ({
186
+ key: filter.key,
187
+ label: filter.display,
188
+ prefix: filter.label,
189
+ remove: () => filter.reset(),
190
+ removeLabel: t("dashboard.filters.clear", { label: filter.label })
191
+ }))
192
+ );
175
193
  const hasHeader = computed(
176
194
  () => Boolean(
177
195
  title.value || subtitle.value || props.legend?.length || slots["header-right"] || actionButtons.value.header.length || menuItems.value.length
@@ -181,6 +199,7 @@ const hasHeader = computed(
181
199
 
182
200
  <template>
183
201
  <section
202
+ v-if="!block.hidden.value"
184
203
  ref="root"
185
204
  :style="block.style.value"
186
205
  :data-phase="phase"
@@ -189,8 +208,9 @@ const hasHeader = computed(
189
208
  :class="classes.root"
190
209
  >
191
210
  <div
192
- v-if="block.refreshing.value"
211
+ v-if="block.fetching.value"
193
212
  aria-hidden="true"
213
+ data-progress
194
214
  class="pointer-events-none absolute inset-x-0 top-0 h-0.5 overflow-hidden"
195
215
  >
196
216
  <div class="nut-dash-progress h-full w-1/3 rounded-full bg-primary" />
@@ -240,7 +260,8 @@ const hasHeader = computed(
240
260
  </UDropdownMenu>
241
261
  </header>
242
262
 
243
- <div v-if="$slots.toolbar" :class="classes.toolbar">
263
+ <div v-if="$slots.toolbar || filterChips.length" :class="classes.toolbar">
264
+ <DashboardChips v-if="filterChips.length" :chips="filterChips" />
244
265
  <slot name="toolbar" />
245
266
  </div>
246
267
 
@@ -255,6 +276,7 @@ const hasHeader = computed(
255
276
  v-else-if="phase === 'error' || phase === 'empty'"
256
277
  :kind="phase"
257
278
  :empty
279
+ :retrying="block.fetching.value"
258
280
  @retry="block.retry"
259
281
  />
260
282
  <div v-else aria-hidden="true" :class="phase === 'loading' && 'nut-dash-shimmer'">
@@ -1,5 +1,5 @@
1
1
  import type { LazyTextValue } from '#ui-tools/shared/types/utils';
2
- import type { DashboardAxisOptions, DashboardBlockBaseProps, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardSourceLike, DashboardValueFormat } from '../types/index.js';
2
+ import type { DashboardAxisOptions, DashboardBlockBaseProps, DashboardChartTotals, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardSourceLike, DashboardValueFormat } from '../types/index.js';
3
3
  declare const __VLS_export: <TRow>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
4
  props: import("vue").PublicProps & __VLS_PrettifyLocal<DashboardBlockBaseProps & {
5
5
  source: DashboardSourceLike<readonly TRow[] | undefined>;
@@ -27,6 +27,11 @@ declare const __VLS_export: <TRow>(__VLS_props: NonNullable<Awaited<typeof __VLS
27
27
  selected?: DashboardSelected<TRow>;
28
28
  /** Prints each group's value above its bars (the stack total when `stacked`). */
29
29
  labels?: boolean;
30
+ /**
31
+ * Footer totals of the solid series, formatted like their axis: `true` / `'sum'` adds each
32
+ * series up, `'average'` averages it. Footer slot content follows them.
33
+ */
34
+ totals?: DashboardChartTotals;
30
35
  /** A click on the chart selects the x position under the pointer. */
31
36
  onSelect?: (event: DashboardSelectEvent<TRow>) => void;
32
37
  }> & (typeof globalThis extends {
@@ -8,6 +8,7 @@ import {
8
8
  import DashboardSkeleton from "./block/dashboard-skeleton.vue";
9
9
  import { dashboardChartRenderer } from "./charts/renderer";
10
10
  import DashboardCard from "./dashboard-card.vue";
11
+ import DashboardTotal from "./dashboard-total.vue";
11
12
  const {
12
13
  source,
13
14
  card = true,
@@ -27,18 +28,19 @@ const {
27
28
  highlight,
28
29
  selected,
29
30
  labels = false,
31
+ totals,
30
32
  onSelect,
31
33
  ...block
32
34
  } = defineProps({
33
35
  title: { type: [String, Number, Function], required: false },
34
36
  subtitle: { type: [String, Number, Function], required: false },
35
37
  size: { type: String, required: false },
36
- rows: { type: String, required: false },
37
38
  card: { type: Boolean, required: false },
38
39
  activation: { type: String, required: false },
39
40
  empty: { type: Object, required: false },
40
41
  menu: { type: [Boolean, Array, Function], required: false },
41
42
  actions: { type: Array, required: false },
43
+ filters: { type: Array, required: false },
42
44
  freshness: { type: Boolean, required: false },
43
45
  ui: { type: Object, required: false },
44
46
  source: { type: Object, required: true },
@@ -48,7 +50,7 @@ const {
48
50
  series: { type: Array, required: true },
49
51
  yAxis: { type: Object, required: false },
50
52
  y2Axis: { type: Object, required: false },
51
- format: { type: Function, required: false },
53
+ format: { type: [String, Function], required: false, skipCheck: true },
52
54
  reference: { type: [Object, Array], required: false },
53
55
  height: { type: Number, required: false },
54
56
  legend: { type: Boolean, required: false },
@@ -56,6 +58,7 @@ const {
56
58
  highlight: { type: [String, Function], required: false },
57
59
  selected: { type: Function, required: false },
58
60
  labels: { type: Boolean, required: false },
61
+ totals: { type: [Boolean, String], required: false },
59
62
  onSelect: { type: Function, required: false }
60
63
  });
61
64
  defineSlots();
@@ -66,6 +69,7 @@ const skeletonSeries = computed(
66
69
  );
67
70
  const skeletonPoints = computed(() => source.data?.length || points);
68
71
  const chart = useDashboardChart({
72
+ totals: () => totals,
69
73
  defaultType: "bar",
70
74
  format: () => format,
71
75
  highlight: () => highlight,
@@ -109,7 +113,13 @@ const chart = useDashboardChart({
109
113
  <template v-if="$slots.toolbar" #toolbar>
110
114
  <slot name="toolbar" />
111
115
  </template>
112
- <template v-if="$slots.footer" #footer>
116
+ <template v-if="$slots.footer || chart.totals.value.length" #footer>
117
+ <DashboardTotal
118
+ v-for="total in chart.totals.value"
119
+ :key="total.key"
120
+ :label="total.label"
121
+ :value="total.text"
122
+ />
113
123
  <slot name="footer" />
114
124
  </template>
115
125
 
@@ -1,5 +1,5 @@
1
1
  import type { LazyTextValue } from '#ui-tools/shared/types/utils';
2
- import type { DashboardAxisOptions, DashboardBlockBaseProps, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardSourceLike, DashboardValueFormat } from '../types/index.js';
2
+ import type { DashboardAxisOptions, DashboardBlockBaseProps, DashboardChartTotals, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardSourceLike, DashboardValueFormat } from '../types/index.js';
3
3
  declare const __VLS_export: <TRow>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
4
  props: import("vue").PublicProps & __VLS_PrettifyLocal<DashboardBlockBaseProps & {
5
5
  source: DashboardSourceLike<readonly TRow[] | undefined>;
@@ -27,6 +27,11 @@ declare const __VLS_export: <TRow>(__VLS_props: NonNullable<Awaited<typeof __VLS
27
27
  selected?: DashboardSelected<TRow>;
28
28
  /** Prints each group's value above its bars (the stack total when `stacked`). */
29
29
  labels?: boolean;
30
+ /**
31
+ * Footer totals of the solid series, formatted like their axis: `true` / `'sum'` adds each
32
+ * series up, `'average'` averages it. Footer slot content follows them.
33
+ */
34
+ totals?: DashboardChartTotals;
30
35
  /** A click on the chart selects the x position under the pointer. */
31
36
  onSelect?: (event: DashboardSelectEvent<TRow>) => void;
32
37
  }> & (typeof globalThis extends {
@@ -40,12 +40,12 @@ const {
40
40
  title: { type: [String, Number, Function], required: false },
41
41
  subtitle: { type: [String, Number, Function], required: false },
42
42
  size: { type: String, required: false },
43
- rows: { type: String, required: false },
44
43
  card: { type: Boolean, required: false },
45
44
  activation: { type: String, required: false },
46
45
  empty: { type: Object, required: false },
47
46
  menu: { type: [Boolean, Array, Function], required: false },
48
47
  actions: { type: Array, required: false },
48
+ filters: { type: Array, required: false },
49
49
  freshness: { type: Boolean, required: false },
50
50
  source: { type: Object, required: true },
51
51
  label: { type: Function, required: true },
@@ -100,7 +100,7 @@ const segments = computed(() => {
100
100
  selected: picked[index] ?? false,
101
101
  share,
102
102
  swatch: base,
103
- text: text ? resolveTextValue(text(row, share)) : formats.percent.value(share),
103
+ text: text ? resolveTextValue(text(row, share)) : formats.percent(share),
104
104
  value: amount
105
105
  };
106
106
  });
@@ -109,7 +109,7 @@ const padAngle = computed(() => gap / Math.max(1, (diameter - thickness) / 2));
109
109
  const centerText = computed(() => {
110
110
  if (!center) return "";
111
111
  const resolved = center(rows.value);
112
- return isNumber(resolved) ? formats.number.value(resolved) : resolveTextValue(resolved);
112
+ return isNumber(resolved) ? formats.number(resolved) : resolveTextValue(resolved);
113
113
  });
114
114
  function select(index) {
115
115
  const segment = segments.value[index];
@@ -124,8 +124,8 @@ function tabulate() {
124
124
  ],
125
125
  rows: segments.value.map((segment) => [
126
126
  toDashboardCell(segment.label),
127
- toDashboardCell(segment.value, formats.number.value(segment.value)),
128
- toDashboardCell(Math.round(segment.share * 10) / 10, formats.percent.value(segment.share))
127
+ toDashboardCell(segment.value, formats.number(segment.value)),
128
+ toDashboardCell(Math.round(segment.share * 10) / 10, formats.percent(segment.share))
129
129
  ])
130
130
  };
131
131
  }
@@ -40,12 +40,12 @@ const {
40
40
  title: { type: [String, Number, Function], required: false },
41
41
  subtitle: { type: [String, Number, Function], required: false },
42
42
  size: { type: String, required: false },
43
- rows: { type: String, required: false },
44
43
  card: { type: Boolean, required: false },
45
44
  activation: { type: String, required: false },
46
45
  empty: { type: Object, required: false },
47
46
  menu: { type: [Boolean, Array, Function], required: false },
48
47
  actions: { type: Array, required: false },
48
+ filters: { type: Array, required: false },
49
49
  freshness: { type: Boolean, required: false },
50
50
  source: { type: Object, required: true },
51
51
  label: { type: Function, required: true },
@@ -0,0 +1,67 @@
1
+ import type { DashboardFilterControl, DashboardFilterUi, DashboardOption, DashboardOptionValue } from '../types/index.js';
2
+ declare const __VLS_export: <TValue, TItem extends DashboardOptionValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<{
4
+ filter: DashboardFilterControl<TValue, TItem>;
5
+ variant?: "pill" | "button";
6
+ /** Name on the pill, or the text of the button. Defaults to the filter label. */
7
+ label?: string;
8
+ /** Leading icon of the trigger. */
9
+ icon?: string;
10
+ /** An active pill shows a button restoring the default value. Defaults to `true`. */
11
+ clearable?: boolean;
12
+ /** Menu alignment against the trigger. Defaults to `start` for pills, `end` for buttons. */
13
+ align?: "start" | "center" | "end";
14
+ /**
15
+ * What the menu lists: options and presets (default), the options only, or the presets only (a
16
+ * "Presets" button next to the filter).
17
+ */
18
+ list?: "all" | "options" | "presets";
19
+ ui?: DashboardFilterUi;
20
+ }> & (typeof globalThis extends {
21
+ __VLS_PROPS_FALLBACK: infer P;
22
+ } ? P : {});
23
+ expose: (exposed: {}) => void;
24
+ attrs: any;
25
+ slots: {
26
+ /** Replaces the whole trigger. The menu still opens from it. */
27
+ trigger?: (props: {
28
+ filter: DashboardFilterControl<TValue, TItem>;
29
+ active: boolean;
30
+ display: string;
31
+ }) => unknown;
32
+ /** Replaces the name and value inside the pill. */
33
+ label?: (props: {
34
+ filter: DashboardFilterControl<TValue, TItem>;
35
+ display: string;
36
+ }) => unknown;
37
+ /** Replaces the content of each menu row. */
38
+ item?: (props: {
39
+ item: DashboardOption<TItem>;
40
+ selected: boolean;
41
+ disabled: boolean;
42
+ filter: DashboardFilterControl<TValue, TItem>;
43
+ }) => unknown;
44
+ /** Content above the option list. */
45
+ header?: (props: {
46
+ filter: DashboardFilterControl<TValue, TItem>;
47
+ }) => unknown;
48
+ /** Content below the option list (presets, actions). */
49
+ footer?: (props: {
50
+ filter: DashboardFilterControl<TValue, TItem>;
51
+ }) => unknown;
52
+ /** Replaces "No results". */
53
+ empty?: (props: {
54
+ filter: DashboardFilterControl<TValue, TItem>;
55
+ }) => unknown;
56
+ };
57
+ emit: {};
58
+ }>) => import("vue").VNode & {
59
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
60
+ };
61
+ declare const _default: typeof __VLS_export;
62
+ export default _default;
63
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
64
+ [K in keyof T]: T[K];
65
+ } : {
66
+ [K in keyof T as K]: T[K];
67
+ }) & {};
@@ -0,0 +1,134 @@
1
+ <script setup>
2
+ import UIcon from "@nuxt/ui/components/Icon.vue";
3
+ import UPopover from "@nuxt/ui/components/Popover.vue";
4
+ import { createReusableTemplate } from "@vueuse/core";
5
+ import { computed, shallowRef, watch } from "vue";
6
+ import { useUiToolsLocale } from "#ui-tools/i18n";
7
+ import { useDashboardUi } from "../composables/use-dashboard-ui";
8
+ import { DASHBOARD_FILTER_CLASSES, hasDashboardFilterMenu } from "../utils/filters";
9
+ import { resolveDashboardClasses } from "../utils/ui";
10
+ import DashboardFilterMenu from "./filter/dashboard-filter-menu.vue";
11
+ const {
12
+ filter,
13
+ variant = "pill",
14
+ label,
15
+ icon,
16
+ clearable = true,
17
+ align,
18
+ list = "all",
19
+ ui
20
+ } = defineProps({
21
+ filter: { type: Object, required: true },
22
+ variant: { type: String, required: false },
23
+ label: { type: String, required: false },
24
+ icon: { type: String, required: false },
25
+ clearable: { type: Boolean, required: false },
26
+ align: { type: String, required: false },
27
+ list: { type: String, required: false },
28
+ ui: { type: Object, required: false }
29
+ });
30
+ defineSlots();
31
+ const { t } = useUiToolsLocale();
32
+ const appUi = useDashboardUi();
33
+ const [DefineMenu, ReuseMenu] = createReusableTemplate();
34
+ const classes = computed(
35
+ () => resolveDashboardClasses(DASHBOARD_FILTER_CLASSES, appUi.value.filter, ui)
36
+ );
37
+ const name = computed(() => label ?? filter.label);
38
+ const active = computed(() => variant === "pill" && filter.changed);
39
+ const listed = computed(() => hasDashboardFilterMenu(filter));
40
+ const content = computed(() => ({
41
+ align: align ?? (variant === "button" ? "end" : "start"),
42
+ side: "bottom",
43
+ sideOffset: 6
44
+ }));
45
+ const open = shallowRef(false);
46
+ watch(open, (value) => {
47
+ filter.open = value;
48
+ });
49
+ function close() {
50
+ open.value = false;
51
+ }
52
+ </script>
53
+
54
+ <template>
55
+ <DefineMenu v-slot="{ title }">
56
+ <DashboardFilterMenu :filter :classes :title :list @picked="close">
57
+ <template v-if="$slots.item" #item="slotProps">
58
+ <slot name="item" v-bind="slotProps" />
59
+ </template>
60
+ <template v-if="$slots.header" #header="slotProps">
61
+ <slot name="header" v-bind="slotProps" />
62
+ </template>
63
+ <template v-if="$slots.footer" #footer="slotProps">
64
+ <slot name="footer" v-bind="slotProps" />
65
+ </template>
66
+ <template v-if="$slots.empty" #empty="slotProps">
67
+ <slot name="empty" v-bind="slotProps" />
68
+ </template>
69
+ </DashboardFilterMenu>
70
+ </DefineMenu>
71
+
72
+ <UPopover
73
+ v-if="variant === 'button'"
74
+ v-model:open="open"
75
+ :content
76
+ :ui="{ content: classes.content }"
77
+ >
78
+ <slot name="trigger" :filter :active :display="filter.display">
79
+ <button type="button" :class="classes.button" data-dashboard-filter-button>
80
+ <UIcon v-if="icon" :name="icon" class="size-3.5 flex-none" />
81
+ {{ name }}
82
+ </button>
83
+ </slot>
84
+ <template #content>
85
+ <ReuseMenu :title="list === 'presets' ? t('dashboard.filters.presets') : filter.label" />
86
+ </template>
87
+ </UPopover>
88
+
89
+ <span
90
+ v-else
91
+ :class="classes.root"
92
+ :data-active="active || void 0"
93
+ :data-dashboard-filter="filter.key"
94
+ >
95
+ <UPopover v-if="listed" v-model:open="open" :content :ui="{ content: classes.content }">
96
+ <slot name="trigger" :filter :active :display="filter.display">
97
+ <button type="button" :class="classes.trigger" data-dashboard-filter-trigger>
98
+ <UIcon v-if="icon" :name="icon" class="size-3.5 flex-none text-muted" />
99
+ <slot name="label" :filter :display="filter.display">
100
+ <span :class="classes.label">{{ name }}</span>
101
+ <span :class="classes.value">{{ filter.display }}</span>
102
+ </slot>
103
+ <UIcon
104
+ v-if="!active || !clearable"
105
+ name="i-lucide-chevron-down"
106
+ :class="classes.chevron"
107
+ />
108
+ </button>
109
+ </slot>
110
+ <template #content>
111
+ <ReuseMenu />
112
+ </template>
113
+ </UPopover>
114
+ <slot v-else name="trigger" :filter :active :display="filter.display">
115
+ <span :class="classes.trigger">
116
+ <UIcon v-if="icon" :name="icon" class="size-3.5 flex-none text-muted" />
117
+ <slot name="label" :filter :display="filter.display">
118
+ <span :class="classes.label">{{ name }}</span>
119
+ <span :class="classes.value">{{ filter.display }}</span>
120
+ </slot>
121
+ </span>
122
+ </slot>
123
+ <button
124
+ v-if="active && clearable"
125
+ type="button"
126
+ :class="classes.clear"
127
+ :aria-label="t('dashboard.filters.clear', { label: name })"
128
+ data-dashboard-filter-clear
129
+ @click="filter.reset()"
130
+ >
131
+ <UIcon name="i-lucide-x" class="size-3" />
132
+ </button>
133
+ </span>
134
+ </template>
@@ -0,0 +1,67 @@
1
+ import type { DashboardFilterControl, DashboardFilterUi, DashboardOption, DashboardOptionValue } from '../types/index.js';
2
+ declare const __VLS_export: <TValue, TItem extends DashboardOptionValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<{
4
+ filter: DashboardFilterControl<TValue, TItem>;
5
+ variant?: "pill" | "button";
6
+ /** Name on the pill, or the text of the button. Defaults to the filter label. */
7
+ label?: string;
8
+ /** Leading icon of the trigger. */
9
+ icon?: string;
10
+ /** An active pill shows a button restoring the default value. Defaults to `true`. */
11
+ clearable?: boolean;
12
+ /** Menu alignment against the trigger. Defaults to `start` for pills, `end` for buttons. */
13
+ align?: "start" | "center" | "end";
14
+ /**
15
+ * What the menu lists: options and presets (default), the options only, or the presets only (a
16
+ * "Presets" button next to the filter).
17
+ */
18
+ list?: "all" | "options" | "presets";
19
+ ui?: DashboardFilterUi;
20
+ }> & (typeof globalThis extends {
21
+ __VLS_PROPS_FALLBACK: infer P;
22
+ } ? P : {});
23
+ expose: (exposed: {}) => void;
24
+ attrs: any;
25
+ slots: {
26
+ /** Replaces the whole trigger. The menu still opens from it. */
27
+ trigger?: (props: {
28
+ filter: DashboardFilterControl<TValue, TItem>;
29
+ active: boolean;
30
+ display: string;
31
+ }) => unknown;
32
+ /** Replaces the name and value inside the pill. */
33
+ label?: (props: {
34
+ filter: DashboardFilterControl<TValue, TItem>;
35
+ display: string;
36
+ }) => unknown;
37
+ /** Replaces the content of each menu row. */
38
+ item?: (props: {
39
+ item: DashboardOption<TItem>;
40
+ selected: boolean;
41
+ disabled: boolean;
42
+ filter: DashboardFilterControl<TValue, TItem>;
43
+ }) => unknown;
44
+ /** Content above the option list. */
45
+ header?: (props: {
46
+ filter: DashboardFilterControl<TValue, TItem>;
47
+ }) => unknown;
48
+ /** Content below the option list (presets, actions). */
49
+ footer?: (props: {
50
+ filter: DashboardFilterControl<TValue, TItem>;
51
+ }) => unknown;
52
+ /** Replaces "No results". */
53
+ empty?: (props: {
54
+ filter: DashboardFilterControl<TValue, TItem>;
55
+ }) => unknown;
56
+ };
57
+ emit: {};
58
+ }>) => import("vue").VNode & {
59
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
60
+ };
61
+ declare const _default: typeof __VLS_export;
62
+ export default _default;
63
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
64
+ [K in keyof T]: T[K];
65
+ } : {
66
+ [K in keyof T as K]: T[K];
67
+ }) & {};
@@ -0,0 +1,49 @@
1
+ import type { DashboardFilterControl, DashboardFilterKeysOf, DashboardFiltersTarget, DashboardFiltersUi, DashboardOption, DashboardOptionValue } from '../types/index.js';
2
+ declare const __VLS_export: <TTarget extends DashboardFiltersTarget>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<{
4
+ dashboard: TTarget;
5
+ /** Shows these filters only, in this order. */
6
+ only?: readonly (DashboardFilterKeysOf<TTarget> & string)[];
7
+ /** Hides these filters. */
8
+ exclude?: readonly (DashboardFilterKeysOf<TTarget> & string)[];
9
+ /** Shows "Reset" once a filter differs from its default. Defaults to `true`. */
10
+ reset?: boolean;
11
+ ui?: DashboardFiltersUi;
12
+ }> & (typeof globalThis extends {
13
+ __VLS_PROPS_FALLBACK: infer P;
14
+ } ? P : {});
15
+ expose: (exposed: {}) => void;
16
+ attrs: any;
17
+ slots: { [TKey in DashboardFilterKeysOf<TTarget> & string]?: ((props: {
18
+ filter: DashboardFilterControl;
19
+ }) => unknown) | undefined; } & {
20
+ /** Renders every filter that has no slot of its own. */
21
+ filter?: (props: {
22
+ filter: DashboardFilterControl;
23
+ }) => unknown;
24
+ /** Content of the menu rows of every pill. */
25
+ item?: (props: {
26
+ item: DashboardOption<DashboardOptionValue>;
27
+ selected: boolean;
28
+ disabled: boolean;
29
+ filter: DashboardFilterControl;
30
+ }) => unknown;
31
+ /** Replaces the "Reset" button. */
32
+ reset?: (props: {
33
+ filtered: boolean;
34
+ reset: () => void;
35
+ }) => unknown;
36
+ leading?: () => unknown;
37
+ trailing?: () => unknown;
38
+ };
39
+ emit: {};
40
+ }>) => import("vue").VNode & {
41
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
42
+ };
43
+ declare const _default: typeof __VLS_export;
44
+ export default _default;
45
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
46
+ [K in keyof T]: T[K];
47
+ } : {
48
+ [K in keyof T as K]: T[K];
49
+ }) & {};