@omnitend/dashboard-for-laravel 0.33.0 → 0.34.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.
- package/dist/charts.js +82 -90
- package/dist/charts.js.map +1 -1
- package/dist/charts.umd.cjs +1 -1
- package/dist/charts.umd.cjs.map +1 -1
- package/dist/components/base/DButton.vue.d.ts +1 -1
- package/dist/components/charts/DXBarChart.vue.d.ts +3 -18
- package/dist/components/charts/DXLineChart.vue.d.ts +3 -18
- package/dist/components/charts/useThemedChart.d.ts +35 -0
- package/dist/components/extended/DXChoiceField.vue.d.ts +26 -0
- package/dist/components/extended/DXDashboardSidebar.vue.d.ts +1 -1
- package/dist/components/extended/DXField.vue.d.ts +10 -113
- package/dist/components/extended/DXFieldShell.vue.d.ts +73 -0
- package/dist/components/extended/DXNumericField.vue.d.ts +23 -0
- package/dist/components/extended/DXRepeater.vue.d.ts +4 -4
- package/dist/components/extended/DXRepeaterCards.vue.d.ts +45 -0
- package/dist/components/extended/DXTable.vue.d.ts +91 -2
- package/dist/components/extended/DXTableEditorModal.vue.d.ts +17 -2
- package/dist/components/extended/DXUserAvatar.vue.d.ts +1 -1
- package/dist/composables/useAsyncOptions.d.ts +20 -0
- package/dist/composables/useResourceEditor.d.ts +2 -1
- package/dist/dashboard-for-laravel.js +9987 -10054
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +7 -7
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/style.css +1 -1
- package/dist/types/index.d.ts +146 -0
- package/dist/utils/formSchema.d.ts +59 -0
- package/docs/public/api-reference.json +464 -30
- package/docs/public/docs-map.md +1 -1
- package/docs/public/llms.txt +5 -2
- package/package.json +1 -1
- package/resources/js/components/charts/DXBarChart.vue +4 -43
- package/resources/js/components/charts/DXLineChart.vue +4 -43
- package/resources/js/components/charts/useThemedChart.ts +69 -0
- package/resources/js/components/extended/DXChoiceField.vue +114 -0
- package/resources/js/components/extended/DXField.vue +328 -615
- package/resources/js/components/extended/DXFieldShell.vue +124 -0
- package/resources/js/components/extended/DXForm.vue +9 -5
- package/resources/js/components/extended/DXNumericField.vue +144 -0
- package/resources/js/components/extended/DXRepeater.vue +53 -175
- package/resources/js/components/extended/DXRepeaterCards.vue +133 -0
- package/resources/js/components/extended/DXTable.vue +250 -37
- package/resources/js/components/extended/DXTableEditorModal.vue +34 -2
- package/resources/js/composables/defineForm.ts +8 -44
- package/resources/js/composables/useAsyncOptions.ts +61 -0
- package/resources/js/composables/useResourceEditor.ts +24 -38
- package/resources/js/index.ts +33 -0
- package/resources/js/types/index.ts +231 -0
- package/resources/js/utils/formSchema.ts +126 -0
|
@@ -14,57 +14,18 @@
|
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script setup lang="ts">
|
|
17
|
-
import { computed } from "vue";
|
|
18
17
|
import { Bar } from "vue-chartjs";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
baseOptions,
|
|
22
|
-
applyPalette,
|
|
23
|
-
mergeOptions,
|
|
24
|
-
type ChartValueFormat,
|
|
25
|
-
} from "./chartTheme";
|
|
18
|
+
import { registerCharts } from "./chartTheme";
|
|
19
|
+
import { useThemedChart, type ThemedChartProps } from "./useThemedChart";
|
|
26
20
|
|
|
27
21
|
registerCharts();
|
|
28
22
|
|
|
29
|
-
interface Props {
|
|
30
|
-
/** X-axis category labels. */
|
|
31
|
-
labels: string[];
|
|
32
|
-
/** Chart.js datasets. Colours are themed when a dataset omits them. */
|
|
33
|
-
datasets: any[];
|
|
34
|
-
/** Chart.js options; deep-merged over the themed defaults. */
|
|
35
|
-
options?: Record<string, any>;
|
|
36
|
-
/** Format value-axis ticks and tooltips. */
|
|
37
|
-
valueFormat?: ChartValueFormat;
|
|
38
|
-
/** Currency symbol for valueFormat: "currency" (default "£"). */
|
|
39
|
-
currencySymbol?: string;
|
|
40
|
-
/** Locale for number formatting. */
|
|
41
|
-
locale?: string;
|
|
42
|
-
/** Show the legend (default: only when there is more than one dataset). */
|
|
43
|
-
showLegend?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
23
|
// `showLegend` defaults to `undefined` (not Vue's Boolean-cast `false`) so the
|
|
47
24
|
// `?? datasets.length > 1` default can actually fire when it isn't passed.
|
|
48
|
-
const props = withDefaults(defineProps<
|
|
25
|
+
const props = withDefaults(defineProps<ThemedChartProps<"bar">>(), {
|
|
49
26
|
currencySymbol: "£",
|
|
50
27
|
showLegend: undefined,
|
|
51
28
|
});
|
|
52
29
|
|
|
53
|
-
const chartData =
|
|
54
|
-
labels: props.labels,
|
|
55
|
-
datasets: applyPalette(props.datasets, "bar", props.labels.length),
|
|
56
|
-
}));
|
|
57
|
-
|
|
58
|
-
const mergedOptions = computed(() =>
|
|
59
|
-
mergeOptions(
|
|
60
|
-
baseOptions({
|
|
61
|
-
valueFormat: props.valueFormat,
|
|
62
|
-
currencySymbol: props.currencySymbol,
|
|
63
|
-
locale: props.locale,
|
|
64
|
-
showLegend: props.showLegend ?? props.datasets.length > 1,
|
|
65
|
-
hasValueAxis: true,
|
|
66
|
-
}),
|
|
67
|
-
props.options ?? {},
|
|
68
|
-
),
|
|
69
|
-
);
|
|
30
|
+
const { chartData, mergedOptions } = useThemedChart("bar", props);
|
|
70
31
|
</script>
|
|
@@ -14,57 +14,18 @@
|
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script setup lang="ts">
|
|
17
|
-
import { computed } from "vue";
|
|
18
17
|
import { Line } from "vue-chartjs";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
baseOptions,
|
|
22
|
-
applyPalette,
|
|
23
|
-
mergeOptions,
|
|
24
|
-
type ChartValueFormat,
|
|
25
|
-
} from "./chartTheme";
|
|
18
|
+
import { registerCharts } from "./chartTheme";
|
|
19
|
+
import { useThemedChart, type ThemedChartProps } from "./useThemedChart";
|
|
26
20
|
|
|
27
21
|
registerCharts();
|
|
28
22
|
|
|
29
|
-
interface Props {
|
|
30
|
-
/** X-axis category labels. */
|
|
31
|
-
labels: string[];
|
|
32
|
-
/** Chart.js datasets. Colours are themed when a dataset omits them. */
|
|
33
|
-
datasets: any[];
|
|
34
|
-
/** Chart.js options; deep-merged over the themed defaults. */
|
|
35
|
-
options?: Record<string, any>;
|
|
36
|
-
/** Format value-axis ticks and tooltips. */
|
|
37
|
-
valueFormat?: ChartValueFormat;
|
|
38
|
-
/** Currency symbol for valueFormat: "currency" (default "£"). */
|
|
39
|
-
currencySymbol?: string;
|
|
40
|
-
/** Locale for number formatting. */
|
|
41
|
-
locale?: string;
|
|
42
|
-
/** Show the legend (default: only when there is more than one dataset). */
|
|
43
|
-
showLegend?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
23
|
// `showLegend` defaults to `undefined` (not Vue's Boolean-cast `false`) so the
|
|
47
24
|
// `?? datasets.length > 1` default can actually fire when it isn't passed.
|
|
48
|
-
const props = withDefaults(defineProps<
|
|
25
|
+
const props = withDefaults(defineProps<ThemedChartProps<"line">>(), {
|
|
49
26
|
currencySymbol: "£",
|
|
50
27
|
showLegend: undefined,
|
|
51
28
|
});
|
|
52
29
|
|
|
53
|
-
const chartData =
|
|
54
|
-
labels: props.labels,
|
|
55
|
-
datasets: applyPalette(props.datasets, "line", props.labels.length),
|
|
56
|
-
}));
|
|
57
|
-
|
|
58
|
-
const mergedOptions = computed(() =>
|
|
59
|
-
mergeOptions(
|
|
60
|
-
baseOptions({
|
|
61
|
-
valueFormat: props.valueFormat,
|
|
62
|
-
currencySymbol: props.currencySymbol,
|
|
63
|
-
locale: props.locale,
|
|
64
|
-
showLegend: props.showLegend ?? props.datasets.length > 1,
|
|
65
|
-
hasValueAxis: true,
|
|
66
|
-
}),
|
|
67
|
-
props.options ?? {},
|
|
68
|
-
),
|
|
69
|
-
);
|
|
30
|
+
const { chartData, mergedOptions } = useThemedChart("line", props);
|
|
70
31
|
</script>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { computed, type ComputedRef } from "vue";
|
|
2
|
+
import type { ChartData, ChartDataset, ChartOptions } from "chart.js";
|
|
3
|
+
import {
|
|
4
|
+
baseOptions,
|
|
5
|
+
applyPalette,
|
|
6
|
+
mergeOptions,
|
|
7
|
+
type ChartValueFormat,
|
|
8
|
+
} from "./chartTheme";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Shared props for the value-axis chart wrappers (`DXBarChart`, `DXLineChart`).
|
|
12
|
+
* `DXBarChart` and `DXLineChart` differ ONLY in the chart.js component they
|
|
13
|
+
* render and the palette kind — everything else (theming, option-merge,
|
|
14
|
+
* legend-default) is identical, and lived duplicated in both SFCs (#135).
|
|
15
|
+
*/
|
|
16
|
+
export interface ThemedChartProps<TType extends "bar" | "line"> {
|
|
17
|
+
/** X-axis category labels. */
|
|
18
|
+
labels: string[];
|
|
19
|
+
/** Chart.js datasets. Colours are themed when a dataset omits them. */
|
|
20
|
+
datasets: ChartDataset<TType>[];
|
|
21
|
+
/** Chart.js options; deep-merged over the themed defaults. */
|
|
22
|
+
options?: ChartOptions<TType>;
|
|
23
|
+
/** Format value-axis ticks and tooltips. */
|
|
24
|
+
valueFormat?: ChartValueFormat;
|
|
25
|
+
/** Currency symbol for valueFormat: "currency" (default "£"). */
|
|
26
|
+
currencySymbol?: string;
|
|
27
|
+
/** Locale for number formatting. */
|
|
28
|
+
locale?: string;
|
|
29
|
+
/** Show the legend (default: only when there is more than one dataset). */
|
|
30
|
+
showLegend?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The themed-chart body shared by `DXBarChart` and `DXLineChart`: applies the
|
|
35
|
+
* data-viz palette to un-coloured datasets and deep-merges the consumer's
|
|
36
|
+
* `options` over the dashboard-friendly defaults. Pass the reactive `props`
|
|
37
|
+
* object (property access stays reactive inside the computeds).
|
|
38
|
+
*/
|
|
39
|
+
export function useThemedChart<TType extends "bar" | "line">(
|
|
40
|
+
type: TType,
|
|
41
|
+
props: ThemedChartProps<TType>,
|
|
42
|
+
): {
|
|
43
|
+
chartData: ComputedRef<ChartData<TType>>;
|
|
44
|
+
mergedOptions: ComputedRef<ChartOptions<TType>>;
|
|
45
|
+
} {
|
|
46
|
+
const chartData = computed(
|
|
47
|
+
() =>
|
|
48
|
+
({
|
|
49
|
+
labels: props.labels,
|
|
50
|
+
datasets: applyPalette(props.datasets, type, props.labels.length),
|
|
51
|
+
}) as ChartData<TType>,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const mergedOptions = computed(
|
|
55
|
+
() =>
|
|
56
|
+
mergeOptions(
|
|
57
|
+
baseOptions({
|
|
58
|
+
valueFormat: props.valueFormat,
|
|
59
|
+
currencySymbol: props.currencySymbol,
|
|
60
|
+
locale: props.locale,
|
|
61
|
+
showLegend: props.showLegend ?? props.datasets.length > 1,
|
|
62
|
+
hasValueAxis: true,
|
|
63
|
+
}),
|
|
64
|
+
props.options ?? {},
|
|
65
|
+
) as ChartOptions<TType>,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return { chartData, mergedOptions };
|
|
69
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component (internal — not exported)
|
|
3
|
+
The choice control family for DXField: `select` (plain or `searchable`),
|
|
4
|
+
`radio`, and `checkbox-group`. Extracted from DXField (#135) unchanged. These
|
|
5
|
+
share the "no native readonly" convention (read-only is expressed as
|
|
6
|
+
`disabled`, hence the pre-merged `disabled` + `controlProps`). The parent
|
|
7
|
+
DXField still owns the value/options/guards and the `setValue` coercion; this
|
|
8
|
+
component only renders the control and emits the edited value up.
|
|
9
|
+
|
|
10
|
+
Plain-text `autocomplete` (a text input + datalist) stays in DXField itself,
|
|
11
|
+
with the text-family controls, because it uses the native-readonly guard path
|
|
12
|
+
rather than this disabled-only convention.
|
|
13
|
+
-->
|
|
14
|
+
<template>
|
|
15
|
+
<!-- Searchable select: type to filter a long option list, while the model
|
|
16
|
+
keeps the option's VALUE (an id), not the typed text. -->
|
|
17
|
+
<template v-if="field.type === 'select' && field.searchable">
|
|
18
|
+
<DAutocomplete
|
|
19
|
+
v-if="optionsReady"
|
|
20
|
+
:model-value="modelValue"
|
|
21
|
+
:options="options"
|
|
22
|
+
:placeholder="field.placeholder"
|
|
23
|
+
:required="field.required"
|
|
24
|
+
:state="state"
|
|
25
|
+
:disabled="disabled"
|
|
26
|
+
open-on-focus
|
|
27
|
+
v-bind="controlProps"
|
|
28
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
29
|
+
/>
|
|
30
|
+
<!-- BAutocomplete resolves the input's display text from the model AT
|
|
31
|
+
MOUNT and doesn't re-derive it when `options` arrive later, so an
|
|
32
|
+
async list would leave the raw id showing ("51" instead of
|
|
33
|
+
"Waitrose") — and a long list is exactly the case that loads async.
|
|
34
|
+
Hold the control until the options are in. -->
|
|
35
|
+
<DFormInput v-else placeholder="Loading…" disabled />
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<!-- Select (sync or async options) -->
|
|
39
|
+
<DFormSelect
|
|
40
|
+
v-else-if="field.type === 'select'"
|
|
41
|
+
:model-value="modelValue"
|
|
42
|
+
:required="field.required"
|
|
43
|
+
:options="options"
|
|
44
|
+
:state="state"
|
|
45
|
+
:disabled="disabled"
|
|
46
|
+
v-bind="controlProps"
|
|
47
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
<!-- Radio group -->
|
|
51
|
+
<DFormRadioGroup
|
|
52
|
+
v-else-if="field.type === 'radio'"
|
|
53
|
+
:model-value="modelValue"
|
|
54
|
+
:options="options"
|
|
55
|
+
:required="field.required"
|
|
56
|
+
:state="state"
|
|
57
|
+
:disabled="disabled"
|
|
58
|
+
v-bind="controlProps"
|
|
59
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<!-- Checkbox group: "pick any of N" — the model is an ARRAY of the checked
|
|
63
|
+
option values (default the field to []). -->
|
|
64
|
+
<DFormCheckboxGroup
|
|
65
|
+
v-else
|
|
66
|
+
:model-value="modelValue"
|
|
67
|
+
:options="options"
|
|
68
|
+
:state="state"
|
|
69
|
+
:disabled="disabled"
|
|
70
|
+
v-bind="controlProps"
|
|
71
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
72
|
+
/>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<script setup lang="ts">
|
|
76
|
+
import DFormSelect from "../base/DFormSelect.vue";
|
|
77
|
+
import DFormRadioGroup from "../base/DFormRadioGroup.vue";
|
|
78
|
+
import DFormCheckboxGroup from "../base/DFormCheckboxGroup.vue";
|
|
79
|
+
import DFormInput from "../base/DFormInput.vue";
|
|
80
|
+
import DAutocomplete from "../base/DAutocomplete.vue";
|
|
81
|
+
import type { FieldDefinition, FieldOption } from "../../types";
|
|
82
|
+
|
|
83
|
+
interface Props {
|
|
84
|
+
/** Field definition (type select/radio/checkbox-group + `searchable`). */
|
|
85
|
+
field: FieldDefinition;
|
|
86
|
+
|
|
87
|
+
/** Current model value. */
|
|
88
|
+
modelValue: any;
|
|
89
|
+
|
|
90
|
+
/** Resolved options (async-loaded or static). */
|
|
91
|
+
options?: FieldOption[];
|
|
92
|
+
|
|
93
|
+
/** Validation state passed to the control. */
|
|
94
|
+
state?: boolean | null;
|
|
95
|
+
|
|
96
|
+
/** Pre-merged disabled state (`isDisabled || isReadonly || isPlaintext`). */
|
|
97
|
+
disabled?: boolean;
|
|
98
|
+
|
|
99
|
+
/** Escape-hatch control props, already guard-merged by DXField. */
|
|
100
|
+
controlProps?: Record<string, any>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Whether async options have resolved (a searchable select must not render
|
|
104
|
+
* before its options load, or it shows the raw id instead of the label).
|
|
105
|
+
*/
|
|
106
|
+
optionsReady?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
defineProps<Props>();
|
|
110
|
+
|
|
111
|
+
const emit = defineEmits<{
|
|
112
|
+
(event: "update:modelValue", value: any): void;
|
|
113
|
+
}>();
|
|
114
|
+
</script>
|