nuxt-ui-tools 1.1.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 (213) 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 +6 -3
  14. package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue.d.ts +1 -1
  15. package/dist/runtime/dashboard/components/block/dashboard-view-scope.d.vue.ts +21 -0
  16. package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue +12 -0
  17. package/dist/runtime/dashboard/components/block/dashboard-view-scope.vue.d.ts +21 -0
  18. package/dist/runtime/dashboard/components/dashboard-alerts.vue +3 -3
  19. package/dist/runtime/dashboard/components/dashboard-bar-chart.d.vue.ts +14 -3
  20. package/dist/runtime/dashboard/components/dashboard-bar-chart.vue +30 -9
  21. package/dist/runtime/dashboard/components/dashboard-bar-chart.vue.d.ts +14 -3
  22. package/dist/runtime/dashboard/components/dashboard-bars.vue +4 -4
  23. package/dist/runtime/dashboard/components/dashboard-card.vue +28 -6
  24. package/dist/runtime/dashboard/components/dashboard-combo-chart.d.vue.ts +6 -1
  25. package/dist/runtime/dashboard/components/dashboard-combo-chart.vue +13 -3
  26. package/dist/runtime/dashboard/components/dashboard-combo-chart.vue.d.ts +6 -1
  27. package/dist/runtime/dashboard/components/dashboard-donut-chart.vue +5 -5
  28. package/dist/runtime/dashboard/components/dashboard-feed.vue +8 -7
  29. package/dist/runtime/dashboard/components/dashboard-filter.d.vue.ts +67 -0
  30. package/dist/runtime/dashboard/components/dashboard-filter.vue +134 -0
  31. package/dist/runtime/dashboard/components/dashboard-filter.vue.d.ts +67 -0
  32. package/dist/runtime/dashboard/components/dashboard-filters.d.vue.ts +49 -0
  33. package/dist/runtime/dashboard/components/dashboard-filters.vue +96 -0
  34. package/dist/runtime/dashboard/components/dashboard-filters.vue.d.ts +49 -0
  35. package/dist/runtime/dashboard/components/dashboard-funnel.vue +5 -5
  36. package/dist/runtime/dashboard/components/dashboard-gauge.vue +3 -3
  37. package/dist/runtime/dashboard/components/dashboard-grid.d.vue.ts +10 -3
  38. package/dist/runtime/dashboard/components/dashboard-grid.vue +24 -9
  39. package/dist/runtime/dashboard/components/dashboard-grid.vue.d.ts +10 -3
  40. package/dist/runtime/dashboard/components/dashboard-line-chart.d.vue.ts +14 -3
  41. package/dist/runtime/dashboard/components/dashboard-line-chart.vue +30 -9
  42. package/dist/runtime/dashboard/components/dashboard-line-chart.vue.d.ts +14 -3
  43. package/dist/runtime/dashboard/components/dashboard-list.d.vue.ts +3 -0
  44. package/dist/runtime/dashboard/components/dashboard-list.vue +18 -6
  45. package/dist/runtime/dashboard/components/dashboard-list.vue.d.ts +3 -0
  46. package/dist/runtime/dashboard/components/dashboard-page.d.vue.ts +53 -0
  47. package/dist/runtime/dashboard/components/dashboard-page.vue +156 -0
  48. package/dist/runtime/dashboard/components/dashboard-page.vue.d.ts +53 -0
  49. package/dist/runtime/dashboard/components/dashboard-paired-bars.vue +4 -4
  50. package/dist/runtime/dashboard/components/dashboard-refresh.d.vue.ts +1 -1
  51. package/dist/runtime/dashboard/components/dashboard-refresh.vue +1 -0
  52. package/dist/runtime/dashboard/components/dashboard-refresh.vue.d.ts +1 -1
  53. package/dist/runtime/dashboard/components/dashboard-stack-bar.vue +4 -4
  54. package/dist/runtime/dashboard/components/dashboard-stat.d.vue.ts +14 -2
  55. package/dist/runtime/dashboard/components/dashboard-stat.vue +28 -10
  56. package/dist/runtime/dashboard/components/dashboard-stat.vue.d.ts +14 -2
  57. package/dist/runtime/dashboard/components/dashboard-stats.vue +3 -3
  58. package/dist/runtime/dashboard/components/dashboard-table.d.vue.ts +1 -1
  59. package/dist/runtime/dashboard/components/dashboard-table.vue +3 -3
  60. package/dist/runtime/dashboard/components/dashboard-table.vue.d.ts +1 -1
  61. package/dist/runtime/dashboard/components/dashboard-tabs.d.vue.ts +1 -1
  62. package/dist/runtime/dashboard/components/dashboard-tabs.vue.d.ts +1 -1
  63. package/dist/runtime/dashboard/components/dashboard-total.d.vue.ts +7 -2
  64. package/dist/runtime/dashboard/components/dashboard-total.vue +10 -2
  65. package/dist/runtime/dashboard/components/dashboard-total.vue.d.ts +7 -2
  66. package/dist/runtime/dashboard/components/dashboard-view-tabs.d.vue.ts +33 -0
  67. package/dist/runtime/dashboard/components/dashboard-view-tabs.vue +66 -0
  68. package/dist/runtime/dashboard/components/dashboard-view-tabs.vue.d.ts +33 -0
  69. package/dist/runtime/dashboard/components/dashboard-widget.vue +1 -1
  70. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.d.vue.ts +44 -0
  71. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue +220 -0
  72. package/dist/runtime/dashboard/components/filter/dashboard-filter-menu.vue.d.ts +44 -0
  73. package/dist/runtime/dashboard/composables/use-dashboard-api.d.ts +6 -1
  74. package/dist/runtime/dashboard/composables/use-dashboard-api.js +29 -6
  75. package/dist/runtime/dashboard/composables/use-dashboard-block.d.ts +5 -4
  76. package/dist/runtime/dashboard/composables/use-dashboard-block.js +32 -15
  77. package/dist/runtime/dashboard/composables/use-dashboard-chart.d.ts +8 -1
  78. package/dist/runtime/dashboard/composables/use-dashboard-chart.js +16 -4
  79. package/dist/runtime/dashboard/composables/use-dashboard-context.d.ts +50 -0
  80. package/dist/runtime/dashboard/composables/use-dashboard-context.js +56 -0
  81. package/dist/runtime/dashboard/composables/use-dashboard-derived.js +6 -1
  82. package/dist/runtime/dashboard/composables/use-dashboard-filter-control.d.ts +16 -0
  83. package/dist/runtime/dashboard/composables/use-dashboard-filter-control.js +161 -0
  84. package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.d.ts +37 -0
  85. package/dist/runtime/dashboard/composables/use-dashboard-filter-scope.js +107 -0
  86. package/dist/runtime/dashboard/composables/use-dashboard-format.d.ts +46 -6
  87. package/dist/runtime/dashboard/composables/use-dashboard-format.js +51 -8
  88. package/dist/runtime/dashboard/composables/use-dashboard-options.d.ts +11 -4
  89. package/dist/runtime/dashboard/composables/use-dashboard-options.js +33 -47
  90. package/dist/runtime/dashboard/composables/use-dashboard-remote-options.d.ts +8 -5
  91. package/dist/runtime/dashboard/composables/use-dashboard-remote-options.js +66 -77
  92. package/dist/runtime/dashboard/composables/use-dashboard-resource.d.ts +15 -4
  93. package/dist/runtime/dashboard/composables/use-dashboard-resource.js +52 -17
  94. package/dist/runtime/dashboard/composables/use-dashboard-scope.d.ts +10 -7
  95. package/dist/runtime/dashboard/composables/use-dashboard-scope.js +26 -16
  96. package/dist/runtime/dashboard/composables/use-dashboard-series-picker.d.ts +20 -0
  97. package/dist/runtime/dashboard/composables/use-dashboard-series-picker.js +30 -0
  98. package/dist/runtime/dashboard/composables/use-dashboard-time.d.ts +2 -0
  99. package/dist/runtime/dashboard/composables/use-dashboard-time.js +4 -1
  100. package/dist/runtime/dashboard/composables/use-dashboard-ui.d.ts +12 -2
  101. package/dist/runtime/dashboard/composables/use-dashboard-ui.js +3 -0
  102. package/dist/runtime/dashboard/composables/use-dashboard-views.d.ts +15 -3
  103. package/dist/runtime/dashboard/composables/use-dashboard-views.js +33 -10
  104. package/dist/runtime/dashboard/composables/use-dashboard.d.ts +18 -12
  105. package/dist/runtime/dashboard/composables/use-dashboard.js +98 -9
  106. package/dist/runtime/dashboard/index.d.ts +3 -1
  107. package/dist/runtime/dashboard/index.js +3 -1
  108. package/dist/runtime/dashboard/schema/index.d.ts +62 -30
  109. package/dist/runtime/dashboard/schema/index.js +3 -0
  110. package/dist/runtime/dashboard/types/blocks.d.ts +30 -4
  111. package/dist/runtime/dashboard/types/charts.d.ts +2 -2
  112. package/dist/runtime/dashboard/types/controls.d.ts +123 -0
  113. package/dist/runtime/dashboard/types/filters.d.ts +236 -0
  114. package/dist/runtime/dashboard/types/index.d.ts +3 -2
  115. package/dist/runtime/dashboard/types/page.d.ts +17 -0
  116. package/dist/runtime/dashboard/types/page.js +0 -0
  117. package/dist/runtime/dashboard/types/resource.d.ts +66 -28
  118. package/dist/runtime/dashboard/types/runtime.d.ts +39 -8
  119. package/dist/runtime/dashboard/types/schema.d.ts +94 -54
  120. package/dist/runtime/dashboard/types/ui.d.ts +78 -0
  121. package/dist/runtime/dashboard/utils/builders/dashboard-filters.d.ts +142 -0
  122. package/dist/runtime/dashboard/utils/builders/dashboard-filters.js +135 -0
  123. package/dist/runtime/dashboard/utils/charts.d.ts +4 -15
  124. package/dist/runtime/dashboard/utils/charts.js +26 -28
  125. package/dist/runtime/dashboard/utils/{params/codecs.d.ts → codecs.d.ts} +2 -2
  126. package/dist/runtime/dashboard/utils/{params/codecs.js → codecs.js} +1 -1
  127. package/dist/runtime/dashboard/utils/environment.d.ts +36 -0
  128. package/dist/runtime/dashboard/utils/environment.js +30 -0
  129. package/dist/runtime/dashboard/utils/filters.d.ts +44 -0
  130. package/dist/runtime/dashboard/utils/filters.js +62 -0
  131. package/dist/runtime/dashboard/utils/format.d.ts +25 -0
  132. package/dist/runtime/dashboard/utils/format.js +66 -0
  133. package/dist/runtime/dashboard/utils/grid.d.ts +17 -0
  134. package/dist/runtime/dashboard/utils/grid.js +14 -0
  135. package/dist/runtime/dashboard/utils/options.d.ts +3 -8
  136. package/dist/runtime/dashboard/utils/options.js +6 -5
  137. package/dist/runtime/dashboard/utils/remote.d.ts +7 -0
  138. package/dist/runtime/dashboard/utils/remote.js +14 -0
  139. package/dist/runtime/dashboard/utils/resource.d.ts +16 -7
  140. package/dist/runtime/dashboard/utils/resource.js +15 -9
  141. package/dist/runtime/dashboard/utils/schema.d.ts +8 -3
  142. package/dist/runtime/dashboard/utils/schema.js +9 -4
  143. package/dist/runtime/dashboard/utils/state.d.ts +11 -6
  144. package/dist/runtime/dashboard/utils/state.js +10 -5
  145. package/dist/runtime/dashboard/utils/time.d.ts +2 -0
  146. package/dist/runtime/dashboard/utils/time.js +11 -1
  147. package/dist/runtime/dashboard/utils/ui.d.ts +1 -1
  148. package/dist/runtime/dashboard/utils/ui.js +1 -1
  149. package/dist/runtime/form/components/root/form.vue +1 -1
  150. package/dist/runtime/form/fields/card-selection.d.ts +1 -0
  151. package/dist/runtime/form/fields/card-selection.js +1 -0
  152. package/dist/runtime/form/fields/checkbox-card/component.vue +3 -1
  153. package/dist/runtime/form/fields/checkbox-group/component.vue +5 -0
  154. package/dist/runtime/form/fields/radio/component.vue +10 -0
  155. package/dist/runtime/form/fields/radio-card/component.vue +3 -1
  156. package/dist/runtime/form/types/options.d.ts +1 -11
  157. package/dist/runtime/form/utils/focus.js +1 -1
  158. package/dist/runtime/i18n/locales/en.js +32 -1
  159. package/dist/runtime/i18n/locales/fr.js +32 -1
  160. package/dist/runtime/i18n/types.d.ts +44 -0
  161. package/dist/runtime/shared/styles/scrollbars.css +1 -1
  162. package/dist/runtime/shared/styles/tokens.css +1 -1
  163. package/dist/runtime/shared/types/query.d.ts +8 -0
  164. package/dist/runtime/shared/utils/remote-options.d.ts +10 -0
  165. package/dist/runtime/shared/utils/remote-options.js +6 -0
  166. package/dist/runtime/table/components/filters/shared/filter-option-list-end.d.vue.ts +11 -0
  167. package/dist/runtime/table/components/filters/shared/filter-option-list-end.vue +76 -0
  168. package/dist/runtime/table/components/filters/shared/filter-option-list-end.vue.d.ts +11 -0
  169. package/dist/runtime/table/components/filters/shared/filter-option-loading-list.d.vue.ts +3 -0
  170. package/dist/runtime/table/components/filters/shared/filter-option-loading-list.vue +2 -1
  171. package/dist/runtime/table/components/filters/shared/filter-option-loading-list.vue.d.ts +3 -0
  172. package/dist/runtime/table/components/filters/shared/filter-option-multiple-list.vue +1 -1
  173. package/dist/runtime/table/components/filters/shared/filter-option-picker-content.vue +13 -0
  174. package/dist/runtime/table/components/filters/shared/filter-option-single-list.d.vue.ts +2 -0
  175. package/dist/runtime/table/components/filters/shared/filter-option-single-list.vue +1 -1
  176. package/dist/runtime/table/components/filters/shared/filter-option-single-list.vue.d.ts +2 -0
  177. package/dist/runtime/table/components/filters/shared/filter-option-tree-content.d.vue.ts +3 -0
  178. package/dist/runtime/table/components/filters/shared/filter-option-tree-content.vue +2 -2
  179. package/dist/runtime/table/components/filters/shared/filter-option-tree-content.vue.d.ts +3 -0
  180. package/dist/runtime/table/components/filters/shared/filter-searchable-panel.vue +1 -0
  181. package/dist/runtime/table/composables/use-option-filter-editor-state.d.ts +13 -1
  182. package/dist/runtime/table/composables/use-option-filter-editor-state.js +6 -2
  183. package/dist/runtime/table/composables/use-table-filter-options.d.ts +11 -1
  184. package/dist/runtime/table/composables/use-table-filter-options.js +128 -17
  185. package/dist/runtime/table/composables/use-table-filter-selected-options.d.ts +20 -0
  186. package/dist/runtime/table/composables/use-table-filter-selected-options.js +99 -0
  187. package/dist/runtime/table/composables/use-table-filters.d.ts +5 -0
  188. package/dist/runtime/table/composables/use-table-filters.js +20 -1
  189. package/dist/runtime/table/composables/use-table-internals.d.ts +15 -0
  190. package/dist/runtime/table/composables/use-table-remote-filter-options.d.ts +42 -0
  191. package/dist/runtime/table/composables/use-table-remote-filter-options.js +102 -0
  192. package/dist/runtime/table/types/filters.d.ts +42 -0
  193. package/dist/runtime/table/types/index.d.ts +1 -0
  194. package/dist/runtime/table/types/remote-options.d.ts +64 -0
  195. package/dist/runtime/table/types/remote-options.js +0 -0
  196. package/dist/runtime/table/types/source.d.ts +15 -1
  197. package/dist/runtime/table/utils/builders/table-source.d.ts +2 -6
  198. package/dist/runtime/table/utils/filters/options.d.ts +2 -0
  199. package/dist/runtime/table/utils/filters/options.js +1 -1
  200. package/dist/runtime/table/utils/index.d.ts +1 -0
  201. package/dist/runtime/table/utils/index.js +1 -0
  202. package/dist/runtime/table/utils/prefetch.js +21 -1
  203. package/dist/runtime/table/utils/remote-table-options.d.ts +26 -0
  204. package/dist/runtime/table/utils/remote-table-options.js +88 -0
  205. package/package.json +4 -1
  206. package/dist/runtime/dashboard/composables/use-dashboard-param-scope.d.ts +0 -30
  207. package/dist/runtime/dashboard/composables/use-dashboard-param-scope.js +0 -71
  208. package/dist/runtime/dashboard/types/options.d.ts +0 -46
  209. package/dist/runtime/dashboard/types/params.d.ts +0 -115
  210. package/dist/runtime/dashboard/utils/builders/dashboard-params.d.ts +0 -85
  211. package/dist/runtime/dashboard/utils/builders/dashboard-params.js +0 -87
  212. /package/dist/runtime/dashboard/types/{options.js → controls.js} +0 -0
  213. /package/dist/runtime/dashboard/types/{params.js → filters.js} +0 -0
