@revenexx/studio-shared 0.3.0 → 0.3.2

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 (29) hide show
  1. package/dist/module.d.mts +1 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +5 -0
  4. package/dist/runtime/components/DataTable/ColumnsMenu.d.vue.ts +2 -0
  5. package/dist/runtime/components/DataTable/ColumnsMenu.vue +90 -34
  6. package/dist/runtime/components/DataTable/ColumnsMenu.vue.d.ts +2 -0
  7. package/dist/runtime/components/DataTable/DataTable.d.vue.ts +26 -2
  8. package/dist/runtime/components/DataTable/DataTable.vue +256 -108
  9. package/dist/runtime/components/DataTable/DataTable.vue.d.ts +26 -2
  10. package/dist/runtime/components/DataTable/FilterMenu.d.vue.ts +5 -3
  11. package/dist/runtime/components/DataTable/FilterMenu.vue +32 -36
  12. package/dist/runtime/components/DataTable/FilterMenu.vue.d.ts +5 -3
  13. package/dist/runtime/components/DataTable/types.d.ts +15 -2
  14. package/dist/runtime/components/Shared/FloatingPanel.d.vue.ts +55 -0
  15. package/dist/runtime/components/Shared/FloatingPanel.vue +118 -0
  16. package/dist/runtime/components/Shared/FloatingPanel.vue.d.ts +55 -0
  17. package/dist/runtime/composables/useFloatingPanel.d.ts +69 -0
  18. package/dist/runtime/composables/useFloatingPanel.js +112 -0
  19. package/dist/runtime/composables/useTalkbackChannels.d.ts +21 -6
  20. package/dist/runtime/composables/useTalkbackChannels.js +16 -12
  21. package/dist/runtime/lib/columnOrder.d.ts +45 -0
  22. package/dist/runtime/lib/columnOrder.js +28 -0
  23. package/dist/runtime/lib/columnVisibility.d.ts +41 -0
  24. package/dist/runtime/lib/columnVisibility.js +12 -0
  25. package/dist/runtime/lib/dataTableFilters.d.ts +83 -0
  26. package/dist/runtime/lib/dataTableFilters.js +23 -0
  27. package/dist/runtime/lib/i18nBridge.d.ts +7 -2
  28. package/dist/types.d.mts +2 -0
  29. package/package.json +2 -2
package/dist/module.d.mts CHANGED
@@ -7,6 +7,7 @@ export { PlatformTenant } from '../dist/runtime/composables/usePlatformTenant.js
7
7
  export { PlatformTalkback } from '../dist/runtime/composables/usePlatformTalkback.js';
8
8
  export { TalkbackChannel, TalkbackChannelOptions, TalkbackMaybeRef } from '../dist/runtime/composables/useTalkbackChannels.js';
9
9
  export { MediaLibraryClient } from '../dist/runtime/composables/useMediaLibrary.js';
10
+ export { FloatingPanelDock, FloatingPanelMode, FloatingPanelOptions } from '../dist/runtime/composables/useFloatingPanel.js';
10
11
  export { IsoOption } from '../dist/runtime/lib/isoLists.js';
11
12
  export { Translate, TranslateNamed, Translator } from '../dist/runtime/lib/i18nBridge.js';
12
13
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "studio-shared",
3
3
  "configKey": "studioShared",
