@xleddyl/443-components-vue 0.10.2 → 0.11.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/CATALOG.md +185 -175
- package/README.md +47 -21
- package/dist/components/data/Tag.vue +2 -0
- package/dist/components/data/Tag.vue.d.ts +2 -0
- package/dist/components/data/TagList.vue +239 -0
- package/dist/components/data/TagList.vue.d.ts +53 -0
- package/dist/components/data/index.d.ts +1 -0
- package/dist/components/data/index.mjs +1 -0
- package/dist/components/data/types.d.ts +15 -0
- package/dist/components/forms/Combobox.vue +33 -4
- package/dist/components/forms/Combobox.vue.d.ts +3 -1
- package/dist/components/forms/NumberInput.vue.d.ts +1 -1
- package/dist/components/forms/PinInput.vue.d.ts +2 -2
- package/dist/components/forms/types.d.ts +2 -0
- package/dist/components/layout/AppShell.vue +14 -2
- package/dist/components/layout/AppShell.vue.d.ts +3 -1
- package/dist/components/layout/Stepper.vue +148 -0
- package/dist/components/layout/Stepper.vue.d.ts +420 -0
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/index.mjs +1 -0
- package/dist/components/layout/types.d.ts +12 -0
- package/dist/components/overlays/Toaster.vue +10 -0
- package/dist/components/overlays/Toaster.vue.d.ts +1 -1
- package/dist/components/templates/DashboardLayout.vue +2 -0
- package/dist/components/templates/DashboardLayout.vue.d.ts +3 -1
- package/dist/components/templates/types.d.ts +2 -1
- package/dist/composables/data.d.ts +1 -0
- package/dist/composables/data.mjs +1 -0
- package/dist/composables/useSortable.d.ts +38 -0
- package/dist/composables/useSortable.mjs +215 -0
- package/dist/grid/cells/BadgeCell.vue +90 -18
- package/dist/grid/cells/BadgeCell.vue.d.ts +14 -14
- package/dist/grid/data-grid.css +24 -0
- package/dist/grid/spreadsheet.mjs +8 -4
- package/dist/grid/types.d.ts +2 -0
- package/dist/internal/data/sortable.d.ts +5 -0
- package/dist/internal/data/sortable.mjs +23 -0
- package/dist/internal/overlays/avoid.d.ts +26 -0
- package/dist/internal/overlays/avoid.mjs +134 -0
- package/dist/locale/de.mjs +20 -0
- package/dist/locale/en.mjs +20 -0
- package/dist/locale/it.mjs +20 -0
- package/dist/locale/types.d.ts +20 -0
- package/dist/nuxt/module.mjs +14 -0
- package/dist/nuxt/runtime/layouts/dashboard.vue +8 -1
- package/dist/styles/data/tag-list.css +93 -0
- package/dist/styles/data.css +1 -0
- package/dist/styles/forced-colors.css +10 -0
- package/dist/styles/layout/app-shell.css +23 -0
- package/dist/styles/layout/stepper.css +244 -0
- package/dist/styles/layout.css +1 -0
- package/dist/styles/overlays/toast.css +17 -12
- package/package.json +1 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { nextTick, onScopeDispose, readonly, ref, toValue } from "vue";
|
|
2
|
+
import { useLocale } from "./useLocale.mjs";
|
|
3
|
+
import { useLiveMessage } from "../internal/core/live.mjs";
|
|
4
|
+
import { isClient } from "../internal/core/env.mjs";
|
|
5
|
+
import { SORTABLE_ATTR, insertionIndex, isRtl, sortableElements } from "../internal/data/sortable.mjs";
|
|
6
|
+
const THRESHOLD = 4;
|
|
7
|
+
const INTERACTIVE = "button, a[href], input, textarea, select, [contenteditable]";
|
|
8
|
+
export function useSortable(container, options) {
|
|
9
|
+
const { t } = useLocale();
|
|
10
|
+
const live = useLiveMessage();
|
|
11
|
+
const dragging = ref(null);
|
|
12
|
+
let drag = null;
|
|
13
|
+
const axis = () => toValue(options.orientation) ?? "vertical";
|
|
14
|
+
const isDisabled = () => Boolean(toValue(options.disabled));
|
|
15
|
+
const list = () => toValue(options.items);
|
|
16
|
+
function movable(index) {
|
|
17
|
+
const item = list()[index];
|
|
18
|
+
if (item === void 0 || isDisabled()) return false;
|
|
19
|
+
return options.canMove ? options.canMove(item, index) : true;
|
|
20
|
+
}
|
|
21
|
+
function labelOf(item) {
|
|
22
|
+
return options.label ? options.label(item) : String(item);
|
|
23
|
+
}
|
|
24
|
+
function announceMove(move2) {
|
|
25
|
+
live.announce(
|
|
26
|
+
options.movedText ? options.movedText(move2) : t("sortable.moved", {
|
|
27
|
+
label: labelOf(move2.item),
|
|
28
|
+
position: move2.to + 1,
|
|
29
|
+
count: move2.items.length
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
function move(from, to, moveOptions = {}) {
|
|
34
|
+
const items = list();
|
|
35
|
+
const target = Math.max(0, Math.min(items.length - 1, to));
|
|
36
|
+
if (from === target || !movable(from)) return false;
|
|
37
|
+
const next = [...items];
|
|
38
|
+
const [item] = next.splice(from, 1);
|
|
39
|
+
next.splice(target, 0, item);
|
|
40
|
+
const entry = {
|
|
41
|
+
item,
|
|
42
|
+
from,
|
|
43
|
+
to: target,
|
|
44
|
+
items: next,
|
|
45
|
+
source: moveOptions.source ?? "api"
|
|
46
|
+
};
|
|
47
|
+
const focused = isClient() ? document.activeElement : null;
|
|
48
|
+
options.onMove(next, entry);
|
|
49
|
+
if (moveOptions.announce) announceMove(entry);
|
|
50
|
+
if (focused && focused !== document.body)
|
|
51
|
+
nextTick(() => {
|
|
52
|
+
if (focused.isConnected && document.activeElement !== focused)
|
|
53
|
+
focused.focus({ preventScroll: true });
|
|
54
|
+
});
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
function keyDelta(event) {
|
|
58
|
+
const rtl = isRtl(event.currentTarget);
|
|
59
|
+
switch (event.key) {
|
|
60
|
+
case "ArrowUp":
|
|
61
|
+
return -1;
|
|
62
|
+
case "ArrowDown":
|
|
63
|
+
return 1;
|
|
64
|
+
case "ArrowLeft":
|
|
65
|
+
return rtl ? 1 : -1;
|
|
66
|
+
case "ArrowRight":
|
|
67
|
+
return rtl ? -1 : 1;
|
|
68
|
+
case "Home":
|
|
69
|
+
return -Infinity;
|
|
70
|
+
case "End":
|
|
71
|
+
return Infinity;
|
|
72
|
+
default:
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function onKeydown(event, index) {
|
|
77
|
+
if (!event.altKey || event.ctrlKey || event.metaKey) return;
|
|
78
|
+
const delta = keyDelta(event);
|
|
79
|
+
if (!delta) return;
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
const to = delta === -Infinity ? 0 : delta === Infinity ? list().length - 1 : index + delta;
|
|
82
|
+
move(index, to, { announce: true, source: "keyboard" });
|
|
83
|
+
}
|
|
84
|
+
function preventSelection(event) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
}
|
|
87
|
+
function suppressClick(event) {
|
|
88
|
+
event.preventDefault();
|
|
89
|
+
event.stopPropagation();
|
|
90
|
+
}
|
|
91
|
+
function listen(enable) {
|
|
92
|
+
if (enable) {
|
|
93
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
94
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
95
|
+
window.addEventListener("pointercancel", onPointerCancel);
|
|
96
|
+
window.addEventListener("keydown", onDragKeydown, true);
|
|
97
|
+
document.addEventListener("selectstart", preventSelection);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
101
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
102
|
+
window.removeEventListener("pointercancel", onPointerCancel);
|
|
103
|
+
window.removeEventListener("keydown", onDragKeydown, true);
|
|
104
|
+
document.removeEventListener("selectstart", preventSelection);
|
|
105
|
+
}
|
|
106
|
+
function follow(event) {
|
|
107
|
+
if (!drag) return;
|
|
108
|
+
const element = drag.element;
|
|
109
|
+
const current = element.style.translate.split(" ").map((value) => parseFloat(value) || 0);
|
|
110
|
+
const rect = element.getBoundingClientRect();
|
|
111
|
+
const layoutX = rect.left - (current[0] ?? 0);
|
|
112
|
+
const layoutY = rect.top - (current[1] ?? 0);
|
|
113
|
+
const x = event.clientX - drag.startX - (layoutX - drag.layoutX);
|
|
114
|
+
const y = event.clientY - drag.startY - (layoutY - drag.layoutY);
|
|
115
|
+
element.style.translate = `${x}px ${y}px`;
|
|
116
|
+
}
|
|
117
|
+
function onPointerDown(event, index) {
|
|
118
|
+
if (event.button !== 0 || !event.isPrimary || drag) return;
|
|
119
|
+
const element = event.currentTarget;
|
|
120
|
+
const target = event.target;
|
|
121
|
+
if (options.handle) {
|
|
122
|
+
if (!target.closest(options.handle)) return;
|
|
123
|
+
} else if (target !== element && target.closest(INTERACTIVE)) return;
|
|
124
|
+
if (!movable(index)) return;
|
|
125
|
+
const rect = element.getBoundingClientRect();
|
|
126
|
+
drag = {
|
|
127
|
+
pointerId: event.pointerId,
|
|
128
|
+
element,
|
|
129
|
+
origin: index,
|
|
130
|
+
index,
|
|
131
|
+
startX: event.clientX,
|
|
132
|
+
startY: event.clientY,
|
|
133
|
+
layoutX: rect.left,
|
|
134
|
+
layoutY: rect.top,
|
|
135
|
+
active: false
|
|
136
|
+
};
|
|
137
|
+
listen(true);
|
|
138
|
+
}
|
|
139
|
+
function onPointerMove(event) {
|
|
140
|
+
if (!drag || event.pointerId !== drag.pointerId) return;
|
|
141
|
+
if (!drag.active) {
|
|
142
|
+
if (Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) < THRESHOLD)
|
|
143
|
+
return;
|
|
144
|
+
drag.active = true;
|
|
145
|
+
dragging.value = drag.index;
|
|
146
|
+
window.getSelection()?.removeAllRanges();
|
|
147
|
+
}
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
const root = toValue(container);
|
|
150
|
+
const others = sortableElements(root).filter((element) => element !== drag.element);
|
|
151
|
+
const target = insertionIndex(others, event.clientX, event.clientY, axis(), isRtl(root));
|
|
152
|
+
if (target !== drag.index && move(drag.index, target, { source: "pointer" })) {
|
|
153
|
+
drag.index = target;
|
|
154
|
+
dragging.value = target;
|
|
155
|
+
nextTick(() => follow(event));
|
|
156
|
+
}
|
|
157
|
+
follow(event);
|
|
158
|
+
}
|
|
159
|
+
function finish(cancelled) {
|
|
160
|
+
const state = drag;
|
|
161
|
+
drag = null;
|
|
162
|
+
listen(false);
|
|
163
|
+
if (!state) return;
|
|
164
|
+
state.element.style.translate = "";
|
|
165
|
+
dragging.value = null;
|
|
166
|
+
if (!state.active) return;
|
|
167
|
+
window.addEventListener("click", suppressClick, { capture: true, once: true });
|
|
168
|
+
setTimeout(() => window.removeEventListener("click", suppressClick, { capture: true }), 0);
|
|
169
|
+
if (cancelled) {
|
|
170
|
+
if (state.index !== state.origin) move(state.index, state.origin, { source: "pointer" });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (state.index !== state.origin) {
|
|
174
|
+
const items = list();
|
|
175
|
+
const item = items[state.index];
|
|
176
|
+
announceMove({
|
|
177
|
+
item,
|
|
178
|
+
from: state.origin,
|
|
179
|
+
to: state.index,
|
|
180
|
+
items: [...items],
|
|
181
|
+
source: "pointer"
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function onPointerUp(event) {
|
|
186
|
+
if (drag && event.pointerId === drag.pointerId) finish(false);
|
|
187
|
+
}
|
|
188
|
+
function onPointerCancel(event) {
|
|
189
|
+
if (drag && event.pointerId === drag.pointerId) finish(true);
|
|
190
|
+
}
|
|
191
|
+
function onDragKeydown(event) {
|
|
192
|
+
if (event.key !== "Escape" || !drag?.active) return;
|
|
193
|
+
event.preventDefault();
|
|
194
|
+
event.stopPropagation();
|
|
195
|
+
finish(true);
|
|
196
|
+
}
|
|
197
|
+
function itemProps(index) {
|
|
198
|
+
return {
|
|
199
|
+
[SORTABLE_ATTR]: index,
|
|
200
|
+
"aria-keyshortcuts": movable(index) ? "Alt+ArrowLeft Alt+ArrowRight Alt+ArrowUp Alt+ArrowDown Alt+Home Alt+End" : void 0,
|
|
201
|
+
onPointerdown: (event) => onPointerDown(event, index),
|
|
202
|
+
onKeydown: (event) => onKeydown(event, index)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
onScopeDispose(() => {
|
|
206
|
+
if (drag) finish(true);
|
|
207
|
+
});
|
|
208
|
+
return {
|
|
209
|
+
dragging: readonly(dragging),
|
|
210
|
+
announcement: live.message,
|
|
211
|
+
itemProps,
|
|
212
|
+
move,
|
|
213
|
+
canMove: movable
|
|
214
|
+
};
|
|
215
|
+
}
|
|
@@ -1,11 +1,60 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
<span
|
|
3
|
+
v-if="isList && entries.length"
|
|
4
|
+
class="k-data-grid-badges"
|
|
5
|
+
:class="{ 'is-wrap': params.wrap }"
|
|
6
|
+
:title="fullText"
|
|
7
|
+
>
|
|
8
|
+
<template v-for="entry in shown" :key="entry.key">
|
|
9
|
+
<Badge
|
|
10
|
+
v-if="params.variant"
|
|
11
|
+
:class="entry.badgeClass"
|
|
12
|
+
:tone="entry.tone"
|
|
13
|
+
:variant="params.variant"
|
|
14
|
+
:size
|
|
15
|
+
>{{ entry.text }}</Badge
|
|
16
|
+
>
|
|
17
|
+
<span
|
|
18
|
+
v-else
|
|
19
|
+
class="k-data-grid-badge"
|
|
20
|
+
:class="[`k-data-grid-badge-${entry.tone}`, entry.badgeClass]"
|
|
21
|
+
>{{ entry.text }}</span
|
|
22
|
+
>
|
|
23
|
+
</template>
|
|
24
|
+
<template v-if="hiddenCount > 0">
|
|
25
|
+
<Badge
|
|
26
|
+
v-if="params.variant"
|
|
27
|
+
class="k-data-grid-badge-more"
|
|
28
|
+
tone="neutral"
|
|
29
|
+
:variant="params.variant"
|
|
30
|
+
:size
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
>+{{ hiddenCount }}</Badge
|
|
33
|
+
>
|
|
34
|
+
<span
|
|
35
|
+
v-else
|
|
36
|
+
class="k-data-grid-badge k-data-grid-badge-neutral k-data-grid-badge-more"
|
|
37
|
+
aria-hidden="true"
|
|
38
|
+
>+{{ hiddenCount }}</span
|
|
39
|
+
>
|
|
40
|
+
<span class="k-visually-hidden">{{ moreText }}</span>
|
|
41
|
+
</template>
|
|
42
|
+
</span>
|
|
43
|
+
<template v-else-if="!isList && single">
|
|
44
|
+
<Badge
|
|
45
|
+
v-if="params.variant"
|
|
46
|
+
:class="single.badgeClass"
|
|
47
|
+
:tone="single.tone"
|
|
48
|
+
:variant="params.variant"
|
|
49
|
+
:size
|
|
50
|
+
>{{ single.text }}</Badge
|
|
51
|
+
>
|
|
52
|
+
<span
|
|
53
|
+
v-else
|
|
54
|
+
class="k-data-grid-badge"
|
|
55
|
+
:class="[`k-data-grid-badge-${single.tone}`, single.badgeClass]"
|
|
56
|
+
>{{ single.text }}</span
|
|
57
|
+
>
|
|
9
58
|
</template>
|
|
10
59
|
<EmptyCell v-else :context="cellContext" />
|
|
11
60
|
</template>
|
|
@@ -13,22 +62,45 @@
|
|
|
13
62
|
<script setup>
|
|
14
63
|
import { computed } from "vue";
|
|
15
64
|
import Badge from "../../components/data/Badge.vue";
|
|
65
|
+
import { formatLocaleMessage } from "../../locale";
|
|
16
66
|
import EmptyCell from "./EmptyCell.vue";
|
|
17
67
|
const props = defineProps({
|
|
18
68
|
params: { type: Object, required: true }
|
|
19
69
|
});
|
|
20
|
-
const
|
|
21
|
-
const raw = props.params.value;
|
|
22
|
-
return raw === null || raw === void 0 ? "" : String(raw);
|
|
23
|
-
});
|
|
24
|
-
const text = computed(() => key.value ? props.params.labels?.[key.value] ?? key.value : "");
|
|
25
|
-
const tone = computed(
|
|
26
|
-
() => props.params.tones?.[key.value] ?? props.params.defaultTone ?? "neutral"
|
|
27
|
-
);
|
|
70
|
+
const cellContext = computed(() => props.params.context);
|
|
28
71
|
const size = computed(() => props.params.size ?? "sm");
|
|
29
|
-
const
|
|
72
|
+
const isList = computed(() => Array.isArray(props.params.value));
|
|
73
|
+
function keyOf(raw) {
|
|
74
|
+
return raw === null || raw === void 0 ? "" : String(raw);
|
|
75
|
+
}
|
|
76
|
+
function entryFor(raw, index) {
|
|
77
|
+
const key = keyOf(raw);
|
|
78
|
+
if (!key) return null;
|
|
30
79
|
const source = props.params.badgeClass;
|
|
31
|
-
return
|
|
80
|
+
return {
|
|
81
|
+
key: `${index}-${key}`,
|
|
82
|
+
text: props.params.labels?.[key] ?? key,
|
|
83
|
+
tone: props.params.tones?.[key] ?? props.params.defaultTone ?? "neutral",
|
|
84
|
+
badgeClass: typeof source === "function" ? source(raw, props.params.data) : source
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const single = computed(() => isList.value ? null : entryFor(props.params.value, 0));
|
|
88
|
+
const entries = computed(() => {
|
|
89
|
+
if (!isList.value) return [];
|
|
90
|
+
return props.params.value.map((raw, index) => entryFor(raw, index)).filter((entry) => entry !== null);
|
|
32
91
|
});
|
|
33
|
-
const
|
|
92
|
+
const limit = computed(() => {
|
|
93
|
+
const max = props.params.max;
|
|
94
|
+
return max === void 0 || max < 1 ? entries.value.length : Math.floor(max);
|
|
95
|
+
});
|
|
96
|
+
const shown = computed(() => entries.value.slice(0, limit.value));
|
|
97
|
+
const hiddenCount = computed(() => entries.value.length - shown.value.length);
|
|
98
|
+
const fullText = computed(() => entries.value.map((entry) => entry.text).join(", "));
|
|
99
|
+
const moreText = computed(
|
|
100
|
+
() => formatLocaleMessage(
|
|
101
|
+
cellContext.value?.locale ?? "en",
|
|
102
|
+
cellContext.value?.messages?.moreValues ?? "{count} more",
|
|
103
|
+
{ count: hiddenCount.value }
|
|
104
|
+
)
|
|
105
|
+
);
|
|
34
106
|
</script>
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import type { BadgeCellParams, GridCellContext } from '../types';
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<{
|
|
3
3
|
params: import("ag-grid-community").ICellRendererParams<any, any, any> & BadgeCellParams<unknown>;
|
|
4
|
-
label?: string | number;
|
|
5
|
-
tone?: import("../../index.ts").Tone;
|
|
6
|
-
variant?: import("../../index.ts").BadgeVariant;
|
|
7
|
-
size?: import("../../index.ts").BadgeSize;
|
|
8
|
-
dot?: boolean;
|
|
9
|
-
pulse?: boolean;
|
|
10
|
-
icon?: import("../../index.ts").IconName;
|
|
11
4
|
innerHTML?: string | undefined | undefined;
|
|
12
5
|
class?: import("vue").ClassValue;
|
|
13
6
|
style?: import("vue").StyleValue;
|
|
@@ -200,6 +193,13 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
200
193
|
ref?: import("vue").VNodeRef | undefined;
|
|
201
194
|
ref_for?: boolean | undefined | undefined;
|
|
202
195
|
ref_key?: string | undefined | undefined;
|
|
196
|
+
label?: string | number;
|
|
197
|
+
tone?: import("../../index.ts").Tone;
|
|
198
|
+
variant?: import("../../index.ts").BadgeVariant;
|
|
199
|
+
size?: import("../../index.ts").BadgeSize;
|
|
200
|
+
dot?: boolean;
|
|
201
|
+
pulse?: boolean;
|
|
202
|
+
icon?: import("../../index.ts").IconName;
|
|
203
203
|
onVnodeBeforeMount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
|
|
204
204
|
onVnodeMounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
|
|
205
205
|
onVnodeBeforeUpdate?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
|
|
@@ -209,13 +209,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
209
209
|
context?: GridCellContext;
|
|
210
210
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
211
211
|
params: import("ag-grid-community").ICellRendererParams<any, any, any> & BadgeCellParams<unknown>;
|
|
212
|
-
label?: string | number;
|
|
213
|
-
tone?: import("../../index.ts").Tone;
|
|
214
|
-
variant?: import("../../index.ts").BadgeVariant;
|
|
215
|
-
size?: import("../../index.ts").BadgeSize;
|
|
216
|
-
dot?: boolean;
|
|
217
|
-
pulse?: boolean;
|
|
218
|
-
icon?: import("../../index.ts").IconName;
|
|
219
212
|
innerHTML?: string | undefined | undefined;
|
|
220
213
|
class?: import("vue").ClassValue;
|
|
221
214
|
style?: import("vue").StyleValue;
|
|
@@ -408,6 +401,13 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
408
401
|
ref?: import("vue").VNodeRef | undefined;
|
|
409
402
|
ref_for?: boolean | undefined | undefined;
|
|
410
403
|
ref_key?: string | undefined | undefined;
|
|
404
|
+
label?: string | number;
|
|
405
|
+
tone?: import("../../index.ts").Tone;
|
|
406
|
+
variant?: import("../../index.ts").BadgeVariant;
|
|
407
|
+
size?: import("../../index.ts").BadgeSize;
|
|
408
|
+
dot?: boolean;
|
|
409
|
+
pulse?: boolean;
|
|
410
|
+
icon?: import("../../index.ts").IconName;
|
|
411
411
|
onVnodeBeforeMount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
|
|
412
412
|
onVnodeMounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
|
|
413
413
|
onVnodeBeforeUpdate?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
|
package/dist/grid/data-grid.css
CHANGED
|
@@ -163,6 +163,30 @@
|
|
|
163
163
|
white-space: nowrap;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
.k-data-grid-badges {
|
|
167
|
+
display: flex;
|
|
168
|
+
flex-wrap: nowrap;
|
|
169
|
+
align-items: center;
|
|
170
|
+
gap: 0.25rem;
|
|
171
|
+
min-width: 0;
|
|
172
|
+
max-width: 100%;
|
|
173
|
+
overflow: hidden;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.k-data-grid-badges.is-wrap {
|
|
177
|
+
flex-wrap: wrap;
|
|
178
|
+
padding-block: 0.25rem;
|
|
179
|
+
line-height: 1.2;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.k-data-grid-badges > * {
|
|
183
|
+
flex-shrink: 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.k-data-grid-badges > .k-data-grid-badge-more {
|
|
187
|
+
font-variant-numeric: tabular-nums;
|
|
188
|
+
}
|
|
189
|
+
|
|
166
190
|
.k-data-grid-badge-accent {
|
|
167
191
|
--k-badge-tone: var(--k-accent-text);
|
|
168
192
|
}
|
|
@@ -102,15 +102,19 @@ export function createGridSpreadsheet(options) {
|
|
|
102
102
|
const inside = cell.row >= rect.top && cell.row <= rect.bottom && cell.col >= rect.left && cell.col <= rect.right;
|
|
103
103
|
return inside ? cell : null;
|
|
104
104
|
}
|
|
105
|
+
function onRangeEdge(params, edge) {
|
|
106
|
+
const cell = rangeCell(params);
|
|
107
|
+
return !!cell && !!rect && edge(cell, rect);
|
|
108
|
+
}
|
|
105
109
|
const classRules = {
|
|
106
110
|
"is-range": (params) => {
|
|
107
111
|
const cell = rangeCell(params);
|
|
108
112
|
return !!cell && !sameCell(cell, active);
|
|
109
113
|
},
|
|
110
|
-
"is-range-top": (params) =>
|
|
111
|
-
"is-range-bottom": (params) =>
|
|
112
|
-
"is-range-left": (params) =>
|
|
113
|
-
"is-range-right": (params) =>
|
|
114
|
+
"is-range-top": (params) => onRangeEdge(params, (cell, area) => cell.row === area.top),
|
|
115
|
+
"is-range-bottom": (params) => onRangeEdge(params, (cell, area) => cell.row === area.bottom),
|
|
116
|
+
"is-range-left": (params) => onRangeEdge(params, (cell, area) => cell.col === area.left),
|
|
117
|
+
"is-range-right": (params) => onRangeEdge(params, (cell, area) => cell.col === area.right),
|
|
114
118
|
"is-active": (params) => !!active && sameCell(cellOf(params), active),
|
|
115
119
|
"is-fill-corner": (params) => {
|
|
116
120
|
if (!rect) return false;
|
package/dist/grid/types.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ export interface BadgeCellParams<T = unknown> {
|
|
|
49
49
|
variant?: BadgeVariant;
|
|
50
50
|
size?: BadgeSize;
|
|
51
51
|
badgeClass?: string | ((value: unknown, data: T | undefined) => string | undefined);
|
|
52
|
+
max?: number;
|
|
53
|
+
wrap?: boolean;
|
|
52
54
|
}
|
|
53
55
|
export type ImageCellFit = 'cover' | 'contain';
|
|
54
56
|
export interface ImageCellParams<T = unknown> {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type SortableAxis = 'horizontal' | 'vertical';
|
|
2
|
+
export declare const SORTABLE_ATTR = "data-k-sortable";
|
|
3
|
+
export declare function sortableElements(container: HTMLElement | null | undefined): HTMLElement[];
|
|
4
|
+
export declare function isRtl(element: Element | null | undefined): boolean;
|
|
5
|
+
export declare function insertionIndex(elements: HTMLElement[], x: number, y: number, axis: SortableAxis, rtl: boolean): number;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const SORTABLE_ATTR = "data-k-sortable";
|
|
2
|
+
export function sortableElements(container) {
|
|
3
|
+
if (!container) return [];
|
|
4
|
+
return Array.from(container.querySelectorAll(`[${SORTABLE_ATTR}]`)).sort(
|
|
5
|
+
(a, b) => Number(a.getAttribute(SORTABLE_ATTR)) - Number(b.getAttribute(SORTABLE_ATTR))
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
export function isRtl(element) {
|
|
9
|
+
return element ? getComputedStyle(element).direction === "rtl" : false;
|
|
10
|
+
}
|
|
11
|
+
function isBefore(rect, x, y, axis, rtl) {
|
|
12
|
+
if (axis === "vertical") return rect.top + rect.height / 2 < y;
|
|
13
|
+
if (rect.bottom <= y) return true;
|
|
14
|
+
if (rect.top > y) return false;
|
|
15
|
+
const center = rect.left + rect.width / 2;
|
|
16
|
+
return rtl ? center > x : center < x;
|
|
17
|
+
}
|
|
18
|
+
export function insertionIndex(elements, x, y, axis, rtl) {
|
|
19
|
+
let index = 0;
|
|
20
|
+
for (const element of elements)
|
|
21
|
+
if (isBefore(element.getBoundingClientRect(), x, y, axis, rtl)) index++;
|
|
22
|
+
return index;
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
export interface ToasterInsets {
|
|
3
|
+
left: number;
|
|
4
|
+
right: number;
|
|
5
|
+
top: number;
|
|
6
|
+
bottom: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ToasterAvoidanceOptions {
|
|
9
|
+
outlet: () => HTMLElement | null;
|
|
10
|
+
toaster: Readonly<Ref<HTMLElement | null | undefined>>;
|
|
11
|
+
position: () => string;
|
|
12
|
+
}
|
|
13
|
+
export declare function useToasterAvoidance(options: ToasterAvoidanceOptions): {
|
|
14
|
+
insets: Ref<{
|
|
15
|
+
left: number;
|
|
16
|
+
right: number;
|
|
17
|
+
top: number;
|
|
18
|
+
bottom: number;
|
|
19
|
+
}, ToasterInsets | {
|
|
20
|
+
left: number;
|
|
21
|
+
right: number;
|
|
22
|
+
top: number;
|
|
23
|
+
bottom: number;
|
|
24
|
+
}>;
|
|
25
|
+
refresh: () => void;
|
|
26
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { onScopeDispose, ref, watch } from "vue";
|
|
2
|
+
import { isClient } from "../core/env.mjs";
|
|
3
|
+
import { waitForAnimations } from "../floating/support.mjs";
|
|
4
|
+
const NONE = { left: 0, right: 0, top: 0, bottom: 0 };
|
|
5
|
+
const GAP = 8;
|
|
6
|
+
function sameInsets(a, b) {
|
|
7
|
+
return a.left === b.left && a.right === b.right && a.top === b.top && a.bottom === b.bottom;
|
|
8
|
+
}
|
|
9
|
+
function rootPixels() {
|
|
10
|
+
return parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
|
|
11
|
+
}
|
|
12
|
+
function drawerSide(dialog) {
|
|
13
|
+
if (!dialog.classList.contains("k-drawer")) return null;
|
|
14
|
+
if (dialog.classList.contains("k-drawer-left")) return "left";
|
|
15
|
+
if (dialog.classList.contains("k-drawer-bottom")) return "bottom";
|
|
16
|
+
return "right";
|
|
17
|
+
}
|
|
18
|
+
function overlapsX(rect, span) {
|
|
19
|
+
return rect.left < span.right && span.left < rect.right;
|
|
20
|
+
}
|
|
21
|
+
function horizontalOf(position) {
|
|
22
|
+
if (position.endsWith("left")) return "left";
|
|
23
|
+
if (position.endsWith("right")) return "right";
|
|
24
|
+
return "center";
|
|
25
|
+
}
|
|
26
|
+
export function useToasterAvoidance(options) {
|
|
27
|
+
const insets = ref(NONE);
|
|
28
|
+
let observer;
|
|
29
|
+
let frame = 0;
|
|
30
|
+
let current = null;
|
|
31
|
+
function sideInsets(dialog, panel, toaster) {
|
|
32
|
+
const side = drawerSide(dialog);
|
|
33
|
+
if (side !== "left" && side !== "right") return null;
|
|
34
|
+
const horizontal = horizontalOf(options.position());
|
|
35
|
+
if (horizontal !== "center" && horizontal !== side) return NONE;
|
|
36
|
+
const style = getComputedStyle(dialog);
|
|
37
|
+
const padding = parseFloat(side === "left" ? style.paddingLeft : style.paddingRight) || 0;
|
|
38
|
+
const occupied = panel.offsetWidth + padding;
|
|
39
|
+
const margin = rootPixels();
|
|
40
|
+
const free = dialog.clientWidth - occupied - 2 * margin;
|
|
41
|
+
if (free < toasterWidth(toaster, dialog.clientWidth)) return null;
|
|
42
|
+
return { ...NONE, [side]: occupied };
|
|
43
|
+
}
|
|
44
|
+
function toasterWidth(toaster, viewport) {
|
|
45
|
+
const width = toaster.offsetWidth || parseFloat(getComputedStyle(toaster).width) || 0;
|
|
46
|
+
return Math.min(width, viewport - 2 * rootPixels());
|
|
47
|
+
}
|
|
48
|
+
function toasterSpan(toaster) {
|
|
49
|
+
const viewport = document.documentElement.clientWidth;
|
|
50
|
+
const margin = rootPixels();
|
|
51
|
+
const width = toasterWidth(toaster, viewport);
|
|
52
|
+
const horizontal = horizontalOf(options.position());
|
|
53
|
+
if (horizontal === "left") return { left: margin, right: margin + width };
|
|
54
|
+
if (horizontal === "right")
|
|
55
|
+
return { left: viewport - margin - width, right: viewport - margin };
|
|
56
|
+
return { left: (viewport - width) / 2, right: (viewport + width) / 2 };
|
|
57
|
+
}
|
|
58
|
+
function verticalInsets(panel, toaster) {
|
|
59
|
+
const bounds = toasterSpan(toaster);
|
|
60
|
+
const viewport = document.documentElement.clientHeight;
|
|
61
|
+
const margin = rootPixels();
|
|
62
|
+
const next = { ...NONE };
|
|
63
|
+
if (options.position().startsWith("top")) {
|
|
64
|
+
const header = panel.querySelector(":scope > header");
|
|
65
|
+
const rect = header?.getBoundingClientRect();
|
|
66
|
+
if (rect && rect.height && overlapsX(rect, bounds) && rect.bottom < viewport / 2)
|
|
67
|
+
next.top = Math.max(0, Math.ceil(rect.bottom + GAP - margin));
|
|
68
|
+
} else {
|
|
69
|
+
const footer = panel.querySelector(":scope > footer");
|
|
70
|
+
const rect = footer?.getBoundingClientRect();
|
|
71
|
+
if (rect && rect.height && overlapsX(rect, bounds) && rect.top > viewport / 2)
|
|
72
|
+
next.bottom = Math.max(0, Math.ceil(viewport - rect.top + GAP - margin));
|
|
73
|
+
}
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
76
|
+
function compute() {
|
|
77
|
+
frame = 0;
|
|
78
|
+
const dialog = current;
|
|
79
|
+
const toaster = options.toaster.value;
|
|
80
|
+
const panel = dialog?.querySelector(':scope > [class$="-panel"]');
|
|
81
|
+
if (!dialog || !toaster || !panel) {
|
|
82
|
+
if (!dialog && !sameInsets(insets.value, NONE)) insets.value = NONE;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const next = sideInsets(dialog, panel, toaster) ?? verticalInsets(panel, toaster);
|
|
86
|
+
if (!sameInsets(next, insets.value)) insets.value = next;
|
|
87
|
+
}
|
|
88
|
+
function schedule() {
|
|
89
|
+
if (!frame) frame = requestAnimationFrame(compute);
|
|
90
|
+
}
|
|
91
|
+
function observe(dialog) {
|
|
92
|
+
observer ??= new ResizeObserver(schedule);
|
|
93
|
+
const panel = dialog.querySelector(':scope > [class$="-panel"]');
|
|
94
|
+
for (const element of [
|
|
95
|
+
dialog,
|
|
96
|
+
panel,
|
|
97
|
+
panel?.querySelector(":scope > header"),
|
|
98
|
+
panel?.querySelector(":scope > footer")
|
|
99
|
+
])
|
|
100
|
+
if (element) observer.observe(element);
|
|
101
|
+
}
|
|
102
|
+
function disconnect() {
|
|
103
|
+
observer?.disconnect();
|
|
104
|
+
if (frame) cancelAnimationFrame(frame);
|
|
105
|
+
frame = 0;
|
|
106
|
+
}
|
|
107
|
+
watch(
|
|
108
|
+
[options.outlet, options.toaster],
|
|
109
|
+
([dialog, toaster]) => {
|
|
110
|
+
if (!isClient()) return;
|
|
111
|
+
disconnect();
|
|
112
|
+
current = dialog;
|
|
113
|
+
if (!dialog) {
|
|
114
|
+
insets.value = NONE;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
observe(dialog);
|
|
118
|
+
if (toaster) observer?.observe(toaster);
|
|
119
|
+
schedule();
|
|
120
|
+
waitForAnimations(dialog).then(() => {
|
|
121
|
+
if (current === dialog) schedule();
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
{ immediate: true, flush: "post" }
|
|
125
|
+
);
|
|
126
|
+
if (isClient()) {
|
|
127
|
+
window.addEventListener("resize", schedule);
|
|
128
|
+
onScopeDispose(() => {
|
|
129
|
+
window.removeEventListener("resize", schedule);
|
|
130
|
+
disconnect();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return { insets, refresh: schedule };
|
|
134
|
+
}
|