@@ -1,34 +1,51 @@
1
- import { computed, onBeforeUnmount, onMounted } from "vue";
1
+ import { computed, onBeforeUnmount, watch } from "vue";
2
2
  import { useResponsiveValue } from "../../shared/composables/use-responsive-value.js";
3
+ import { parseDashboardSpan, resolveDashboardCellStyle } from "../utils/grid.js";
3
4
  import { observeDashboardVisibility } from "../utils/visibility.js";
5
+ import { useDashboardGridContext } from "./use-dashboard-ui.js";
4
6
  export function useDashboardBlock(params) {
7
+ const hidden = computed(() => params.source()?.state === "disabled");
5
8
  const phase = computed(() => {
6
9
  const source = params.source();
7
10
  if (!source) return "content";
11
+ if (source.state === "disabled") return "idle";
8
12
  if (source.state !== "ready") return source.state;
9
13
  return params.empty() ? "empty" : "content";
10
14
  });
11
- const refreshing = computed(() => params.source()?.refreshing ?? false);
12
- const span = useResponsiveValue(() => params.size() ?? "", "col");
13
- const rowSpan = useResponsiveValue(() => params.rows() ?? "", "row");
15
+ const fetching = computed(() => {
16
+ const source = params.source();
17
+ return source ? source.fetching ?? source.refreshing : false;
18
+ });
19
+ const grid = useDashboardGridContext();
20
+ const span = useResponsiveValue(() => params.size() ?? "", "integer");
14
21
  const style = computed(
15
- () => [span.value ?? "grid-column: 1 / -1", rowSpan.value].filter(Boolean).join("; ")
22
+ () => grid ? resolveDashboardCellStyle({
23
+ columns: grid.columns.value,
24
+ fill: grid.fill.value,
25
+ gap: grid.gap.value,
26
+ span: parseDashboardSpan(span.value)
27
+ }) : ""
16
28
  );
17
29
  let stopObserving;
18
- onMounted(() => {
19
- const source = params.source();
20
- const activation = params.activation() ?? "visible";
21
- if (!source || activation === "manual" || !waitsForActivation(source)) return;
22
- const element = params.root.value;
23
- if (activation === "mount" || !element || typeof IntersectionObserver === "undefined")
24
- return source.activate();
25
- stopObserving = observeDashboardVisibility(element, () => params.source()?.activate());
26
- });
30
+ watch(
31
+ () => params.root.value,
32
+ (element) => {
33
+ stopObserving?.();
34
+ stopObserving = void 0;
35
+ const source = params.source();
36
+ const activation = params.activation() ?? "visible";
37
+ if (!element || !source || activation === "manual" || !waitsForActivation(source)) return;
38
+ if (activation === "mount" || typeof IntersectionObserver === "undefined")
39
+ return source.activate();
40
+ stopObserving = observeDashboardVisibility(element, () => params.source()?.activate());
41
+ },
42
+ { flush: "post", immediate: true }
43
+ );
27
44
  onBeforeUnmount(() => stopObserving?.());
28
45
  function retry() {
29
46
  params.source()?.refresh().catch(() => void 0);
30
47
  }
31
- return { phase, refreshing, retry, style };
48
+ return { fetching, hidden, phase, retry, style };
32
49
  }