4
- "version": "0.3.0",
4
+ "version": "0.3.2",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -36,6 +36,11 @@ const module$1 = defineNuxtModule({
36
36
  // Collapsible list-rail state (persisted per surface) behind the
37
37
  // DataTable toolbar's rail handle.
38
38
  { name: "useListRail", from: join(runtime, "composables/useListRail"), priority: -1 },
39
+ // A panel that docks to either side of a canvas, floats anywhere on it,
40
+ // or collapses to a pill — and is dragged between those by its header.
41
+ // Lifted out of the integration studio's workflow editor so a second
42
+ // editor can have the same panels without a second implementation.
43
+ { name: "useFloatingPanel", from: join(runtime, "composables/useFloatingPanel"), priority: -1 },
39
44
  // Realtime provider seam (Talkback). Composes usePlatformAuth +
40
45
  // usePlatformTenant, so a host that overrides those gets a correct client
41
46
  // without overriding this one too.
@@ -6,7 +6,9 @@ type __VLS_Props = {
6
6
  };
7
7
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
8
  toggle: (key: string) => any;
9
+ reorder: (from: number, to: number) => any;
9
10
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
10
11
  onToggle?: ((key: string) => any) | undefined;
12
+ onReorder?: ((from: number, to: number) => any) | undefined;
11
13
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
14
  export default _default;
@@ -1,51 +1,107 @@
1
1
  <script setup>
2
- import { Widget as Columns, CheckCircle as Check } from "#solar-icons";
3
- import {
4
- DropdownMenu,
5
- DropdownMenuContent,
6
- DropdownMenuItem,
7
- DropdownMenuLabel,
8
- DropdownMenuSeparator,
9
- DropdownMenuTrigger
10
- } from "@revenexx/studio";
2
+ import { Eye, EyeClosed, ListArrowDownMinimalistic, Widget as Columns } from "#solar-icons";
3
+ import { Popover, PopoverContent, PopoverTrigger } from "@revenexx/studio";
11
4
  const props = defineProps({
12
5
  columns: { type: Array, required: true },
13
6
  visible: { type: Set, required: true }
14
7
  });
15
- const emit = defineEmits(["toggle"]);
16
- const toggleable = computed(() => props.columns.filter((c) => c.toggleable !== false));
8
+ const emit = defineEmits(["toggle", "reorder"]);
9
+ const listed = computed(() => props.columns);
10
+ const visibleCount = computed(() => props.columns.filter((c) => props.visible.has(c.key)).length);
11
+ function canHide(col) {
12
+ if (col.toggleable === false) return false;
13
+ return !props.visible.has(col.key) || visibleCount.value > 1;
14
+ }
15
+ const dragging = ref(null);
16
+ const over = ref(null);
17
+ const announcement = ref("");
18
+ function move(from, to) {
19
+ if (to < 0 || to >= listed.value.length || to === from) return;
20
+ emit("reorder", from, to);
21
+ const column = listed.value[from];
22
+ if (column) announcement.value = `${column.label}, ${to + 1} / ${listed.value.length}`;
23
+ }
24
+ function onDrop(index) {
25
+ if (dragging.value !== null) move(dragging.value, index);
26
+ dragging.value = null;
27
+ over.value = null;
28
+ }
29
+ function onKey(event, index) {
30
+ if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
31
+ event.preventDefault();
32
+ const to = event.key === "ArrowUp" ? index - 1 : index + 1;
33
+ move(index, to);
34
+ const list = event.currentTarget.closest("[data-columns-list]");
35
+ requestAnimationFrame(() => {
36
+ list?.querySelectorAll("[data-column-handle]")[to]?.focus();
37
+ });
38
+ }
17
39
  const t = useT();
18
40
  </script>
19
41
 
20
42
  <template>
21
- <DropdownMenu>
22
- <DropdownMenuTrigger as-child>
43
+ <Popover>
44
+ <PopoverTrigger as-child>
23
45
  <button
24
46
  type="button"
25
47
  class="flex size-7 items-center justify-center rounded-md border border-black/[0.06] bg-white text-muted-foreground transition hover:text-foreground"
26
48
  :title="t('shared.datatable.columnsmenu.tooltip')"
27
49
  >
28
- <Columns :size="15" />
50
+ <Columns :size="15" weight="Bold" />
29
51
  </button>
30
- </DropdownMenuTrigger>
31
- <DropdownMenuContent align="end" class="w-48">
32
- <DropdownMenuLabel class="text-sm text-muted-foreground">
52
+ </PopoverTrigger>
53
+
54
+ <PopoverContent align="end" class="w-60 p-1.5">
55
+ <p class="px-2 py-1.5 text-sm text-muted-foreground">
33
56
  {{ t("shared.datatable.columnsmenu.heading") }}
34
- </DropdownMenuLabel>
35
- <DropdownMenuSeparator />
36
- <DropdownMenuItem
37
- v-for="col in toggleable"
38
- :key="col.key"
39
- class="justify-between gap-2"
40
- @select.prevent="emit('toggle', col.key)"
41
- >
42
- <span class="truncate">{{ col.label }}</span>
43
- <Check
44
- v-if="visible.has(col.key)"
45
- :size="14"
46
- class="text-muted-foreground shrink-0"
47
- />
48
- </DropdownMenuItem>
49
- </DropdownMenuContent>
50
- </DropdownMenu>
57
+ </p>
58
+
59
+ <div data-columns-list class="space-y-0.5">
60
+ <div
61
+ v-for="(col, index) in listed"
62
+ :key="col.key"
63
+ class="flex items-center gap-1 rounded-md pr-1 transition-colors"
64
+ :class="[
65
+ over === index && dragging !== null && dragging !== index ? 'bg-primary/10' : 'hover:bg-muted',
66
+ dragging === index && 'opacity-40'
67
+ ]"
68
+ @dragover.prevent="over = index"
69
+ @drop.prevent="onDrop(index)"
70
+ >
71
+ <button
72
+ type="button"
73
+ data-column-handle
74
+ draggable="true"
75
+ class="flex size-7 shrink-0 cursor-grab items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring active:cursor-grabbing"
76
+ :aria-label="t('shared.datatable.columnsmenu.reorder', { column: col.label })"
77
+ @dragstart="dragging = index"
78
+ @dragend="dragging = null;
79
+ over = null"
80
+ @keydown="onKey($event, index)"
81
+ >
82
+ <ListArrowDownMinimalistic :size="15" weight="Linear" />
83
+ </button>
84
+
85
+ <span
86
+ class="min-w-0 flex-1 truncate py-1.5 text-sm transition-colors"
87
+ :class="visible.has(col.key) ? 'text-foreground' : 'text-muted-foreground'"
88
+ >{{ col.label }}</span>
89
+
90
+ <button
91
+ type="button"
92
+ class="flex size-7 shrink-0 cursor-pointer items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-35"
93
+ :disabled="!canHide(col)"
94
+ :aria-pressed="visible.has(col.key)"
95
+ :aria-label="col.label"
96
+ @click="emit('toggle', col.key)"
97
+ >
98
+ <Eye v-if="visible.has(col.key)" :size="16" weight="Linear" />
99
+ <EyeClosed v-else :size="16" weight="Linear" />
100
+ </button>
101
+ </div>
102
+ </div>
103
+
104
+ <p class="sr-only" role="status" aria-live="polite">{{ announcement }}</p>
105
+ </PopoverContent>
106
+ </Popover>
51
107
  </template>
@@ -6,7 +6,9 @@ type __VLS_Props = {
6
6
  };
7
7
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
8
  toggle: (key: string) => any;
9
+ reorder: (from: number, to: number) => any;
9
10
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
10
11
  onToggle?: ((key: string) => any) | undefined;
12
+ onReorder?: ((from: number, to: number) => any) | undefined;
11
13
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
14
  export default _default;
@@ -11,8 +11,11 @@ declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>
11
11
  data: T[];
12
12
  columns: DataTableColumn<T>[];
13
13
  rowKey: RowKey<T>;
14
+ /** `label` is the field's accessible name; it defaults to the placeholder
15
+ * where the surface wrote one (see `searchLabel`). */
14
16
  search?: boolean | {
15
17
  placeholder?: string;
18
+ label?: string;
16
19
  };
17
20
  columnsMenu?: boolean;
18
21
  /** Mount the surface's own filter panel in the toolbar's Filter popover
@@ -20,6 +23,7 @@ declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>
20
23
  filter?: boolean | {
21
24
  width?: string;
22
25
  active?: boolean;
26
+ count?: number;
23
27
  };
24
28
  /** Built-in status/dimension filter pills (static mode). One dimension, or
25
29
  * several (each renders as its own sub-menu). */
@@ -32,6 +36,26 @@ declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>
32
36
  viewModes?: DataTableViewMode[] | null;
33
37
  /** Collapse handle for the surface's left rail (see `ListSurface`). */
34
38
  rail?: boolean | DataTableRail;
39
+ /**
40
+ * Scroll the ROWS inside the table instead of the page.
41
+ *
42
+ * The toolbar, the header and the footer stay put and only the data moves,
43
+ * so paging through a long list keeps the search box, the filters and the
44
+ * "showing 20 of 400" in view — you stay in the table's context instead of
45
+ * scrolling the whole surface away and losing the controls that scope it.
46
+ *
47
+ * OPT-IN. A short list scrolling inside a box shorter than the list is worse
48
+ * than a page that scrolls, and there is no way for this component to know
49
+ * which it is looking at.
50
+ *
51
+ * The header row moves INSIDE the scroll container and sticks, rather than
52
+ * sitting above it. That is not a detail: a scrollbar takes width from the
53
+ * scrolling box, so a header outside it stays wider than the rows and every
54
+ * column drifts by however wide the scrollbar is.
55
+ */
56
+ scrollBody?: boolean | {
57
+ maxHeight?: string;
58
+ };
35
59
  pagination?: boolean | {
36
60
  pageSize?: number;
37
61
  };
@@ -61,12 +85,12 @@ declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>
61
85
  }) => any) | undefined;
62
86
  } & {
63
87
  'filter-menu'?: (props: {}) => any;
88
+ } & {
89
+ scope?: (props: {}) => any;
64
90
  } & {
65
91
  'toolbar-left'?: (props: {}) => any;
66
92
  } & {
67
93
  'toolbar-right'?: (props: {}) => any;
68
- } & {
69
- scope?: (props: {}) => any;
70
94
  } & {
71
95
  actions?: (props: {}) => any;
72
96
  } & {