@xleddyl/443-components-vue 0.10.2 → 0.12.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 +195 -180
- package/README.md +107 -23
- 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/Sidebar.vue +8 -3
- package/dist/components/layout/Sidebar.vue.d.ts +6 -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 +13 -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 +13 -1
- package/dist/components/templates/DashboardLayout.vue.d.ts +7 -2
- package/dist/components/templates/SettingsModal.vue +95 -4
- package/dist/components/templates/SettingsModal.vue.d.ts +6 -1
- package/dist/components/templates/types.d.ts +4 -1
- package/dist/composables/data.d.ts +1 -0
- package/dist/composables/data.mjs +1 -0
- package/dist/composables/layout.d.ts +1 -0
- package/dist/composables/layout.mjs +1 -0
- package/dist/composables/useRouteState.d.ts +13 -0
- package/dist/composables/useRouteState.mjs +37 -0
- package/dist/composables/useSortable.d.ts +38 -0
- package/dist/composables/useSortable.mjs +215 -0
- package/dist/grid/DataGrid.vue +7 -1
- package/dist/grid/DataGrid.vue.d.ts +8 -1
- package/dist/grid/GridToolbar.vue +57 -2
- package/dist/grid/GridToolbar.vue.d.ts +13 -2
- package/dist/grid/cells/BadgeCell.vue +90 -18
- package/dist/grid/cells/BadgeCell.vue.d.ts +14 -14
- package/dist/grid/data-grid.css +57 -0
- package/dist/grid/spreadsheet.mjs +8 -4
- package/dist/grid/types.d.ts +3 -0
- package/dist/icons/builtin.d.ts +2 -0
- package/dist/icons/builtin.mjs +2 -0
- package/dist/internal/data/sortable.d.ts +5 -0
- package/dist/internal/data/sortable.mjs +23 -0
- package/dist/internal/layout/query.d.ts +6 -0
- package/dist/internal/layout/query.mjs +64 -0
- package/dist/internal/layout/route.d.ts +9 -2
- package/dist/internal/overlays/avoid.d.ts +26 -0
- package/dist/internal/overlays/avoid.mjs +134 -0
- package/dist/locale/de.mjs +24 -0
- package/dist/locale/en.mjs +24 -0
- package/dist/locale/it.mjs +24 -0
- package/dist/locale/types.d.ts +24 -0
- package/dist/nuxt/module.mjs +14 -0
- package/dist/nuxt/runtime/layouts/dashboard.vue +9 -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 +25 -6
- package/dist/styles/layout/sidebar.css +11 -2
- package/dist/styles/layout/stepper.css +244 -0
- package/dist/styles/layout.css +1 -0
- package/dist/styles/overlays/toast.css +17 -12
- package/dist/styles/templates/settings-modal.css +5 -1
- package/package.json +1 -1
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
v-if="item.to !== void 0"
|
|
54
54
|
v-bind="resolveLink({ to: item.to })?.attrs"
|
|
55
55
|
class="k-settings-modal-tab"
|
|
56
|
-
@click="close"
|
|
56
|
+
@click="syncing ? void 0 : close()"
|
|
57
57
|
>
|
|
58
58
|
<Icon v-if="item.icon" :name="item.icon" />
|
|
59
59
|
<span class="k-settings-modal-tab-label">{{ item.label }}</span>
|
|
@@ -199,11 +199,13 @@
|
|
|
199
199
|
</template>
|
|
200
200
|
|
|
201
201
|
<script setup>
|
|
202
|
-
import { computed, useId, useTemplateRef, watch } from "vue";
|
|
202
|
+
import { computed, nextTick, onMounted, useId, useTemplateRef, watch } from "vue";
|
|
203
203
|
import { THEME_PRESETS } from "../../composables/usePreset";
|
|
204
204
|
import { useLocale } from "../../composables/useLocale";
|
|
205
205
|
import { useLinkResolver } from "../../internal/core/link";
|
|
206
206
|
import { useScrollEdges } from "../../internal/core/scroll-edges";
|
|
207
|
+
import { useQueryValue, writeQueryValue } from "../../internal/layout/query";
|
|
208
|
+
import { useRouterLike } from "../../internal/layout/route";
|
|
207
209
|
import Button from "../core/Button.vue";
|
|
208
210
|
import Icon from "../core/Icon.vue";
|
|
209
211
|
import Avatar from "../data/Avatar.vue";
|
|
@@ -232,7 +234,9 @@ const props = defineProps({
|
|
|
232
234
|
presetText: { type: String, required: false, default: void 0 },
|
|
233
235
|
onSignOut: { type: Function, required: false },
|
|
234
236
|
hideSession: { type: Boolean, required: false },
|
|
235
|
-
beforeClose: { type: Function, required: false }
|
|
237
|
+
beforeClose: { type: Function, required: false },
|
|
238
|
+
route: { type: [String, Boolean], required: false, default: false },
|
|
239
|
+
resolvePage: { type: Function, required: false }
|
|
236
240
|
});
|
|
237
241
|
defineSlots();
|
|
238
242
|
const emit = defineEmits(["open", "close", "afterLeave"]);
|
|
@@ -307,7 +311,94 @@ const trail = computed(() => [
|
|
|
307
311
|
function slotProps(item, close) {
|
|
308
312
|
return { section: item, close, page: currentPage.value, pages: pages.value, openPage, back };
|
|
309
313
|
}
|
|
310
|
-
|
|
314
|
+
const router = useRouterLike();
|
|
315
|
+
const routeKey = computed(() => props.route === true ? "settings" : props.route || void 0);
|
|
316
|
+
const routeParam = useQueryValue(router, routeKey);
|
|
317
|
+
const syncing = computed(() => Boolean(router && routeKey.value));
|
|
318
|
+
let applying = false;
|
|
319
|
+
let resolution = 0;
|
|
320
|
+
const routeValue = computed(() => {
|
|
321
|
+
if (!open.value || !activeId.value) return void 0;
|
|
322
|
+
return [activeId.value, ...pages.value.map((page) => page.id)].map(encodeURIComponent).join("/");
|
|
323
|
+
});
|
|
324
|
+
function decodeSegment(segment) {
|
|
325
|
+
try {
|
|
326
|
+
return decodeURIComponent(segment);
|
|
327
|
+
} catch {
|
|
328
|
+
return segment;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function writeRoute(value, history) {
|
|
332
|
+
const key = routeKey.value;
|
|
333
|
+
if (!router || !key || value === routeParam.value) return;
|
|
334
|
+
void writeQueryValue(router, key, value, history);
|
|
335
|
+
}
|
|
336
|
+
async function settle() {
|
|
337
|
+
await nextTick();
|
|
338
|
+
applying = false;
|
|
339
|
+
writeRoute(routeValue.value, "replace");
|
|
340
|
+
}
|
|
341
|
+
function resolvedPage(token, sectionId, index, id, label) {
|
|
342
|
+
if (token !== resolution || activeId.value !== sectionId || pages.value[index]?.id !== id) return;
|
|
343
|
+
if (label === void 0) {
|
|
344
|
+
applying = true;
|
|
345
|
+
pages.value = pages.value.slice(0, index);
|
|
346
|
+
void settle();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
pages.value = pages.value.map((page, position) => position === index ? { id, label } : page);
|
|
350
|
+
}
|
|
351
|
+
function applyRoute(value) {
|
|
352
|
+
if (value === routeValue.value) return;
|
|
353
|
+
const token = ++resolution;
|
|
354
|
+
applying = true;
|
|
355
|
+
const [sectionId, ...pageIds] = (value ?? "").split("/").filter(Boolean).map(decodeSegment);
|
|
356
|
+
if (!sectionId) {
|
|
357
|
+
open.value = false;
|
|
358
|
+
void settle();
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const reuse = activeId.value === sectionId;
|
|
362
|
+
open.value = true;
|
|
363
|
+
section.value = sectionId;
|
|
364
|
+
const next = [];
|
|
365
|
+
if (selectable.value.some((item) => item.id === sectionId)) {
|
|
366
|
+
for (const [index, id] of pageIds.entries()) {
|
|
367
|
+
const known = pages.value[index];
|
|
368
|
+
if (reuse && known?.id === id && next.every((page, i) => pages.value[i] === page)) {
|
|
369
|
+
next.push(known);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const result = props.resolvePage ? props.resolvePage(sectionId, id, next.slice()) : id;
|
|
373
|
+
if (result === void 0) break;
|
|
374
|
+
if (typeof result === "string") {
|
|
375
|
+
next.push({ id, label: result });
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
next.push({ id, label: "" });
|
|
379
|
+
void Promise.resolve(result).then(
|
|
380
|
+
(label) => resolvedPage(token, sectionId, index, id, label),
|
|
381
|
+
() => resolvedPage(token, sectionId, index, id, void 0)
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
pages.value = next;
|
|
386
|
+
void settle();
|
|
387
|
+
}
|
|
388
|
+
watch(activeId, () => {
|
|
389
|
+
if (!applying) goTo(0);
|
|
390
|
+
});
|
|
391
|
+
watch(routeValue, (value) => {
|
|
392
|
+
if (!applying) writeRoute(value, "push");
|
|
393
|
+
});
|
|
394
|
+
watch(routeParam, (value) => {
|
|
395
|
+
if (syncing.value) applyRoute(value);
|
|
396
|
+
});
|
|
397
|
+
onMounted(() => {
|
|
398
|
+
if (!syncing.value) return;
|
|
399
|
+
if (routeParam.value !== void 0) applyRoute(routeParam.value);
|
|
400
|
+
else writeRoute(routeValue.value, "replace");
|
|
401
|
+
});
|
|
311
402
|
watch(
|
|
312
403
|
() => pages.value.length,
|
|
313
404
|
() => contentBody.value?.scrollTo({ top: 0 })
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThemePreset } from '../../composables/usePreset';
|
|
2
2
|
import type { DialogBeforeClose } from '../overlays/types';
|
|
3
|
-
import type { SettingsModalAccount, SettingsModalPage, SettingsModalSection, SettingsSectionSlotProps } from './types';
|
|
3
|
+
import type { SettingsModalAccount, SettingsModalPage, SettingsModalSection, SettingsPageResolver, SettingsSectionSlotProps } from './types';
|
|
4
4
|
type __VLS_Slots = {
|
|
5
5
|
'account-fields'?: (props: {
|
|
6
6
|
account: SettingsModalAccount;
|
|
@@ -32,6 +32,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
32
32
|
onSignOut?: () => void;
|
|
33
33
|
hideSession?: boolean;
|
|
34
34
|
beforeClose?: DialogBeforeClose;
|
|
35
|
+
route?: string | boolean;
|
|
36
|
+
resolvePage?: SettingsPageResolver;
|
|
35
37
|
open?: boolean | undefined;
|
|
36
38
|
section?: string;
|
|
37
39
|
pages?: SettingsModalPage[];
|
|
@@ -274,6 +276,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
274
276
|
onSignOut?: () => void;
|
|
275
277
|
hideSession?: boolean;
|
|
276
278
|
beforeClose?: DialogBeforeClose;
|
|
279
|
+
route?: string | boolean;
|
|
280
|
+
resolvePage?: SettingsPageResolver;
|
|
277
281
|
open?: boolean | undefined;
|
|
278
282
|
section?: string;
|
|
279
283
|
pages?: SettingsModalPage[];
|
|
@@ -501,6 +505,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
501
505
|
themeText: string;
|
|
502
506
|
presetLabel: string;
|
|
503
507
|
presetText: string;
|
|
508
|
+
route: string | boolean;
|
|
504
509
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
505
510
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
506
511
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Component } from 'vue';
|
|
2
2
|
import type { LinkTarget, Tone } from '../core/types';
|
|
3
3
|
import type { DescriptionItem, StatTrend } from '../data/types';
|
|
4
|
-
import type { BreadcrumbItem, NavItem, NavSection } from '../layout/types';
|
|
4
|
+
import type { BreadcrumbItem, NavItem, NavSection, ShellContent } from '../layout/types';
|
|
5
5
|
import type { CommandEmptyText, CommandGroup, MenuItems } from '../overlays/types';
|
|
6
6
|
import type { ThemePreset } from '../../internal/core/preset-data';
|
|
7
7
|
export type DashboardVariant = 'inset' | 'sidebar' | 'floating';
|
|
@@ -34,6 +34,7 @@ export interface SettingsModalPage {
|
|
|
34
34
|
id: string;
|
|
35
35
|
label: string;
|
|
36
36
|
}
|
|
37
|
+
export type SettingsPageResolver = (section: string, id: string, parents: SettingsModalPage[]) => string | undefined | Promise<string | undefined>;
|
|
37
38
|
export interface SettingsSectionSlotProps {
|
|
38
39
|
section: SettingsModalSection;
|
|
39
40
|
close: () => void;
|
|
@@ -129,6 +130,7 @@ export interface KAppConfig {
|
|
|
129
130
|
sections?: SettingsModalSection[];
|
|
130
131
|
presets?: ThemePreset[] | false;
|
|
131
132
|
signOutTo?: LinkTarget | false;
|
|
133
|
+
route?: string | boolean;
|
|
132
134
|
};
|
|
133
135
|
dashboard?: {
|
|
134
136
|
variant?: DashboardVariant;
|
|
@@ -138,6 +140,7 @@ export interface KAppConfig {
|
|
|
138
140
|
storageKey?: string | false;
|
|
139
141
|
fluid?: boolean;
|
|
140
142
|
fill?: boolean;
|
|
143
|
+
content?: ShellContent;
|
|
141
144
|
breadcrumbs?: boolean;
|
|
142
145
|
};
|
|
143
146
|
auth?: {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import type { RouteHistory } from '../internal/layout/query';
|
|
3
|
+
export type { RouteHistory };
|
|
4
|
+
export interface RouteStateOptions<T> {
|
|
5
|
+
parse?: (value: string) => T | undefined;
|
|
6
|
+
serialize?: (value: T) => string | undefined;
|
|
7
|
+
history?: RouteHistory;
|
|
8
|
+
default?: T;
|
|
9
|
+
}
|
|
10
|
+
export declare function useRouteState<T = string>(key: string, options: RouteStateOptions<T> & {
|
|
11
|
+
default: T;
|
|
12
|
+
}): Ref<T>;
|
|
13
|
+
export declare function useRouteState<T = string>(key: string, options?: RouteStateOptions<T>): Ref<T | undefined>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { computed, shallowRef, watch } from "vue";
|
|
2
|
+
import { useQueryValue, writeQueryValue } from "../internal/layout/query.mjs";
|
|
3
|
+
import { useRouterLike } from "../internal/layout/route.mjs";
|
|
4
|
+
export function useRouteState(key, options = {}) {
|
|
5
|
+
const router = useRouterLike();
|
|
6
|
+
const raw = useQueryValue(router, key);
|
|
7
|
+
const fallback = options.default;
|
|
8
|
+
const parse = options.parse ?? ((value) => value);
|
|
9
|
+
const serialize = options.serialize ?? ((value) => String(value));
|
|
10
|
+
function fromRaw(value) {
|
|
11
|
+
if (value === void 0 || value === "") return fallback;
|
|
12
|
+
return parse(value) ?? fallback;
|
|
13
|
+
}
|
|
14
|
+
function toRaw(value) {
|
|
15
|
+
if (value === void 0 || value === null) return void 0;
|
|
16
|
+
const text = serialize(value);
|
|
17
|
+
if (text === void 0 || text === "") return void 0;
|
|
18
|
+
if (fallback !== void 0 && text === serialize(fallback)) return void 0;
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
21
|
+
const state = shallowRef(fromRaw(raw.value));
|
|
22
|
+
let version = 0;
|
|
23
|
+
watch(raw, (value) => {
|
|
24
|
+
state.value = fromRaw(value);
|
|
25
|
+
});
|
|
26
|
+
return computed({
|
|
27
|
+
get: () => state.value,
|
|
28
|
+
set(value) {
|
|
29
|
+
state.value = value;
|
|
30
|
+
if (!router) return;
|
|
31
|
+
const current = ++version;
|
|
32
|
+
void writeQueryValue(router, key, toRaw(value), options.history ?? "push").then((ok) => {
|
|
33
|
+
if (!ok && current === version) state.value = fromRaw(raw.value);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import type { SortableAxis } from '../internal/data/sortable';
|
|
3
|
+
import { SORTABLE_ATTR } from '../internal/data/sortable';
|
|
4
|
+
export type SortableOrientation = SortableAxis;
|
|
5
|
+
export interface SortableMove<T> {
|
|
6
|
+
item: T;
|
|
7
|
+
from: number;
|
|
8
|
+
to: number;
|
|
9
|
+
items: T[];
|
|
10
|
+
source: 'pointer' | 'keyboard' | 'api';
|
|
11
|
+
}
|
|
12
|
+
export interface UseSortableOptions<T> {
|
|
13
|
+
items: MaybeRefOrGetter<readonly T[]>;
|
|
14
|
+
orientation?: MaybeRefOrGetter<SortableOrientation | undefined>;
|
|
15
|
+
disabled?: MaybeRefOrGetter<boolean | undefined>;
|
|
16
|
+
handle?: string;
|
|
17
|
+
canMove?: (item: T, index: number) => boolean;
|
|
18
|
+
label?: (item: T) => string;
|
|
19
|
+
movedText?: (move: SortableMove<T>) => string;
|
|
20
|
+
onMove: (items: T[], move: SortableMove<T>) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface SortableItemProps {
|
|
23
|
+
[SORTABLE_ATTR]: number;
|
|
24
|
+
'aria-keyshortcuts'?: string;
|
|
25
|
+
onPointerdown: (event: PointerEvent) => void;
|
|
26
|
+
onKeydown: (event: KeyboardEvent) => void;
|
|
27
|
+
}
|
|
28
|
+
export interface SortableMoveOptions {
|
|
29
|
+
announce?: boolean;
|
|
30
|
+
source?: SortableMove<unknown>['source'];
|
|
31
|
+
}
|
|
32
|
+
export declare function useSortable<T>(container: MaybeRefOrGetter<HTMLElement | null | undefined>, options: UseSortableOptions<T>): {
|
|
33
|
+
dragging: Readonly<import("vue").Ref<number | null, number | null>>;
|
|
34
|
+
announcement: import("vue").Ref<string, string>;
|
|
35
|
+
itemProps: (index: number) => SortableItemProps;
|
|
36
|
+
move: (from: number, to: number, moveOptions?: SortableMoveOptions) => boolean;
|
|
37
|
+
canMove: (index: number) => boolean;
|
|
38
|
+
};
|
|
@@ -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
|
+
}
|
package/dist/grid/DataGrid.vue
CHANGED
|
@@ -22,9 +22,14 @@
|
|
|
22
22
|
:exportable="exportable"
|
|
23
23
|
:export-file-name="exportFileName"
|
|
24
24
|
:debounce="searchDebounce"
|
|
25
|
+
:filter-count="filterCount"
|
|
25
26
|
@reset-columns="clearStoredState"
|
|
27
|
+
@filters-reset="emit('filtersReset')"
|
|
26
28
|
>
|
|
27
29
|
<slot name="actions" :api="api" v-bind="sheetSlot" />
|
|
30
|
+
<template v-if="$slots.filters" #filters="scope">
|
|
31
|
+
<slot name="filters" v-bind="scope" />
|
|
32
|
+
</template>
|
|
28
33
|
</GridToolbar>
|
|
29
34
|
|
|
30
35
|
<div
|
|
@@ -152,6 +157,7 @@ const props = defineProps({
|
|
|
152
157
|
exportable: { type: Boolean, required: false, default: true },
|
|
153
158
|
exportFileName: { type: String, required: false, default: "export" },
|
|
154
159
|
searchDebounce: { type: Number, required: false, default: 0 },
|
|
160
|
+
filterCount: { type: Number, required: false, default: 0 },
|
|
155
161
|
serverSort: { type: Boolean, required: false },
|
|
156
162
|
pagination: { type: Boolean, required: false },
|
|
157
163
|
showEdges: { type: Boolean, required: false },
|
|
@@ -169,7 +175,7 @@ const props = defineProps({
|
|
|
169
175
|
editable: { type: Boolean, required: false },
|
|
170
176
|
spreadsheet: { type: Boolean, required: false }
|
|
171
177
|
});
|
|
172
|
-
const emit = defineEmits(["rowClick", "selectionChange", "sortChange", "filterChange", "copy", "cellsChange", "cellsInvalid", "dirtyChange", "rangeChange"]);
|
|
178
|
+
const emit = defineEmits(["rowClick", "selectionChange", "sortChange", "filterChange", "copy", "cellsChange", "cellsInvalid", "dirtyChange", "rangeChange", "filtersReset"]);
|
|
173
179
|
const query = defineModel("query", { type: String, ...{ default: "" } });
|
|
174
180
|
const page = defineModel("page", { type: Number, ...{ default: 1 } });
|
|
175
181
|
const pageSize = defineModel("pageSize", { type: Number, ...{ default: 25 } });
|
|
@@ -20,6 +20,7 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
|
|
|
20
20
|
exportable?: boolean;
|
|
21
21
|
exportFileName?: string;
|
|
22
22
|
searchDebounce?: number;
|
|
23
|
+
filterCount?: number;
|
|
23
24
|
serverSort?: boolean;
|
|
24
25
|
pagination?: boolean;
|
|
25
26
|
showEdges?: boolean;
|
|
@@ -48,6 +49,7 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
|
|
|
48
49
|
onRowClick?: ((event: RowClickedEvent<T, any>) => any) | undefined;
|
|
49
50
|
"onUpdate:sort"?: ((value: GridSortChange | null | undefined) => any) | undefined;
|
|
50
51
|
"onUpdate:query"?: ((value: string) => any) | undefined;
|
|
52
|
+
onFiltersReset?: (() => any) | undefined;
|
|
51
53
|
onSelectionChange?: ((rows: T[]) => any) | undefined;
|
|
52
54
|
onSortChange?: ((change: GridSortChange | null) => any) | undefined;
|
|
53
55
|
onFilterChange?: ((model: FilterModel, event: FilterChangedEvent<T, any>) => any) | undefined;
|
|
@@ -106,8 +108,13 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
|
|
|
106
108
|
clearDirty: (rowIds?: string[]) => void;
|
|
107
109
|
api: GridApi<T> | null;
|
|
108
110
|
}) => any;
|
|
111
|
+
} & {
|
|
112
|
+
filters?: (props: {
|
|
113
|
+
close: () => void;
|
|
114
|
+
count: number;
|
|
115
|
+
}) => any;
|
|
109
116
|
};
|
|
110
|
-
emit: (((evt: "copy", text: string) => void) & ((evt: "rowClick", event: RowClickedEvent<T, any>) => void) & ((evt: "selectionChange", rows: T[]) => void) & ((evt: "sortChange", change: GridSortChange | null) => void) & ((evt: "filterChange", model: FilterModel, event: FilterChangedEvent<T, any>) => void) & ((evt: "cellsChange", event: GridCellsChange) => void) & ((evt: "cellsInvalid", event: GridCellsInvalid) => void) & ((evt: "dirtyChange", count: number) => void) & ((evt: "rangeChange", range: GridCellRange | null) => void)) & (((event: "update:page", value: number) => void) & ((event: "update:pageSize", value: number) => void) & ((event: "update:sort", value: GridSortChange | null | undefined) => void) & ((event: "update:query", value: string) => void));
|
|
117
|
+
emit: (((evt: "copy", text: string) => void) & ((evt: "rowClick", event: RowClickedEvent<T, any>) => void) & ((evt: "filtersReset") => void) & ((evt: "selectionChange", rows: T[]) => void) & ((evt: "sortChange", change: GridSortChange | null) => void) & ((evt: "filterChange", model: FilterModel, event: FilterChangedEvent<T, any>) => void) & ((evt: "cellsChange", event: GridCellsChange) => void) & ((evt: "cellsInvalid", event: GridCellsInvalid) => void) & ((evt: "dirtyChange", count: number) => void) & ((evt: "rangeChange", range: GridCellRange | null) => void)) & (((event: "update:page", value: number) => void) & ((event: "update:pageSize", value: number) => void) & ((event: "update:sort", value: GridSortChange | null | undefined) => void) & ((event: "update:query", value: string) => void));
|
|
111
118
|
}>) => import("vue").VNode & {
|
|
112
119
|
__ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
|
|
113
120
|
};
|