33
50
  function waitsForActivation(source) {
34
51
  return !("stage" in source) || source.stage === "deferred";
@@ -1,5 +1,5 @@
1
1
  import type { LazyTextValue } from '../../shared/types/utils.js';
2
- import type { DashboardAxisOptions, DashboardChartFrame, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardValueFormat } from '../types/index.js';
2
+ import type { DashboardAxisOptions, DashboardChartFrame, DashboardChartTotals, DashboardHighlight, DashboardReferenceLine, DashboardSelected, DashboardSelectEvent, DashboardSeries, DashboardValueFormat } from '../types/index.js';
3
3
  /** A chart drawn taller in the expand dialog. */
4
4
  export declare function resolveDashboardExpandedHeight(height: number): number;
5
5
  /**
@@ -27,10 +27,17 @@ export declare function useDashboardChart<TRow>(params: {
27
27
  selected?: () => DashboardSelected<TRow> | undefined;
28
28
  /** Bar charts: prints each group's value above its bars. */
29
29
  labels?: () => boolean;
30
+ /** Footer totals of the solid series: their sum, or their average. */
31
+ totals?: () => DashboardChartTotals | undefined;
30
32
  }): {
31
33
  frame: import("vue").ComputedRef<DashboardChartFrame>;
32
34
  legend: import("vue").ComputedRef<import("../types/index.js").DashboardLegendItem[]>;
33
35
  select: (index: number) => void;
34
36
  selectable: import("vue").ComputedRef<boolean>;
35
37
  tabulate: () => import("../types/index.js").DashboardDataTable;
38
+ totals: import("vue").ComputedRef<{
39
+ key: string;
40
+ label: string;
41
+ text: string;
42
+ }[]>;
36
43
  };
