@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.
Files changed (72) hide show
  1. package/CATALOG.md +195 -180
  2. package/README.md +107 -23
  3. package/dist/components/data/Tag.vue +2 -0
  4. package/dist/components/data/Tag.vue.d.ts +2 -0
  5. package/dist/components/data/TagList.vue +239 -0
  6. package/dist/components/data/TagList.vue.d.ts +53 -0
  7. package/dist/components/data/index.d.ts +1 -0
  8. package/dist/components/data/index.mjs +1 -0
  9. package/dist/components/data/types.d.ts +15 -0
  10. package/dist/components/forms/Combobox.vue +33 -4
  11. package/dist/components/forms/Combobox.vue.d.ts +3 -1
  12. package/dist/components/forms/NumberInput.vue.d.ts +1 -1
  13. package/dist/components/forms/PinInput.vue.d.ts +2 -2
  14. package/dist/components/forms/types.d.ts +2 -0
  15. package/dist/components/layout/AppShell.vue +14 -2
  16. package/dist/components/layout/AppShell.vue.d.ts +3 -1
  17. package/dist/components/layout/Sidebar.vue +8 -3
  18. package/dist/components/layout/Sidebar.vue.d.ts +6 -1
  19. package/dist/components/layout/Stepper.vue +148 -0
  20. package/dist/components/layout/Stepper.vue.d.ts +420 -0
  21. package/dist/components/layout/index.d.ts +1 -0
  22. package/dist/components/layout/index.mjs +1 -0
  23. package/dist/components/layout/types.d.ts +13 -0
  24. package/dist/components/overlays/Toaster.vue +10 -0
  25. package/dist/components/overlays/Toaster.vue.d.ts +1 -1
  26. package/dist/components/templates/DashboardLayout.vue +13 -1
  27. package/dist/components/templates/DashboardLayout.vue.d.ts +7 -2
  28. package/dist/components/templates/SettingsModal.vue +95 -4
  29. package/dist/components/templates/SettingsModal.vue.d.ts +6 -1
  30. package/dist/components/templates/types.d.ts +4 -1
  31. package/dist/composables/data.d.ts +1 -0
  32. package/dist/composables/data.mjs +1 -0
  33. package/dist/composables/layout.d.ts +1 -0
  34. package/dist/composables/layout.mjs +1 -0
  35. package/dist/composables/useRouteState.d.ts +13 -0
  36. package/dist/composables/useRouteState.mjs +37 -0
  37. package/dist/composables/useSortable.d.ts +38 -0
  38. package/dist/composables/useSortable.mjs +215 -0
  39. package/dist/grid/DataGrid.vue +7 -1
  40. package/dist/grid/DataGrid.vue.d.ts +8 -1
  41. package/dist/grid/GridToolbar.vue +57 -2
  42. package/dist/grid/GridToolbar.vue.d.ts +13 -2
  43. package/dist/grid/cells/BadgeCell.vue +90 -18
  44. package/dist/grid/cells/BadgeCell.vue.d.ts +14 -14
  45. package/dist/grid/data-grid.css +57 -0
  46. package/dist/grid/spreadsheet.mjs +8 -4
  47. package/dist/grid/types.d.ts +3 -0
  48. package/dist/icons/builtin.d.ts +2 -0
  49. package/dist/icons/builtin.mjs +2 -0
  50. package/dist/internal/data/sortable.d.ts +5 -0
  51. package/dist/internal/data/sortable.mjs +23 -0
  52. package/dist/internal/layout/query.d.ts +6 -0
  53. package/dist/internal/layout/query.mjs +64 -0
  54. package/dist/internal/layout/route.d.ts +9 -2
  55. package/dist/internal/overlays/avoid.d.ts +26 -0
  56. package/dist/internal/overlays/avoid.mjs +134 -0
  57. package/dist/locale/de.mjs +24 -0
  58. package/dist/locale/en.mjs +24 -0
  59. package/dist/locale/it.mjs +24 -0
  60. package/dist/locale/types.d.ts +24 -0
  61. package/dist/nuxt/module.mjs +14 -0
  62. package/dist/nuxt/runtime/layouts/dashboard.vue +9 -1
  63. package/dist/styles/data/tag-list.css +93 -0
  64. package/dist/styles/data.css +1 -0
  65. package/dist/styles/forced-colors.css +10 -0
  66. package/dist/styles/layout/app-shell.css +25 -6
  67. package/dist/styles/layout/sidebar.css +11 -2
  68. package/dist/styles/layout/stepper.css +244 -0
  69. package/dist/styles/layout.css +1 -0
  70. package/dist/styles/overlays/toast.css +17 -12
  71. package/dist/styles/templates/settings-modal.css +5 -1
  72. 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
- watch(activeId, () => goTo(0));
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?: {
@@ -1 +1,2 @@
1
1
  export * from './useTableSort';
2
+ export * from './useSortable';
@@ -1 +1,2 @@
1
1
  export * from "./useTableSort.mjs";
2
+ export * from "./useSortable.mjs";
@@ -1 +1,2 @@
1
1
  export * from './useAppShell';
2
+ export * from './useRouteState';
@@ -1 +1,2 @@
1
1
  export * from "./useAppShell.mjs";
2
+ export * from "./useRouteState.mjs";
@@ -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
+ }
@@ -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
  };