@omnitend/dashboard-for-laravel 0.44.0 → 0.45.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/components/extended/DXLoading.vue.d.ts +3 -0
- package/dist/dashboard-for-laravel.js +4584 -4588
- 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/style.css +1 -1
- package/docs/public/api-reference.json +4 -4
- package/docs/public/docs-map.md +1 -1
- package/package.json +1 -1
- package/resources/css/theme.scss +120 -0
- package/resources/js/components/extended/DXField.vue +36 -8
- package/resources/js/components/extended/DXLoading.vue +18 -11
- package/resources/js/components/extended/DXTable.vue +2 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-10-
|
|
2
|
+
"generated": "2026-10-11T09:08:08.777Z",
|
|
3
3
|
"package": {
|
|
4
4
|
"name": "@omnitend/dashboard-for-laravel",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.45.0"
|
|
6
6
|
},
|
|
7
7
|
"components": {
|
|
8
8
|
"base": [
|
|
@@ -2932,8 +2932,8 @@
|
|
|
2932
2932
|
"name": "delay",
|
|
2933
2933
|
"type": "number",
|
|
2934
2934
|
"required": false,
|
|
2935
|
-
"default": "
|
|
2936
|
-
"description": ""
|
|
2935
|
+
"default": "600",
|
|
2936
|
+
"description": "Milliseconds to wait before showing anything. Most loads finish\n sooner, and one that has already taken this long is likely to take\n longer, so a quick load never flashes a loader."
|
|
2937
2937
|
}
|
|
2938
2938
|
],
|
|
2939
2939
|
"events": [],
|
package/docs/public/docs-map.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Documentation Map
|
|
2
2
|
|
|
3
3
|
> Auto-generated hierarchical overview of all documentation
|
|
4
|
-
> Last updated: 2026-10-
|
|
4
|
+
> Last updated: 2026-10-11T09:08:08.837Z
|
|
5
5
|
|
|
6
6
|
This file provides a complete map of all available documentation for AI agents and developers.
|
|
7
7
|
|
package/package.json
CHANGED
package/resources/css/theme.scss
CHANGED
|
@@ -1992,3 +1992,123 @@ $dx-chart-edge-dark: $body-bg-dark;
|
|
|
1992
1992
|
thead tr:has(.dx-table-filter-cell) > td {
|
|
1993
1993
|
padding: 0.5rem;
|
|
1994
1994
|
}
|
|
1995
|
+
|
|
1996
|
+
// ————————————————— DXLoading (the soft loader)
|
|
1997
|
+
//
|
|
1998
|
+
// Modelled on Omni Tend's legacy loader: a small grey spinner beside the
|
|
1999
|
+
// text on one line, the text in the display face with a slow light sweep
|
|
2000
|
+
// across it, fading in after DXLoading's delay. Quieter than a navy spinner,
|
|
2001
|
+
// but the text keeps AA contrast (#6c757d, 4.69:1 on white; the legacy
|
|
2002
|
+
// gray-300 was 1.5:1). The sweep passes through a lighter grey, so a moment
|
|
2003
|
+
// of the text sits below AA while it moves. Global, not scoped: DXTable and
|
|
2004
|
+
// consumers render it, and its spinner is a bvn component.
|
|
2005
|
+
//
|
|
2006
|
+
// The `role="status"` box renders at once with its contents hidden, and
|
|
2007
|
+
// `.dx-loading--shown` reveals them after the delay. Two reasons: a live
|
|
2008
|
+
// region that is already in the page announces content added to it (one
|
|
2009
|
+
// inserted together with its text can go unannounced), and the space the
|
|
2010
|
+
// loader will take is held from the start, so nothing jumps when it appears.
|
|
2011
|
+
@mixin dx-loading-light-vars {
|
|
2012
|
+
--dx-loading-color: #{$gray-600};
|
|
2013
|
+
--dx-loading-sweep-color: #{$gray-500};
|
|
2014
|
+
--dx-loading-spinner-color: #{$gray-500};
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
// `[data-bs-theme="light"]` too, so a light section inside a dark page gets
|
|
2018
|
+
// the light set back (as the chart tokens do).
|
|
2019
|
+
:root,
|
|
2020
|
+
[data-bs-theme="light"] {
|
|
2021
|
+
@include dx-loading-light-vars;
|
|
2022
|
+
// Slower than Bootstrap's 0.75 s a turn: a calmer spin to match the soft
|
|
2023
|
+
// look (1.1 s chosen against 1.5 s and 2 s side by side).
|
|
2024
|
+
--dx-loading-spinner-speed: 1.1s;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
[data-bs-theme="dark"] {
|
|
2028
|
+
--dx-loading-color: #{$gray-500};
|
|
2029
|
+
--dx-loading-sweep-color: #{$gray-600};
|
|
2030
|
+
--dx-loading-spinner-color: #{$gray-600};
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
.dx-loading {
|
|
2034
|
+
display: flex;
|
|
2035
|
+
justify-content: center;
|
|
2036
|
+
align-items: center;
|
|
2037
|
+
gap: 1rem;
|
|
2038
|
+
color: var(--dx-loading-color);
|
|
2039
|
+
|
|
2040
|
+
// Hidden, not removed: `visibility` keeps the box's size and keeps the
|
|
2041
|
+
// contents out of the accessibility tree until they are revealed.
|
|
2042
|
+
> * {
|
|
2043
|
+
visibility: hidden;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
// Set on the spinner itself: Bootstrap declares its speed on
|
|
2047
|
+
// `.spinner-border`, so a value inherited from `.dx-loading` would lose.
|
|
2048
|
+
.spinner-border {
|
|
2049
|
+
flex: none;
|
|
2050
|
+
color: var(--dx-loading-spinner-color);
|
|
2051
|
+
--bs-spinner-animation-speed: var(--dx-loading-spinner-speed);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
.dx-loading--shown {
|
|
2056
|
+
animation: dx-loading-fade-in 0.4s ease-out both;
|
|
2057
|
+
|
|
2058
|
+
> * {
|
|
2059
|
+
visibility: visible;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
.dx-loading__text {
|
|
2064
|
+
margin: 0;
|
|
2065
|
+
font-family: var(--dx-font-family-display);
|
|
2066
|
+
font-weight: 500;
|
|
2067
|
+
font-size: $h2-font-size;
|
|
2068
|
+
line-height: $headings-line-height;
|
|
2069
|
+
background-image: linear-gradient(
|
|
2070
|
+
to right,
|
|
2071
|
+
var(--dx-loading-color) 20%,
|
|
2072
|
+
var(--dx-loading-color) 40%,
|
|
2073
|
+
var(--dx-loading-sweep-color) 60%,
|
|
2074
|
+
var(--dx-loading-sweep-color) 80%,
|
|
2075
|
+
var(--dx-loading-color) 99%
|
|
2076
|
+
);
|
|
2077
|
+
background-size: 200% auto;
|
|
2078
|
+
-webkit-background-clip: text;
|
|
2079
|
+
background-clip: text;
|
|
2080
|
+
-webkit-text-fill-color: transparent;
|
|
2081
|
+
animation: dx-loading-sweep 3s linear infinite;
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
@keyframes dx-loading-fade-in {
|
|
2085
|
+
from {
|
|
2086
|
+
opacity: 0;
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
@keyframes dx-loading-sweep {
|
|
2091
|
+
to {
|
|
2092
|
+
background-position: 200% center;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
// For people who asked for less motion: no sweep and no fade (the text is
|
|
2097
|
+
// plain grey and appears at once), and the spinner slows to double its turn,
|
|
2098
|
+
// as Bootstrap's own reduced-motion rule does for its spinners. That rule
|
|
2099
|
+
// cannot reach this one, because the speed above out-ranks it.
|
|
2100
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2101
|
+
.dx-loading--shown,
|
|
2102
|
+
.dx-loading__text {
|
|
2103
|
+
animation: none;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
.dx-loading__text {
|
|
2107
|
+
background-image: none;
|
|
2108
|
+
-webkit-text-fill-color: currentColor;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
.dx-loading .spinner-border {
|
|
2112
|
+
--bs-spinner-animation-speed: calc(2 * var(--dx-loading-spinner-speed));
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
@@ -405,7 +405,14 @@ import DXNumericField from "./DXNumericField.vue";
|
|
|
405
405
|
import DXChoiceField from "./DXChoiceField.vue";
|
|
406
406
|
import { useAsyncOptions } from "../../composables/useAsyncOptions";
|
|
407
407
|
import type { UseFormReturn } from "../../composables/useForm";
|
|
408
|
-
import type {
|
|
408
|
+
import type {
|
|
409
|
+
FieldDefinition,
|
|
410
|
+
FieldOption,
|
|
411
|
+
FieldType,
|
|
412
|
+
LabelCols,
|
|
413
|
+
MaybeFn,
|
|
414
|
+
} from "../../types";
|
|
415
|
+
import { humaniseErrorKey } from "../../utils/formErrorTargets";
|
|
409
416
|
import { getByPath, setByPath } from "../../utils/objectPath";
|
|
410
417
|
|
|
411
418
|
// Async to break the DXField <-> DXRepeater circular import.
|
|
@@ -619,6 +626,21 @@ function resolveMaybe<TValue>(
|
|
|
619
626
|
return value;
|
|
620
627
|
}
|
|
621
628
|
|
|
629
|
+
/** Resolve display TEXT (label, hint, info, switch text) the way
|
|
630
|
+
* resolveMaybe does, but a function that throws (a repeater row missing a
|
|
631
|
+
* property it reads) gives `undefined` instead of breaking the render (#204).
|
|
632
|
+
* Behaviour options (disabled, readonly, plaintext) stay unguarded: no
|
|
633
|
+
* fallback for those is safe to guess. */
|
|
634
|
+
function resolveText(
|
|
635
|
+
value: MaybeFn<string> | undefined,
|
|
636
|
+
): string | undefined {
|
|
637
|
+
try {
|
|
638
|
+
return resolveMaybe(value);
|
|
639
|
+
} catch {
|
|
640
|
+
return undefined;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
622
644
|
const fieldValue = computed({
|
|
623
645
|
get: () =>
|
|
624
646
|
usePathSemantics.value
|
|
@@ -691,13 +713,19 @@ function setValue(value: any): void {
|
|
|
691
713
|
|
|
692
714
|
const fieldState = computed(() => props.form.getState(errorKey.value));
|
|
693
715
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
716
|
+
// A label function that throws falls back to the humanised key, as the
|
|
717
|
+
// repeater's headers and the error summary do; a missing label still shows
|
|
718
|
+
// the raw key, as it always has.
|
|
719
|
+
const resolvedLabel = computed(() => {
|
|
720
|
+
if (typeof props.field.label !== "function") {
|
|
721
|
+
return props.field.label ?? props.field.key;
|
|
722
|
+
}
|
|
723
|
+
return resolveText(props.field.label) ?? humaniseErrorKey(props.field.key);
|
|
724
|
+
});
|
|
697
725
|
|
|
698
|
-
const resolvedHint = computed(() =>
|
|
726
|
+
const resolvedHint = computed(() => resolveText(props.field.hint));
|
|
699
727
|
|
|
700
|
-
const resolvedInfo = computed(() =>
|
|
728
|
+
const resolvedInfo = computed(() => resolveText(props.field.info));
|
|
701
729
|
|
|
702
730
|
// ————————————————— switch-list (#160)
|
|
703
731
|
|
|
@@ -763,8 +791,8 @@ const switchModel = computed({
|
|
|
763
791
|
*/
|
|
764
792
|
const switchText = computed(() => {
|
|
765
793
|
const contextual = switchIsOn.value
|
|
766
|
-
?
|
|
767
|
-
:
|
|
794
|
+
? resolveText(props.field.textWhenTrue)
|
|
795
|
+
: resolveText(props.field.textWhenFalse);
|
|
768
796
|
return contextual ?? resolvedLabel.value;
|
|
769
797
|
});
|
|
770
798
|
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<!-- The status box is there from the start, holding the loader's space
|
|
3
|
+
with its contents hidden (theme.scss); the delay only reveals them.
|
|
4
|
+
Content added to a live region already in the page is announced,
|
|
5
|
+
where a region inserted with its text can be missed. -->
|
|
2
6
|
<div
|
|
3
|
-
|
|
4
|
-
class="dx-loading
|
|
7
|
+
class="dx-loading py-5"
|
|
8
|
+
:class="{ 'dx-loading--shown': isVisible }"
|
|
5
9
|
role="status"
|
|
6
10
|
aria-live="polite"
|
|
7
11
|
>
|
|
8
|
-
<DSpinner
|
|
9
|
-
<
|
|
12
|
+
<DSpinner small aria-hidden="true" />
|
|
13
|
+
<p class="dx-loading__text">{{ text }}</p>
|
|
10
14
|
</div>
|
|
11
15
|
</template>
|
|
12
16
|
|
|
@@ -14,14 +18,20 @@
|
|
|
14
18
|
import { onBeforeUnmount, onMounted, ref } from "vue";
|
|
15
19
|
import DSpinner from "../base/DSpinner.vue";
|
|
16
20
|
|
|
21
|
+
// Styles (one line, grey, a slow sweep across the text, a fade-in, contents
|
|
22
|
+
// hidden until `.dx-loading--shown`) are global in theme.scss under
|
|
23
|
+
// `.dx-loading`, with `--dx-loading-*` tokens.
|
|
17
24
|
const props = withDefaults(
|
|
18
25
|
defineProps<{
|
|
19
26
|
text?: string;
|
|
27
|
+
/** Milliseconds to wait before showing anything. Most loads finish
|
|
28
|
+
* sooner, and one that has already taken this long is likely to take
|
|
29
|
+
* longer, so a quick load never flashes a loader. */
|
|
20
30
|
delay?: number;
|
|
21
31
|
}>(),
|
|
22
32
|
{
|
|
23
33
|
text: "Loading…",
|
|
24
|
-
delay:
|
|
34
|
+
delay: 600,
|
|
25
35
|
},
|
|
26
36
|
);
|
|
27
37
|
|
|
@@ -29,14 +39,11 @@ const isVisible = ref(false);
|
|
|
29
39
|
let showTimer: ReturnType<typeof setTimeout> | undefined;
|
|
30
40
|
|
|
31
41
|
onMounted(() => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
42
|
+
// Always a timer, even for no delay: the empty status box must reach the
|
|
43
|
+
// page a task before its contents, or the announcement can be missed.
|
|
37
44
|
showTimer = setTimeout(() => {
|
|
38
45
|
isVisible.value = true;
|
|
39
|
-
}, props.delay);
|
|
46
|
+
}, Math.max(props.delay, 0));
|
|
40
47
|
});
|
|
41
48
|
|
|
42
49
|
onBeforeUnmount(() => {
|
|
@@ -35,10 +35,7 @@
|
|
|
35
35
|
{{ error || apiError }}
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
|
-
<
|
|
39
|
-
<DSpinner variant="primary" />
|
|
40
|
-
<p class="mt-2">{{ loadingText }}</p>
|
|
41
|
-
</div>
|
|
38
|
+
<DXLoading v-if="effectiveBusy && !isProviderMode" :text="loadingText" />
|
|
42
39
|
|
|
43
40
|
<!-- One table for all three data modes. The modes differ only
|
|
44
41
|
in a few bound props, supplied by `tableModeBindings`, so
|
|
@@ -326,7 +323,7 @@ import DContainer from "../base/DContainer.vue";
|
|
|
326
323
|
import DRow from "../base/DRow.vue";
|
|
327
324
|
import DCol from "../base/DCol.vue";
|
|
328
325
|
import DXTableShell from "./DXTableShell.vue";
|
|
329
|
-
import
|
|
326
|
+
import DXLoading from "./DXLoading.vue";
|
|
330
327
|
import DTable from "../base/DTable.vue";
|
|
331
328
|
import DFormInput from "../base/DFormInput.vue";
|
|
332
329
|
import DFormSelect from "../base/DFormSelect.vue";
|