@@ -58,7 +58,7 @@ export function useDashboardChart(params) {
58
58
  const values = stacked && axis === "left" ? data.map((datum) => indexes.reduce((sum, index) => sum + (datum.values[index] ?? 0), 0)) : data.flatMap((datum) => indexes.map((index) => datum.values[index]));
59
59
  return [...values, ...references.filter((ref) => ref.axis === axis).map((ref) => ref.value)];
60
60
  };
61
- const format = params.format() ?? formats.number.value;
61
+ const format = formats.resolve(params.format());
62
62
  const yAxis = params.yAxis();
63
63
  const y2Axis = params.y2Axis?.();
64
64
  const hasRight = resolved.some((entry) => entry.axis === "right");
@@ -70,7 +70,7 @@ export function useDashboardChart(params) {
70
70
  );
71
71
  const selected = params.selected?.();
72
72
  const emphasis = hasBars ? resolveDashboardEmphasis(rows, barTotals, params.highlight?.(), selected) : null;
73
- const leftFormat = yAxis?.format ?? format;
73
+ const leftFormat = yAxis?.format ? formats.resolve(yAxis.format) : format;
74
74
  return {
75
75
  data,
76
76
  emphasis,
@@ -82,7 +82,7 @@ export function useDashboardChart(params) {
82
82
  references,
83
83
  right: hasRight ? {
84
84
  ...resolveDashboardAxis(axisValues("right"), y2Axis, headroom),
85
- format: y2Axis?.format ?? format
85
+ format: y2Axis?.format ? formats.resolve(y2Axis.format) : format
86
86
  } : null,
87
87
  series: resolved.map(({ axis, color, dashed, key, label, type }, index) => ({
88
88
  axis,
@@ -105,6 +105,18 @@ export function useDashboardChart(params) {
105
105
  xDomain: hasBars || last === 0 ? [-0.5, last + 0.5] : [0, last]
106
106
  };
107
107
  });
108
+ const totals = computed(() => {
109
+ const mode = params.totals?.();
110
+ if (!mode) return [];
111
+ const { data, left, right, series: entries } = frame.value;
112
+ return entries.filter((entry) => !entry.dashed && !entry.key.endsWith(":compare")).map((entry) => {
113
+ const values = data.flatMap((datum) => datum.values[entry.index] ?? []);
114
+ const sum = values.reduce((total, value2) => total + value2, 0);
115
+ const value = mode === "average" ? values.length ? sum / values.length : 0 : sum;
116
+ const format = (entry.axis === "right" ? right?.format : void 0) ?? left.format;
117
+ return { key: entry.key, label: entry.label, text: format(value) };
118
+ });
119
+ });
108
120
  const tabulate = () => tabulateDashboardFrame(
109
121
  frame.value,
110
122
  resolveTextValue(params.xLabel(), t("dashboard.table.category"))
@@ -114,5 +126,5 @@ export function useDashboardChart(params) {
114
126
  const row = params.rows()[index];
115
127
  if (row !== void 0) params.onSelect()?.({ index, row });
116
128
  }
117
- return { frame, legend, select, selectable, tabulate };
129
+ return { frame, legend, select, selectable, tabulate, totals };
118
130
  }
@@ -0,0 +1,50 @@
1
+ import type { DashboardSchemaInput, DashboardSchemaLike, DashboardViewInput, InferDashboard, InferDashboardView } from '../types/index.js';
2
+ /** One dashboard created by `useDashboard`, as its descendants find it. */
3
+ export interface DashboardContextEntry {
4
+ /** What `useDashboard` received: a schema, or a function returning one. */
5
+ readonly source: unknown;
6
+ /** The schema the dashboard currently runs. */
7
+ schema(): DashboardSchemaLike;
8
+ /** The dashboard object `useDashboard` returned. */
9
+ readonly api: object;
10
+ /** Handle of a view, stable across rebuilds. */
11
+ view(key: string): object | undefined;
12
+ /** Key of the view declared with this object, if the current schema has one. */
13
+ findView(declaration: object): string | undefined;
14
+ /** Key of the view on screen. */
15
+ current(): string | undefined;
16
+ }
17
+ /** Makes a dashboard available to descendant components. */
18
+ export declare function provideDashboard(entry: DashboardContextEntry): void;
19
+ /**
20
+ * Marks the components below as rendering one view of a dashboard, so `useDashboardView` resolves
21
+ * a view function to it. `UiDashboardPage` does it around the current view's slot.
22
+ */
23
+ export declare function provideDashboardView(dashboard: object, key: string): void;
24
+ /**
25
+ * Returns the dashboard an ancestor component created with `useDashboard`, fully typed, so nested
26
+ * components read it without props. Pass the schema, or the schema function: the nearest dashboard
27
+ * built from it answers (for a function, the nearest dashboard).
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const account = injectDashboard(accountSchema)
32
+ * account.filters.year
33
+ * ```
34
+ */
35
+ export declare function injectDashboard<const TInput extends DashboardSchemaInput>(input: TInput): InferDashboard<TInput>;
36
+ /**
37
+ * Returns the handle of a view: its queries, derived values, filters and controls, fully typed. A
38
+ * tab component needs nothing else.
39
+ *
40
+ * Pass the view, or the view function. Under `UiDashboardPage`, the view is the one whose slot
41
+ * renders the component; elsewhere, a view object is found by identity and a view function reads
42
+ * the view on screen.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const consumption = useDashboardView(consumptionView)
47
+ * consumption.filters.year
48
+ * ```
49
+ */
50
+ export declare function useDashboardView<const TInput extends DashboardViewInput>(input: TInput): InferDashboardView<TInput>;
@@ -0,0 +1,56 @@
1
+ import { getCurrentInstance, inject, provide } from "vue";
2
+ const dashboardContextKey = Symbol("nuxt-ui-tools.dashboard");
3
+ function injectDashboardContext() {
4
+ return getCurrentInstance() ? inject(dashboardContextKey, null) : null;
5
+ }
6
+ export function provideDashboard(entry) {
7
+ if (!getCurrentInstance()) return;
8
+ const parent = injectDashboardContext();
9
+ provide(dashboardContextKey, { dashboards: [...parent?.dashboards ?? [], entry] });
10
+ }
11
+ export function provideDashboardView(dashboard, key) {
12
+ const parent = injectDashboardContext();
13
+ const entry = parent ? findLastEntry(parent.dashboards, (candidate) => candidate.api === dashboard) : void 0;
14
+ if (!parent || !entry) return;
15
+ provide(dashboardContextKey, { dashboards: parent.dashboards, view: { entry, key } });
16
+ }
17
+ export function injectDashboard(input) {
18
+ const dashboards = injectDashboardContext()?.dashboards ?? [];
19
+ const entry = findLastEntry(
20
+ dashboards,
21
+ (candidate) => candidate.source === input || candidate.schema() === input
22
+ ) ?? (typeof input === "function" ? dashboards.at(-1) : void 0);
23
+ if (!entry)
24
+ throw new Error(
25
+ "[dashboard] injectDashboard() found no dashboard. Call useDashboard() in a parent component."
26
+ );
27
+ return entry.api;
28
+ }
29
+ export function useDashboardView(input) {
30
+ const context = injectDashboardContext();
31
+ const handle = resolveView(context, input);
32
+ if (!handle)
33
+ throw new Error(
34
+ "[dashboard] useDashboardView() found no view. Render the component in a view slot of UiDashboardPage, under a dashboard created with useDashboard() whose schema declares the view."
35
+ );
36
+ return handle;
37
+ }
38
+ function resolveView(context, input) {
39
+ if (!context) return void 0;
40
+ const enclosing = context.view;
41
+ if (enclosing && (typeof input === "function" || enclosing.entry.findView(input) === enclosing.key))
42
+ return enclosing.entry.view(enclosing.key);
43
+ for (let index = context.dashboards.length - 1; index >= 0; index--) {
44
+ const entry = context.dashboards[index];
45
+ const key = typeof input === "function" ? entry?.current() : entry?.findView(input);
46
+ if (entry && key !== void 0) return entry.view(key);
47
+ }
48
+ return void 0;
49
+ }
50
+ function findLastEntry(dashboards, match) {
51
+ for (let index = dashboards.length - 1; index >= 0; index--) {
52
+ const entry = dashboards[index];
53
+ if (entry && match(entry)) return entry;
54
+ }
55
+ return void 0;
56
+ }
@@ -21,16 +21,20 @@ export function useDashboardDerived(params) {
21
21
  if (sourcesState.value !== "ready") return sourcesState.value;
22
22
  return evaluation.value.error === void 0 ? "ready" : "error";
23
23
  });
24
- return markRaw({
24
+ const derived = markRaw({
25
25
  activate() {
26
26
  for (const source of evaluation.value.sources) source.activate();
27
27
  },
28
28
  get data() {
29
+ params.tracker.record(derived);
29
30
  return evaluation.value.value;
30
31
  },
31
32
  get error() {
32
33
  return evaluation.value.error ?? evaluation.value.sources.find((source) => source.state === "error")?.error;
33
34
  },
35
+ get fetching() {
36
+ return evaluation.value.sources.some((source) => source.fetching ?? source.refreshing);
37
+ },
34
38
  id: params.id,
35
39
  kind: "derived",
36
40
  refresh: () => refreshDashboardSources(evaluation.value.sources),
@@ -44,4 +48,5 @@ export function useDashboardDerived(params) {
44
48
  return resolveDashboardUpdatedAt(evaluation.value.sources.map((source) => source.updatedAt));
45
49
  }
46
50
  });
51
+ return derived;
47
52
  }
@@ -0,0 +1,16 @@
1
+ import type { QueryKey } from '@tanstack/vue-query';
2
+ import type { DashboardFilterControl, DashboardRuntimeFilter } from '../types/index.js';
3
+ import type { DashboardLocale } from '../utils/environment.js';
4
+ /**
5
+ * Control of one filter: its value and presentation (label, display text, option list) plus the
6
+ * actions pickers perform (`toggle`, `reset`). It owns no state of its own besides the option list;
7
+ * the value lives wherever the filter syncs it.
8
+ */
9
+ export declare function useDashboardFilterControl(params: {
10
+ key: string;
11
+ definition: DashboardRuntimeFilter;
12
+ queryKey: QueryKey;
13
+ locale: DashboardLocale;
14
+ get: () => unknown;
15
+ set: (value: unknown) => void;
16
+ }): DashboardFilterControl;
@@ -0,0 +1,161 @@
1
+ import { computed, markRaw } from "vue";
2
+ import { isNullish } from "../../shared/utils/predicate.js";
3
+ import { resolveTextValue } from "../../shared/utils/render.js";
4
+ import {
5
+ formatDashboardFilterValue,
6
+ isDashboardOptionValue,
7
+ isDashboardFilterHeadless
8
+ } from "../utils/filters.js";
9
+ import { resolveDashboardCondition } from "../utils/state.js";
10
+ import { useDashboardOptions } from "./use-dashboard-options.js";
11
+ export function useDashboardFilterControl(params) {
12
+ const { definition, get, set } = params;
13
+ const { code, t } = params.locale;
14
+ const options = useDashboardOptions({
15
+ definition,
16
+ locale: params.locale,
17
+ queryKey: params.queryKey,
18
+ value: get
19
+ });
20
+ const listed = definition.items !== void 0 || definition.remote !== void 0;
21
+ const label = computed(() => resolveTextValue(definition.label, params.key));
22
+ const placeholder = computed(
23
+ () => resolveTextValue(definition.placeholder, t("dashboard.filters.all"))
24
+ );
25
+ const changed = computed(
26
+ () => definition.codec.serialize(get()) !== definition.codec.serialize(definition.resolveDefault())
27
+ );
28
+ const values = computed(() => {
29
+ const value = get();
30
+ const list = Array.isArray(value) ? value : [value];
31
+ return list.filter(isDashboardOptionValue);
32
+ });
33
+ const keys = computed(() => new Set(values.value.map(String)));
34
+ const selected = computed(
35
+ () => values.value.map(
36
+ (value) => options.known.value.get(String(value)) ?? {
37
+ label: options.resolving.value ? "\u2026" : describe(value),
38
+ value
39
+ }
40
+ )
41
+ );
42
+ const display = computed(() => {
43
+ const value = get();
44
+ if (isNullish(value) || Array.isArray(value) && value.length === 0) return placeholder.value;
45
+ const [first, second] = selected.value;
46
+ if (!first) return describe(value);
47
+ if (!second) return first.label;
48
+ return selected.value.length === 2 ? `${first.label}, ${second.label}` : t("dashboard.filters.more", { count: selected.value.length - 1, label: first.label });
49
+ });
50
+ function describe(value) {
51
+ return definition.format ? definition.format(value) : formatDashboardFilterValue(value, code.value);
52
+ }
53
+ const presets = computed(() => {
54
+ const current = definition.codec.serialize(get());
55
+ return (definition.presets?.() ?? []).map((preset) => ({
56
+ active: definition.codec.serialize(preset.value) === current,
57
+ apply: () => set(preset.value),
58
+ hint: preset.hint,
59
+ icon: preset.icon,
60
+ label: resolveTextValue(preset.label),
61
+ value: preset.value
62
+ }));
63
+ });
64
+ const menu = computed(() => ({
65
+ items: [...options.items.value],
66
+ labelKey: "label",
67
+ multiple: definition.multiple,
68
+ valueKey: "value",
69
+ ...options.menu.value
70
+ }));
71
+ function toggle(value) {
72
+ if (!definition.multiple) return set(value);
73
+ const current = Array.isArray(get()) ? values.value : [];
74
+ const key = String(value);
75
+ if (keys.value.has(key)) return set(current.filter((entry) => String(entry) !== key));
76
+ if (definition.max !== void 0 && current.length >= definition.max) return;
77
+ const order = options.order.value;
78
+ const next = [...current, value];
79
+ if (order) {
80
+ const rank = (entry) => order.get(String(entry)) ?? order.size;
81
+ next.sort((first, second) => rank(first) - rank(second));
82
+ }
83
+ set(next);
84
+ }
85
+ return markRaw({
86
+ get changed() {
87
+ return changed.value;
88
+ },
89
+ get columns() {
90
+ return definition.columns;
91
+ },
92
+ get defaultValue() {
93
+ return definition.resolveDefault();
94
+ },
95
+ get display() {
96
+ return display.value;
97
+ },
98
+ get error() {
99
+ return options.error.value;
100
+ },
101
+ get hasMore() {
102
+ return options.hasMore.value;
103
+ },
104
+ get enabled() {
105
+ return resolveDashboardCondition(definition.enabled);
106
+ },
107
+ headless: isDashboardFilterHeadless(definition),
108
+ isSelected: (value) => keys.value.has(String(value)),
109
+ get items() {
110
+ return listed ? options.items.value : [];
111
+ },
112
+ key: params.key,
113
+ kind: definition.kind,
114
+ get label() {
115
+ return label.value;
116
+ },
117
+ get loading() {
118
+ return options.loading.value;
119
+ },
120
+ get loadingMore() {
121
+ return options.loadingMore.value;
122
+ },
123
+ loadMore: options.loadMore,
124
+ max: definition.max,
125
+ get menu() {
126
+ return menu.value;
127
+ },
128
+ multiple: definition.multiple,
129
+ get open() {
130
+ return options.open.value;
131
+ },
132
+ set open(next) {
133
+ options.open.value = next;
134
+ },
135
+ get placeholder() {
136
+ return placeholder.value;
137
+ },
138
+ get presets() {
139
+ return presets.value;
140
+ },
141
+ refresh: options.refresh,
142
+ reset: () => set(definition.resolveDefault()),
143
+ get search() {
144
+ return options.search.value;
145
+ },
146
+ set search(next) {
147
+ options.search.value = next;
148
+ },
149
+ searchable: definition.searchable === true,
150
+ get selected() {
151
+ return selected.value;
152
+ },
153
+ toggle,
154
+ get value() {
155
+ return get();
156
+ },
157
+ set value(next) {
158
+ set(next);
159
+ }
160
+ });
161
+ }
@@ -0,0 +1,37 @@
1
+ import type { QueryKey } from '@tanstack/vue-query';
2
+ import type { DashboardFilterControl, DashboardFilterLike } from '../types/index.js';
3
+ import type { DashboardEnvironment } from '../utils/environment.js';
4
+ /**
5
+ * What one filter scope exposes. Declared rather than inferred: the inferred type would carry Vue's
6
+ * `Raw<…>` marker, which declaration files cannot name.
7
+ */
8
+ export interface DashboardFilterScope {
9
+ keys: readonly string[];
10
+ /** Controls, by filter key. */
11
+ controls: Readonly<Record<string, DashboardFilterControl>>;
12
+ /** URL segments of this scope's URL-synced filters, before the dashboard prefix. */
13
+ urlKeys: readonly string[];
14
+ /** Writable facade: one getter / setter per filter. */
15
+ values: object;
16
+ /** A filter that is enabled and not headless differs from its default. */
17
+ changed: () => boolean;
18
+ /** Restores the default of every filter that is enabled and not headless. */
19
+ reset: () => void;
20
+ }
21
+ /**
22
+ * Owns the filters of one scope (dashboard root, a view, or a query): where each value lives (one
23
+ * `useQueryStates` for the URL-synced ones, a ref per memory filter, the external ref or getter of
24
+ * synced ones), a writable values facade, and one control per filter. Scopes without filters
25
+ * allocate nothing.
26
+ *
27
+ * A URL key names one filter across the dashboard: scopes declaring the same key read and write the
28
+ * same value, and must declare it the same way.
29
+ */
30
+ export declare function useDashboardFilterScope(params: {
31
+ definitions: Readonly<Record<string, DashboardFilterLike>>;
32
+ /** Where the scope sits, for error messages: `view "consumption"`. */
33
+ owner: string;
34
+ prefix: string;
35
+ queryKey: QueryKey;
36
+ environment: DashboardEnvironment;
37
+ }): DashboardFilterScope;
@@ -0,0 +1,107 @@
1
+ import { computed, isRef, markRaw, shallowRef } from "vue";
2
+ import { useQueryStates } from "../../query-state/index.js";
3
+ import { hasProperty, isNullish } from "../../shared/utils/predicate.js";
4
+ import { registerDashboardFilter } from "../utils/environment.js";
5
+ import { joinDashboardUrlKey, resolveDashboardCondition } from "../utils/state.js";
6
+ import { useDashboardFilterControl } from "./use-dashboard-filter-control.js";
7
+ const emptyFacade = markRaw({});
8
+ const noUrlKeys = [];
9
+ export function useDashboardFilterScope(params) {
10
+ const entries = Object.entries(params.definitions).flatMap(
11
+ ([key, definition]) => isRuntimeFilter(definition) ? [[key, definition]] : []
12
+ );
13
+ if (entries.length === 0)
14
+ return {
15
+ changed: () => false,
16
+ controls: emptyFacade,
17
+ keys: [],
18
+ reset() {
19
+ },
20
+ urlKeys: noUrlKeys,
21
+ values: emptyFacade
22
+ };
23
+ const urlEntries = entries.filter(([, definition]) => (definition.sync ?? "url") === "url");
24
+ const schema = {};
25
+ for (const [key, definition] of urlEntries) {
26
+ registerDashboardFilter(params.environment.registry, {
27
+ definition,
28
+ owner: `${params.owner} ("${key}")`,
29
+ urlKey: joinDashboardUrlKey(params.prefix, definition.urlKey ?? key)
30
+ });
31
+ schema[key] = {
32
+ codec: definition.codec,
33
+ defaultValue: definition.defaultValue,
34
+ historyMode: definition.historyMode,
35
+ omitDefault: definition.omitDefault,
36
+ urlKey: definition.urlKey
37
+ };
38
+ }
39
+ const state = urlEntries.length > 0 ? useQueryStates({ historyMode: "replace", prefix: params.prefix, schema }) : null;
40
+ function createAccessor(key, definition) {
41
+ const { defaultValue, sync = "url" } = definition;
42
+ if (sync === "url" && state) {
43
+ return {
44
+ get: () => {
45
+ const current = state.value;
46
+ return current[key];
47
+ },
48
+ set: (value) => {
49
+ state.value = { ...state.value, [key]: value };
50
+ }
51
+ };
52
+ }
53
+ if (sync === "url" || sync === "memory") {
54
+ const cell = shallowRef(defaultValue);
55
+ return { get: () => cell.value, set: (value) => cell.value = value };
56
+ }
57
+ if (isRef(sync)) return { get: () => sync.value, set: (value) => sync.value = value };
58
+ return { get: () => sync(), set() {
59
+ } };
60
+ }
61
+ const values = {};
62
+ const controls = {};
63
+ for (const [key, definition] of entries) {
64
+ const accessor = createAccessor(key, definition);
65
+ const { codec, multiple } = definition;
66
+ const enabled = () => resolveDashboardCondition(definition.enabled);
67
+ const get = () => {
68
+ if (!enabled()) return definition.resolveDefault();
69
+ const value = accessor.get();
70
+ const unset = isNullish(value) || multiple && Array.isArray(value) && value.length === 0;
71
+ return unset ? definition.resolveDefault() : value;
72
+ };
73
+ const set = (value) => {
74
+ if (!enabled()) return;
75
+ const next = value ?? definition.resolveDefault();
76
+ const isDefault = codec.serialize(next) === codec.serialize(definition.resolveDefault());
77
+ accessor.set(isDefault ? definition.defaultValue : next);
78
+ };
79
+ Object.defineProperty(values, key, { enumerable: true, get, set });
80
+ definition.bind(get);
81
+ controls[key] = useDashboardFilterControl({
82
+ definition,
83
+ get,
84
+ key,
85
+ locale: params.environment.locale,
86
+ queryKey: [...params.queryKey, key],
87
+ set
88
+ });
89
+ }
90
+ const visible = Object.values(controls).filter((control) => !control.headless);
91
+ const changed = computed(
92
+ () => visible.some((control) => control.enabled && control.changed)
93
+ );
94
+ return {
95
+ changed: () => changed.value,
96
+ controls: markRaw(controls),
97
+ keys: entries.map(([key]) => key),
98
+ reset() {
99
+ for (const control of visible) if (control.enabled) control.reset();
100
+ },
101
+ urlKeys: urlEntries.map(([key, definition]) => definition.urlKey ?? key),
102
+ values: markRaw(values)
103
+ };
104
+ }
105
+ function isRuntimeFilter(definition) {
106
+ return hasProperty(definition, "codec");
107
+ }
@@ -1,6 +1,46 @@
1
- /** Locale-aware default formatters used when a block receives no explicit `format`. */
2
- export declare function useDashboardFormat(): {
3
- delta: import("vue").ComputedRef<import("../types/index.js").DashboardValueFormat>;
4
- number: import("vue").ComputedRef<import("../types/index.js").DashboardValueFormat>;
5
- percent: import("vue").ComputedRef<import("../types/index.js").DashboardValueFormat>;
6
- };
1
+ import type { DashboardFormatPreset, DashboardValueFormat, DashboardValueFormatter } from '../types/index.js';
2
+ /**
3
+ * The number and month formatters dashboard blocks use, in the dashboard locale (the Nuxt UI locale
4
+ * unless overridden). Use them for captions, labels, and any text next to a block so everything on
5
+ * screen reads the same way. Reads are reactive: a locale switch re-renders what used them.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const format = useDashboardFormat()
10
+ * format.integer(12345) // "12,345"
11
+ * format.percent(57) // "57%"
12
+ * format.points(2.1) // "+2.1 pts"
13
+ * format.currency(1200, 'EUR') // "€1,200"
14
+ * format.month(3) // "Mar"
15
+ * format.ratio(null) // "—"
16
+ * ```
17
+ *
18
+ * Every number formatter takes `null` / `undefined` too, and prints "—" for them, so a missing rate
19
+ * or an empty period needs no fallback in the template.
20
+ */
21
+ export declare function useDashboardFormat(): import("vue").Raw<{
22
+ /** `12600` → "12.6K". */
23
+ compact: (value: number | null | undefined) => string;
24
+ /** An amount in a currency, rounded to units unless `options` say otherwise. */
25
+ currency: (value: number | null | undefined, currency: string, options?: Intl.NumberFormatOptions) => string;
26
+ /** One decimal at most. */
27
+ decimal: (value: number | null | undefined) => string;
28
+ /** Signed percent change: `12.4` → "+12.4%". */
29
+ delta: (value: number | null | undefined) => string;
30
+ /** Grouped, no decimals. */
31
+ integer: (value: number | null | undefined) => string;
32
+ /** Month name, capitalized: `3` (1–12) or a date → "Mar" (`'long'`: "March"). */
33
+ month: (value: number | Date, width?: "short" | "long") => string;
34
+ /** Grouped, one decimal at most, compact from 10,000. */
35
+ number: (value: number | null | undefined) => string;
36
+ /** A share out of 100: `57` → "57%". */
37
+ percent: (value: number | null | undefined) => string;
38
+ points: (value: number | null | undefined) => string;
39
+ /** A share out of 1: `0.57` → "57%". */
40
+ ratio: (value: number | null | undefined) => string;
41
+ resolve: (format: DashboardValueFormat | undefined, fallback?: DashboardFormatPreset) => DashboardValueFormatter;
42
+ /** Signed number: `3` → "+3". */
43
+ signed: (value: number | null | undefined) => string;
44
+ }>;
45
+ /** Text of a missing number: an empty period, a rate without a base. */
46
+ export declare const DASHBOARD_MISSING_VALUE = "\u2014";