@alfakit/vue 0.1.9 → 0.1.10

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 (122) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/app/components.d.ts.map +1 -1
  3. package/dist/app/components.js +1 -0
  4. package/dist/app/components.js.map +1 -1
  5. package/dist/components/dev-tools/DevToolsInspector.js.map +1 -1
  6. package/dist/components/dev-tools/DevToolsInspector.vue.d.ts.map +1 -1
  7. package/dist/components/dev-tools/DevToolsInspector.vue_vue_type_script_setup_true_lang.js +1 -1
  8. package/dist/components/dev-tools/DevToolsInspector.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/fields/CheckboxListField.js.map +1 -1
  10. package/dist/components/fields/CheckboxListField.vue.d.ts.map +1 -1
  11. package/dist/components/fields/CheckboxListField.vue_vue_type_script_setup_true_lang.js +2 -2
  12. package/dist/components/fields/CheckboxListField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/fields/DatePickerField.js.map +1 -1
  14. package/dist/components/fields/DatePickerField.vue.d.ts.map +1 -1
  15. package/dist/components/fields/DatePickerField.vue_vue_type_script_setup_true_lang.js +34 -32
  16. package/dist/components/fields/DatePickerField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/fields/RichEditorSuggestions.js.map +1 -1
  18. package/dist/components/fields/RichEditorSuggestions.vue.d.ts +1 -1
  19. package/dist/components/fields/RichEditorSuggestions.vue.d.ts.map +1 -1
  20. package/dist/components/fields/RichEditorSuggestions.vue_vue_type_script_setup_true_lang.js +29 -23
  21. package/dist/components/fields/RichEditorSuggestions.vue_vue_type_script_setup_true_lang.js.map +1 -1
  22. package/dist/components/fields/RichEditorToolbarGroup.js.map +1 -1
  23. package/dist/components/fields/RichEditorToolbarGroup.vue.d.ts.map +1 -1
  24. package/dist/components/fields/RichEditorToolbarGroup.vue_vue_type_script_setup_true_lang.js +9 -4
  25. package/dist/components/fields/RichEditorToolbarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  26. package/dist/components/file-manager/FileManagerView.js.map +1 -1
  27. package/dist/components/file-manager/FileManagerView.vue.d.ts.map +1 -1
  28. package/dist/components/file-manager/FileManagerView.vue_vue_type_script_setup_true_lang.js +5 -1
  29. package/dist/components/file-manager/FileManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/components/layout/CalloutComponent.js.map +1 -1
  31. package/dist/components/layout/CalloutComponent.vue.d.ts.map +1 -1
  32. package/dist/components/layout/CalloutComponent.vue_vue_type_script_setup_true_lang.js +43 -39
  33. package/dist/components/layout/CalloutComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  34. package/dist/components/layout/EmptyStateComponent.js.map +1 -1
  35. package/dist/components/layout/EmptyStateComponent.vue.d.ts.map +1 -1
  36. package/dist/components/layout/EmptyStateComponent.vue_vue_type_script_setup_true_lang.js +29 -26
  37. package/dist/components/layout/EmptyStateComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/layout/MixedContent.js.map +1 -1
  39. package/dist/components/layout/MixedContent.vue.d.ts +5 -3
  40. package/dist/components/layout/MixedContent.vue.d.ts.map +1 -1
  41. package/dist/components/layout/MixedContent.vue_vue_type_script_setup_true_lang.js +5 -4
  42. package/dist/components/layout/MixedContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/components/layout/SectionComponent.js.map +1 -1
  44. package/dist/components/layout/SectionComponent.vue.d.ts.map +1 -1
  45. package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js +12 -8
  46. package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  47. package/dist/components/notifications/NotificationsMenu.js.map +1 -1
  48. package/dist/components/notifications/NotificationsMenu.vue.d.ts.map +1 -1
  49. package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js +133 -104
  50. package/dist/components/notifications/NotificationsMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  51. package/dist/components/panel/ShortcutsOverlay.js.map +1 -1
  52. package/dist/components/panel/ShortcutsOverlay.vue.d.ts.map +1 -1
  53. package/dist/components/panel/ShortcutsOverlay.vue_vue_type_script_setup_true_lang.js +20 -19
  54. package/dist/components/panel/ShortcutsOverlay.vue_vue_type_script_setup_true_lang.js.map +1 -1
  55. package/dist/components/table/ColumnManager.js.map +1 -1
  56. package/dist/components/table/ColumnManager.vue.d.ts.map +1 -1
  57. package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js +6 -6
  58. package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js.map +1 -1
  59. package/dist/components/table/Spreadsheet.js.map +1 -1
  60. package/dist/components/table/Spreadsheet.vue.d.ts.map +1 -1
  61. package/dist/components/table/Spreadsheet.vue_vue_type_script_setup_true_lang.js +37 -33
  62. package/dist/components/table/Spreadsheet.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/translation-manager/TranslationManagerView.js.map +1 -1
  64. package/dist/components/translation-manager/TranslationManagerView.vue.d.ts.map +1 -1
  65. package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js +1 -1
  66. package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/components/ui/SidebarMenuButton.js.map +1 -1
  68. package/dist/components/ui/SidebarMenuButton.vue.d.ts.map +1 -1
  69. package/dist/components/ui/SidebarMenuButton.vue_vue_type_script_setup_true_lang.js +12 -12
  70. package/dist/components/ui/SidebarMenuButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  71. package/dist/components/widgets/StatCard.js.map +1 -1
  72. package/dist/components/widgets/StatCard.vue.d.ts.map +1 -1
  73. package/dist/components/widgets/StatCard.vue_vue_type_script_setup_true_lang.js +30 -30
  74. package/dist/components/widgets/StatCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  75. package/dist/eject-manifest.json +2 -2
  76. package/dist/pages/AlfakitPage.js.map +1 -1
  77. package/dist/pages/AlfakitPage.vue.d.ts.map +1 -1
  78. package/dist/pages/AlfakitPage.vue_vue_type_script_setup_true_lang.js +16 -19
  79. package/dist/pages/AlfakitPage.vue_vue_type_script_setup_true_lang.js.map +1 -1
  80. package/dist/standalone/AlfakitComponent.js.map +1 -1
  81. package/dist/standalone/AlfakitComponent.vue.d.ts.map +1 -1
  82. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js +2 -2
  83. package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  84. package/dist/standalone/runtime.d.ts.map +1 -1
  85. package/dist/standalone/runtime.js +25 -25
  86. package/dist/standalone/runtime.js.map +1 -1
  87. package/dist/standalone.css +2 -1
  88. package/dist/starter-kit/AlfakitStarterKitRoot.js.map +1 -1
  89. package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts.map +1 -1
  90. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js +1 -1
  91. package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  92. package/dist/starter-kit/navigation.d.ts +6 -1
  93. package/dist/starter-kit/navigation.d.ts.map +1 -1
  94. package/dist/starter-kit/navigation.js +11 -10
  95. package/dist/starter-kit/navigation.js.map +1 -1
  96. package/dist/styles.css +2 -1
  97. package/dist/themes.css +4 -0
  98. package/package.json +2 -2
  99. package/src/app/components.ts +3 -0
  100. package/src/components/dev-tools/DevToolsInspector.vue +1 -1
  101. package/src/components/fields/CheckboxListField.vue +2 -2
  102. package/src/components/fields/DatePickerField.vue +1 -0
  103. package/src/components/fields/RichEditorSuggestions.vue +13 -6
  104. package/src/components/fields/RichEditorToolbarGroup.vue +16 -1
  105. package/src/components/file-manager/FileManagerView.vue +3 -1
  106. package/src/components/layout/CalloutComponent.vue +15 -2
  107. package/src/components/layout/EmptyStateComponent.vue +10 -1
  108. package/src/components/layout/MixedContent.vue +12 -4
  109. package/src/components/layout/SectionComponent.vue +20 -4
  110. package/src/components/notifications/NotificationsMenu.vue +45 -1
  111. package/src/components/panel/ShortcutsOverlay.vue +27 -22
  112. package/src/components/table/ColumnManager.vue +6 -4
  113. package/src/components/table/Spreadsheet.vue +9 -4
  114. package/src/components/translation-manager/TranslationManagerView.vue +1 -1
  115. package/src/components/ui/SidebarMenuButton.vue +6 -0
  116. package/src/components/widgets/StatCard.vue +6 -3
  117. package/src/pages/AlfakitPage.vue +13 -3
  118. package/src/standalone/AlfakitComponent.vue +8 -4
  119. package/src/standalone/runtime.ts +3 -0
  120. package/src/starter-kit/AlfakitStarterKitRoot.vue +3 -2
  121. package/src/starter-kit/navigation.ts +12 -1
  122. package/src/styles.css +2 -1
@@ -3,10 +3,10 @@ import n from "../ui/Button2.js";
3
3
  import r from "../ui/Dialog.js";
4
4
  import i from "../ui/DialogContent.js";
5
5
  import a from "../ui/DialogDescription.js";
6
- import ee from "../ui/DialogHeader.js";
7
- import o from "../ui/DialogTitle.js";
8
- import s from "./ShortcutKeys.js";
9
- import { bindingFromEvent as c, flattenActionGroup as l, saveShortcutOverrides as u, shortcutOverlayGroups as d, shortcuts as f } from "@alfakit/core";
6
+ import o from "../ui/DialogHeader.js";
7
+ import s from "../ui/DialogTitle.js";
8
+ import c from "./ShortcutKeys.js";
9
+ import { ShortcutRecorder as l, flattenActionGroup as ee, saveShortcutOverrides as u, shortcutOverlayGroups as d, shortcuts as f } from "@alfakit/core";
10
10
  import { Fragment as p, computed as m, createBlock as h, createCommentVNode as g, createElementBlock as _, createElementVNode as v, createTextVNode as y, createVNode as b, defineComponent as x, onBeforeUnmount as S, onMounted as C, openBlock as w, ref as T, renderList as E, toDisplayString as D, unref as O, watch as k, withCtx as A } from "vue";
11
11
  //#region src/components/panel/ShortcutsOverlay.vue?vue&type=script&setup=true&lang.ts
12
12
  var j = {
@@ -43,7 +43,7 @@ var j = {
43
43
  J.value = f.getVersion();
44
44
  });
45
45
  }), S(() => Z());
46
- let Q = m(() => (J.value, d(f.list(), l(q.value?.headerActions ?? [])))), te = (e) => ({
46
+ let Q = m(() => (J.value, d(f.list(), ee(q.value?.headerActions ?? [])))), te = (e) => ({
47
47
  general: K("shortcuts.groups.general", {}, "General"),
48
48
  navigation: K("shortcuts.groups.navigation", {}, "Navigation"),
49
49
  commands: K("shortcuts.groups.commands", {}, "Commands"),
@@ -60,22 +60,23 @@ var j = {
60
60
  k(Y, (e, t, n) => {
61
61
  if (!e || typeof window > "u") return;
62
62
  f.setPaused(!0);
63
- let r = (t) => {
64
- if (t.preventDefault(), t.stopPropagation(), t.key === "Escape") {
65
- Y.value = null, X.value = K("shortcuts.cancelled", {}, "Change cancelled.");
63
+ let r = new l({ onDone: (t) => {
64
+ Y.value = null;
65
+ let n = f.conflict([t], e);
66
+ if (n) {
67
+ X.value = K("shortcuts.conflict", { label: n.label }, `Already used by “${n.label}”.`);
66
68
  return;
67
69
  }
68
- let n = c(t);
69
- if (!n) return;
70
- let r = f.conflict([n], e);
71
- if (Y.value = null, r) {
72
- X.value = K("shortcuts.conflict", { label: r.label }, `Already used by “${r.label}”.`);
70
+ $(e, [t]);
71
+ } }), i = (e) => {
72
+ if (e.preventDefault(), e.stopPropagation(), e.key === "Escape") {
73
+ r.cancel(), Y.value = null, X.value = K("shortcuts.cancelled", {}, "Change cancelled.");
73
74
  return;
74
75
  }
75
- $(e, [n]);
76
+ r.press(e);
76
77
  };
77
- window.addEventListener("keydown", r, !0), n(() => {
78
- window.removeEventListener("keydown", r, !0), f.setPaused(!1);
78
+ window.addEventListener("keydown", i, !0), n(() => {
79
+ r.cancel(), window.removeEventListener("keydown", i, !0), f.setPaused(!1);
79
80
  });
80
81
  });
81
82
  let re = (e) => {
@@ -87,8 +88,8 @@ var j = {
87
88
  }, {
88
89
  default: A(() => [b(i, { class: "max-h-[85vh] overflow-y-auto sm:max-w-lg" }, {
89
90
  default: A(() => [v("div", j, [
90
- b(ee, null, {
91
- default: A(() => [b(o, null, {
91
+ b(o, null, {
92
+ default: A(() => [b(s, null, {
92
93
  default: A(() => [y(D(O(K)("shortcuts.title", {}, "Keyboard shortcuts")), 1)]),
93
94
  _: 1
94
95
  }), b(a, null, {
@@ -111,7 +112,7 @@ var j = {
111
112
  class: "flex items-center gap-3 px-3 py-2 text-sm"
112
113
  }, [
113
114
  v("span", R, D(e.label), 1),
114
- Y.value === e.id ? (w(), _("span", z, D(O(K)("shortcuts.press_keys", {}, "Press keys…")), 1)) : e.keys.length === 0 ? (w(), _("span", B, D(O(K)("shortcuts.off", {}, "Off")), 1)) : (w(), _("span", V, [(w(!0), _(p, null, E(e.keys, (e) => (w(), h(s, {
115
+ Y.value === e.id ? (w(), _("span", z, D(O(K)("shortcuts.press_keys", {}, "Press keys…")), 1)) : e.keys.length === 0 ? (w(), _("span", B, D(O(K)("shortcuts.off", {}, "Off")), 1)) : (w(), _("span", V, [(w(!0), _(p, null, E(e.keys, (e) => (w(), h(c, {
115
116
  key: e,
116
117
  binding: e
117
118
  }, null, 8, ["binding"]))), 128))])),
@@ -1 +1 @@
1
- {"version":3,"file":"ShortcutsOverlay.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Dialog","_withCtx","_createVNode","DialogContent","_createElementVNode","DialogHeader","DialogTitle","_createTextVNode","_toDisplayString","_unref","DialogDescription","_createElementBlock","_Fragment","_renderList","ShortcutKeys","Button","_createCommentVNode","Button_default","Dialog_default","DialogContent_default","DialogDescription_default","DialogHeader_default","DialogTitle_default","ShortcutKeys_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","ShortcutsOverlay_vue_vue_type_script_setup_true_lang_default","__emit","props","__props","emit","t","useT","page","usePageSchema","version","ref","shortcuts","recording","message","unsubscribe","onMounted","onBeforeUnmount","groups","computed","shortcutOverlayGroups","flattenActionGroup","groupLabel","group","save","saveShortcutOverrides","id","keys","change","item","listener","event","binding","bindingFromEvent","conflict","onCleanup","update","next","openBlock","createBlock","withCtx","createVNode","createElementVNode","createTextVNode","toDisplayString","unref","createElementBlock","Fragment","renderList","key","createCommentVNode"],"sources":["../../../src/components/panel/ShortcutsOverlay.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ShortcutListGroup, ShortcutListItem } from '@alfakit/core'\nimport {\n bindingFromEvent,\n flattenActionGroup,\n saveShortcutOverrides,\n shortcutOverlayGroups,\n shortcuts,\n} from '@alfakit/core'\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { usePageSchema, useT } from '../../context'\nimport Button from '../ui/Button.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport ShortcutKeys from './ShortcutKeys.vue'\n\n/** The `?` overlay: every shortcut on the page, grouped; users may change their keys. */\nconst props = defineProps<{ open: boolean; customizable: boolean; endpoint?: string }>()\nconst emit = defineEmits<{ 'update:open': [open: boolean] }>()\n\nconst t = useT()\nconst page = usePageSchema()\nconst version = ref(shortcuts.getVersion())\nconst recording = ref<string | null>(null)\nconst message = ref('')\n\n// Subscribed once mounted: a server render must not leave listeners on the shared registry.\nlet unsubscribe = () => {}\n\nonMounted(() => {\n version.value = shortcuts.getVersion()\n unsubscribe = shortcuts.subscribe(() => {\n version.value = shortcuts.getVersion()\n })\n})\n\nonBeforeUnmount(() => unsubscribe())\n\nconst groups = computed(() => {\n void version.value\n\n return shortcutOverlayGroups(\n shortcuts.list(),\n flattenActionGroup(page.value?.headerActions ?? []),\n )\n})\n\nconst groupLabel = (group: ShortcutListGroup['group']) =>\n ({\n general: t('shortcuts.groups.general', {}, 'General'),\n navigation: t('shortcuts.groups.navigation', {}, 'Navigation'),\n commands: t('shortcuts.groups.commands', {}, 'Commands'),\n actions: t('shortcuts.groups.actions', {}, 'Actions on this page'),\n })[group]\n\nconst save = async (id: string, keys: string[] | null) => {\n if (!props.endpoint) return\n\n try {\n shortcuts.setOverrides(await saveShortcutOverrides(props.endpoint, { [id]: keys }))\n message.value = t('shortcuts.saved', {}, 'Shortcut saved.')\n } catch {\n message.value = t('shortcuts.save_failed', {}, 'The shortcut could not be saved.')\n }\n}\n\nconst change = (item: ShortcutListItem) => {\n message.value = t(\n 'shortcuts.recording',\n { label: item.label },\n `Press the new keys for “${item.label}”. Escape cancels.`,\n )\n recording.value = item.id\n}\n\n// While recording, the next key press is the new binding (Escape cancels). Listening in the\n// capture phase keeps the key from closing the dialog or running another shortcut.\nwatch(recording, (id, _old, onCleanup) => {\n if (!id || typeof window === 'undefined') return\n\n shortcuts.setPaused(true)\n\n const listener = (event: KeyboardEvent) => {\n event.preventDefault()\n event.stopPropagation()\n\n if (event.key === 'Escape') {\n recording.value = null\n message.value = t('shortcuts.cancelled', {}, 'Change cancelled.')\n\n return\n }\n\n const binding = bindingFromEvent(event)\n\n if (!binding) return\n\n const conflict = shortcuts.conflict([binding], id)\n\n recording.value = null\n\n if (conflict) {\n message.value = t(\n 'shortcuts.conflict',\n { label: conflict.label },\n `Already used by “${conflict.label}”.`,\n )\n\n return\n }\n\n void save(id, [binding])\n }\n\n window.addEventListener('keydown', listener, true)\n onCleanup(() => {\n window.removeEventListener('keydown', listener, true)\n shortcuts.setPaused(false)\n })\n})\n\nconst update = (next: boolean) => {\n recording.value = null\n message.value = ''\n emit('update:open', next)\n}\n</script>\n\n<template>\n <Dialog :open=\"props.open\" @update:open=\"update\">\n <DialogContent class=\"max-h-[85vh] overflow-y-auto sm:max-w-lg\">\n <div data-slot=\"shortcuts-overlay\" class=\"flex flex-col gap-4\">\n <DialogHeader>\n <DialogTitle>{{ t('shortcuts.title', {}, 'Keyboard shortcuts') }}</DialogTitle>\n <DialogDescription>{{\n t('shortcuts.description', {}, 'Shortcuts available on this page.')\n }}</DialogDescription>\n </DialogHeader>\n <div role=\"status\" aria-live=\"polite\" class=\"text-muted-foreground min-h-5 text-sm\">\n {{ message }}\n </div>\n <div class=\"flex flex-col gap-5\">\n <section\n v-for=\"group in groups\"\n :key=\"group.group\"\n :data-group=\"group.group\"\n :aria-labelledby=\"`shortcuts-${group.group}`\"\n >\n <h3\n :id=\"`shortcuts-${group.group}`\"\n class=\"text-muted-foreground mb-2 text-xs font-medium uppercase\"\n >\n {{ groupLabel(group.group) }}\n </h3>\n <ul class=\"flex flex-col divide-y rounded-md border\">\n <li\n v-for=\"item in group.items\"\n :key=\"item.id\"\n :data-shortcut=\"item.id\"\n class=\"flex items-center gap-3 px-3 py-2 text-sm\"\n >\n <span class=\"min-w-0 flex-1 truncate\">{{ item.label }}</span>\n <span v-if=\"recording === item.id\" class=\"text-primary text-xs\">{{\n t('shortcuts.press_keys', {}, 'Press keys…')\n }}</span>\n <span v-else-if=\"item.keys.length === 0\" class=\"text-muted-foreground text-xs\">{{\n t('shortcuts.off', {}, 'Off')\n }}</span>\n <span v-else class=\"flex flex-wrap items-center justify-end gap-2\">\n <ShortcutKeys v-for=\"key in item.keys\" :key=\"key\" :binding=\"key\" />\n </span>\n <span v-if=\"props.customizable && item.customizable\" class=\"flex shrink-0 gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n :aria-label=\"\n t(\n 'shortcuts.change_label',\n { label: item.label },\n `Change the shortcut for ${item.label}`,\n )\n \"\n @click=\"change(item)\"\n >{{ t('shortcuts.change', {}, 'Change') }}</Button\n >\n <Button\n v-if=\"item.keys.length > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n :aria-label=\"\n t(\n 'shortcuts.turn_off_label',\n { label: item.label },\n `Turn off the shortcut for ${item.label}`,\n )\n \"\n @click=\"save(item.id, [])\"\n >{{ t('shortcuts.turn_off', {}, 'Turn off') }}</Button\n >\n <Button\n v-if=\"item.customized\"\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n :aria-label=\"\n t(\n 'shortcuts.reset_label',\n { label: item.label },\n `Restore the default shortcut for ${item.label}`,\n )\n \"\n @click=\"save(item.id, null)\"\n >{{ t('shortcuts.reset', {}, 'Reset') }}</Button\n >\n </span>\n </li>\n </ul>\n </section>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"ShortcutsOverlay.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Dialog","_withCtx","_createVNode","DialogContent","_createElementVNode","DialogHeader","DialogTitle","_createTextVNode","_toDisplayString","_unref","DialogDescription","_createElementBlock","_Fragment","_renderList","ShortcutKeys","Button","_createCommentVNode","Button_default","Dialog_default","DialogContent_default","DialogDescription_default","DialogHeader_default","DialogTitle_default","ShortcutKeys_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","ShortcutsOverlay_vue_vue_type_script_setup_true_lang_default","__emit","props","__props","emit","t","useT","page","usePageSchema","version","ref","shortcuts","recording","message","unsubscribe","onMounted","onBeforeUnmount","groups","computed","shortcutOverlayGroups","flattenActionGroup","groupLabel","group","save","saveShortcutOverrides","id","keys","change","item","recorder","ShortcutRecorder","conflict","binding","listener","event","onCleanup","update","next","openBlock","createBlock","withCtx","createVNode","createElementVNode","createTextVNode","toDisplayString","unref","createElementBlock","Fragment","renderList","key","createCommentVNode"],"sources":["../../../src/components/panel/ShortcutsOverlay.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ShortcutListGroup, ShortcutListItem } from '@alfakit/core'\nimport {\n ShortcutRecorder,\n flattenActionGroup,\n saveShortcutOverrides,\n shortcutOverlayGroups,\n shortcuts,\n} from '@alfakit/core'\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { usePageSchema, useT } from '../../context'\nimport Button from '../ui/Button.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport ShortcutKeys from './ShortcutKeys.vue'\n\n/** The `?` overlay: every shortcut on the page, grouped; users may change their keys. */\nconst props = defineProps<{ open: boolean; customizable: boolean; endpoint?: string }>()\nconst emit = defineEmits<{ 'update:open': [open: boolean] }>()\n\nconst t = useT()\nconst page = usePageSchema()\nconst version = ref(shortcuts.getVersion())\nconst recording = ref<string | null>(null)\nconst message = ref('')\n\n// Subscribed once mounted: a server render must not leave listeners on the shared registry.\nlet unsubscribe = () => {}\n\nonMounted(() => {\n version.value = shortcuts.getVersion()\n unsubscribe = shortcuts.subscribe(() => {\n version.value = shortcuts.getVersion()\n })\n})\n\nonBeforeUnmount(() => unsubscribe())\n\nconst groups = computed(() => {\n void version.value\n\n return shortcutOverlayGroups(\n shortcuts.list(),\n flattenActionGroup(page.value?.headerActions ?? []),\n )\n})\n\nconst groupLabel = (group: ShortcutListGroup['group']) =>\n ({\n general: t('shortcuts.groups.general', {}, 'General'),\n navigation: t('shortcuts.groups.navigation', {}, 'Navigation'),\n commands: t('shortcuts.groups.commands', {}, 'Commands'),\n actions: t('shortcuts.groups.actions', {}, 'Actions on this page'),\n })[group]\n\nconst save = async (id: string, keys: string[] | null) => {\n if (!props.endpoint) return\n\n try {\n shortcuts.setOverrides(await saveShortcutOverrides(props.endpoint, { [id]: keys }))\n message.value = t('shortcuts.saved', {}, 'Shortcut saved.')\n } catch {\n message.value = t('shortcuts.save_failed', {}, 'The shortcut could not be saved.')\n }\n}\n\nconst change = (item: ShortcutListItem) => {\n message.value = t(\n 'shortcuts.recording',\n { label: item.label },\n `Press the new keys for “${item.label}”. Escape cancels.`,\n )\n recording.value = item.id\n}\n\n// While recording, the keys pressed are the new binding: one key (with modifiers) or a\n// sequence (\"g o\"), finished a second after the last key (Escape cancels). Listening in\n// the capture phase keeps the keys from closing the dialog or running another shortcut.\nwatch(recording, (id, _old, onCleanup) => {\n if (!id || typeof window === 'undefined') return\n\n shortcuts.setPaused(true)\n\n const recorder = new ShortcutRecorder({\n onDone: (binding) => {\n recording.value = null\n\n const conflict = shortcuts.conflict([binding], id)\n\n if (conflict) {\n message.value = t(\n 'shortcuts.conflict',\n { label: conflict.label },\n `Already used by “${conflict.label}”.`,\n )\n\n return\n }\n\n void save(id, [binding])\n },\n })\n\n const listener = (event: KeyboardEvent) => {\n event.preventDefault()\n event.stopPropagation()\n\n if (event.key === 'Escape') {\n recorder.cancel()\n recording.value = null\n message.value = t('shortcuts.cancelled', {}, 'Change cancelled.')\n\n return\n }\n\n recorder.press(event)\n }\n\n window.addEventListener('keydown', listener, true)\n onCleanup(() => {\n recorder.cancel()\n window.removeEventListener('keydown', listener, true)\n shortcuts.setPaused(false)\n })\n})\n\nconst update = (next: boolean) => {\n recording.value = null\n message.value = ''\n emit('update:open', next)\n}\n</script>\n\n<template>\n <Dialog :open=\"props.open\" @update:open=\"update\">\n <DialogContent class=\"max-h-[85vh] overflow-y-auto sm:max-w-lg\">\n <div data-slot=\"shortcuts-overlay\" class=\"flex flex-col gap-4\">\n <DialogHeader>\n <DialogTitle>{{ t('shortcuts.title', {}, 'Keyboard shortcuts') }}</DialogTitle>\n <DialogDescription>{{\n t('shortcuts.description', {}, 'Shortcuts available on this page.')\n }}</DialogDescription>\n </DialogHeader>\n <div role=\"status\" aria-live=\"polite\" class=\"text-muted-foreground min-h-5 text-sm\">\n {{ message }}\n </div>\n <div class=\"flex flex-col gap-5\">\n <section\n v-for=\"group in groups\"\n :key=\"group.group\"\n :data-group=\"group.group\"\n :aria-labelledby=\"`shortcuts-${group.group}`\"\n >\n <h3\n :id=\"`shortcuts-${group.group}`\"\n class=\"text-muted-foreground mb-2 text-xs font-medium uppercase\"\n >\n {{ groupLabel(group.group) }}\n </h3>\n <ul class=\"flex flex-col divide-y rounded-md border\">\n <li\n v-for=\"item in group.items\"\n :key=\"item.id\"\n :data-shortcut=\"item.id\"\n class=\"flex items-center gap-3 px-3 py-2 text-sm\"\n >\n <span class=\"min-w-0 flex-1 truncate\">{{ item.label }}</span>\n <span v-if=\"recording === item.id\" class=\"text-primary text-xs\">{{\n t('shortcuts.press_keys', {}, 'Press keys…')\n }}</span>\n <span v-else-if=\"item.keys.length === 0\" class=\"text-muted-foreground text-xs\">{{\n t('shortcuts.off', {}, 'Off')\n }}</span>\n <span v-else class=\"flex flex-wrap items-center justify-end gap-2\">\n <ShortcutKeys v-for=\"key in item.keys\" :key=\"key\" :binding=\"key\" />\n </span>\n <span v-if=\"props.customizable && item.customizable\" class=\"flex shrink-0 gap-1\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n :aria-label=\"\n t(\n 'shortcuts.change_label',\n { label: item.label },\n `Change the shortcut for ${item.label}`,\n )\n \"\n @click=\"change(item)\"\n >{{ t('shortcuts.change', {}, 'Change') }}</Button\n >\n <Button\n v-if=\"item.keys.length > 0\"\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n :aria-label=\"\n t(\n 'shortcuts.turn_off_label',\n { label: item.label },\n `Turn off the shortcut for ${item.label}`,\n )\n \"\n @click=\"save(item.id, [])\"\n >{{ t('shortcuts.turn_off', {}, 'Turn off') }}</Button\n >\n <Button\n v-if=\"item.customized\"\n type=\"button\"\n variant=\"ghost\"\n size=\"xs\"\n :aria-label=\"\n t(\n 'shortcuts.reset_label',\n { label: item.label },\n `Restore the default shortcut for ${item.label}`,\n )\n \"\n @click=\"save(item.id, null)\"\n >{{ t('shortcuts.reset', {}, 'Reset') }}</Button\n >\n </span>\n </li>\n </ul>\n </section>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnManager.js","names":["_sfc_main","ColumnManager_vue_vue_type_script_setup_true_lang_default","ColumnManager_default"],"sources":["../../../src/components/table/ColumnManager.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { TableSchema } from '@alfakit/core'\nimport {\n columnDraftChanged,\n columnManagerPosition,\n columnOrderChanged,\n defaultVisibleColumns,\n FILTERS_MODAL_WIDTH_CLASSES,\n gridColumnsClasses,\n keepMoveButtonFocus,\n moveColumnInManager,\n moveColumnTo,\n orderColumnsBy,\n saveColumnOrder,\n slideOverSide,\n toggleVisibleColumn,\n triggerButtonView,\n visitTable,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon, Columns3Icon, GripVerticalIcon } from '@lucide/vue'\nimport { createReusableTemplate } from '@vueuse/core'\nimport { computed, ref, useId, watch } from 'vue'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { showToast } from '../notifications/flash-toasts'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport DialogTrigger from '../ui/DialogTrigger.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport TableTriggerButton from './TableTriggerButton.vue'\n\n/**\n * The column manager: show / hide toggleable columns (kept in the query string) and, with\n * `reorderableColumns()`, move columns (stored per user on the server) by dragging a row\n * onto another or with the move up / down buttons (the keyboard path).\n *\n * `deferColumnManager()` keeps toggles in a draft until \"Apply\"; `columnManagerLayout()`\n * opens it in a dialog; `columnManagerColumns()` lays the list out in a grid.\n */\nconst props = defineProps<{ table: TableSchema; token: string; component: string }>()\nconst t = useT()\nconst panel = usePanel()\nconst direction = useDirection()\nconst open = ref(false)\n// `columnManagerTriggerAction()` may set `slideOver()`, `modalWidth()` and the heading.\nconst modal = computed(() => props.table.triggerActions?.columnManager?.modal)\nconst modalHeading = computed(() => modal.value?.heading ?? t('table.columns', {}, 'Columns'))\nconst modalDescription = computed(() => modal.value?.description ?? props.table.pluralModelLabel)\nconst modalWidthClass = computed(() =>\n modal.value?.width ? FILTERS_MODAL_WIDTH_CLASSES[modal.value.width] : undefined,\n)\nconst saving = ref(false)\nconst dragging = ref<string | null>(null)\nconst dropTarget = ref<string | null>(null)\n// Toggles of a deferred column manager wait here until \"Apply\".\nconst draft = ref<string[] | null>(null)\nconst reorderable = computed(() =>\n Boolean(props.table.reorderableColumns && panel.value.endpoints.tableColumns),\n)\nconst toggleable = computed(() => Boolean(props.table.toggleableColumns))\nconst deferred = computed(() => Boolean(props.table.deferColumnManager))\n// A moved column order: the draft of a deferred column manager, or shown at once while\n// it is saved.\nconst orderDraft = ref<string[] | null>(null)\n// Screen-reader announcement of the last move.\nconst announcement = ref('')\nconst idBase = useId()\nconst columns = computed(() =>\n orderColumnsBy(\n reorderable.value\n ? props.table.columns\n : props.table.columns.filter((column) => column.toggleable),\n orderDraft.value,\n ),\n)\nconst appliedNames = computed(() => props.table.columns.map((column) => column.name))\nconst names = computed(() => orderDraft.value ?? appliedNames.value)\nconst orderChanged = computed(\n () => orderDraft.value !== null && columnOrderChanged(appliedNames.value, orderDraft.value),\n)\nconst positions = computed(() =>\n Object.fromEntries(\n columns.value.map((column) => [\n column.name,\n columnManagerPosition(names.value, column.name, props.table.columnGroups),\n ]),\n ),\n)\n\n// The server's order replaces the one shown while saving.\nwatch(\n () => props.table.columns,\n () => {\n if (!deferred.value) orderDraft.value = null\n },\n)\nconst visible = computed(() => draft.value ?? props.table.visibleColumns)\n\nconst trigger = computed(() =>\n triggerButtonView(props.table, 'columnManager', {\n label: t('table.columns', {}, 'Columns'),\n showLabel: false,\n }),\n)\nconst resetView = computed(() =>\n triggerButtonView(props.table, 'columnManagerReset', {\n label: toggleable.value\n ? t('table.reset_columns', {}, 'Reset')\n : t('table.reset_column_order', {}, 'Reset column order'),\n variant: 'ghost',\n }),\n)\nconst applyView = computed(() =>\n deferred.value\n ? triggerButtonView(props.table, 'columnManagerApply', {\n label: t('table_filters.apply', {}, 'Apply'),\n variant: 'default',\n })\n : null,\n)\nconst inHeader = computed(() => props.table.columnManagerResetActionPosition === 'header')\nconst draftChanged = computed(\n () => draft.value !== null && columnDraftChanged(props.table.visibleColumns, draft.value),\n)\n\nconst toggle = (name: string) => {\n const next = toggleVisibleColumn(visible.value, name)\n\n if (deferred.value) {\n draft.value = next\n } else {\n visitTable(props.table.identifier, { columns: next }, ['page'])\n }\n}\n\nconst dragStart = (event: DragEvent, name: string) => {\n if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'\n dragging.value = name\n}\n\nconst dragOver = (event: DragEvent, name: string) => {\n if (dragging.value === null) return\n\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n dropTarget.value = name\n}\n\nconst drop = (name: string) => {\n if (dragging.value !== null && dragging.value !== name) {\n reorder(dragging.value, moveColumnTo(names.value, dragging.value, name))\n }\n\n dragging.value = null\n dropTarget.value = null\n}\n\nconst save = async (order: string[]): Promise<boolean> => {\n const endpoint = panel.value.endpoints.tableColumns\n\n if (!endpoint) return false\n\n saving.value = true\n\n try {\n await saveColumnOrder(endpoint, props.token, props.component, order)\n\n return true\n } catch (error) {\n showToast({\n id: 'alfakit-column-order-failed',\n title: t('table.column_order_failed', {}, \"Couldn't save the column order\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n\n return false\n } finally {\n saving.value = false\n }\n}\n\nconst positionText = (name: string) => {\n const { position, count, group } = positions.value[name] ?? { position: 0, count: 0 }\n\n return group\n ? t(\n 'table.column_manager.position_in_group',\n { position, count, group },\n `Position ${position} of ${count} in ${group}.`,\n )\n : t('table.column_manager.position', { position, count }, `Position ${position} of ${count}.`)\n}\n\nconst announce = (name: string, order: string[]) => {\n const { position, count, group } = columnManagerPosition(order, name, props.table.columnGroups)\n const label = props.table.columns.find((column) => column.name === name)?.label ?? name\n const replace = { column: label, position, count, group: group ?? '' }\n\n announcement.value = group\n ? deferred.value\n ? t(\n 'table.column_manager.reordered_in_group_deferred',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered_in_group',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}.`,\n )\n : deferred.value\n ? t(\n 'table.column_manager.reordered_deferred',\n replace,\n `${label} moved to position ${position} of ${count}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered',\n replace,\n `${label} moved to position ${position} of ${count}.`,\n )\n}\n\n// A new order: kept as a draft until \"Apply\" (`deferColumnManager()`), else saved now.\nconst reorder = (name: string, order: string[]) => {\n if (saving.value || !columnOrderChanged(names.value, order)) return\n\n orderDraft.value = order\n announcement.value = ''\n\n if (deferred.value) {\n announce(name, order)\n\n return\n }\n\n void save(order).then((saved) => {\n if (saved) announce(name, order)\n else orderDraft.value = null\n })\n}\n\nconst move = (name: string, offset: -1 | 1, event: MouseEvent) => {\n keepMoveButtonFocus(event.currentTarget as HTMLElement | null)\n reorder(name, moveColumnInManager(names.value, name, offset, props.table.columnGroups))\n}\n\n// The order is saved before the visibility visit: both requests share the session, and a\n// visit running alongside the save would write the old order back when it finishes.\nconst apply = async () => {\n const order = orderDraft.value && orderChanged.value ? orderDraft.value : null\n const columns =\n draft.value && columnDraftChanged(props.table.visibleColumns, draft.value) ? draft.value : null\n\n draft.value = null\n orderDraft.value = null\n announcement.value = ''\n open.value = false\n\n if (order) await save(order)\n\n if (columns) visitTable(props.table.identifier, { columns }, ['page'])\n}\n\n// Reset: the defined column order and, for toggleable columns, the default visibility.\nconst reset = async () => {\n if (reorderable.value) {\n orderDraft.value = null\n await save([])\n }\n\n if (toggleable.value) {\n draft.value = null\n visitTable(props.table.identifier, { columns: defaultVisibleColumns(props.table) }, ['page'])\n }\n}\n\nconst setOpen = (next: boolean) => {\n // Closing without \"Apply\" drops the draft.\n if (!next) {\n draft.value = null\n if (deferred.value) orderDraft.value = null\n announcement.value = ''\n }\n open.value = next\n}\n\nconst [DefineBody, ManagerBody] = createReusableTemplate()\nconst [DefineReset, ResetButton] = createReusableTemplate()\n</script>\n\n<template>\n <template v-if=\"(toggleable || reorderable) && trigger\">\n <DefineReset>\n <TableTriggerButton\n v-if=\"resetView\"\n :view=\"resetView\"\n :disabled=\"saving\"\n data-slot=\"column-manager-reset\"\n :class=\"cn(!applyView && 'w-full')\"\n @click=\"reset\"\n />\n </DefineReset>\n <DefineBody>\n <div class=\"flex flex-col gap-1\">\n <div v-if=\"inHeader && resetView\" class=\"flex justify-end\"><ResetButton /></div>\n <ul\n :class=\"\n cn(\n props.table.columnManagerColumns\n ? ['grid gap-0.5', gridColumnsClasses(props.table.columnManagerColumns)]\n : 'flex flex-col gap-0.5',\n )\n \"\n :aria-label=\"t('table.columns', {}, 'Columns')\"\n >\n <li\n v-for=\"column in columns\"\n :key=\"column.name\"\n :data-column=\"column.name\"\n :draggable=\"reorderable && !saving\"\n :class=\"\n cn(\n 'flex items-center gap-2 rounded-md px-2 py-1 text-sm',\n reorderable && 'cursor-grab',\n dragging === column.name && 'opacity-50',\n dropTarget === column.name && dragging !== column.name && 'bg-muted',\n )\n \"\n @dragstart=\"dragStart($event, column.name)\"\n @dragover=\"dragOver($event, column.name)\"\n @dragleave=\"dropTarget === column.name && (dropTarget = null)\"\n @dragend=\"((dragging = null), (dropTarget = null))\"\n @drop.prevent=\"drop(column.name)\"\n >\n <GripVerticalIcon\n v-if=\"reorderable\"\n class=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n <label v-if=\"column.toggleable\" class=\"flex min-w-0 flex-1 items-center gap-2\">\n <Checkbox\n :model-value=\"visible.includes(column.name)\"\n @update:model-value=\"toggle(column.name)\"\n />\n <span class=\"truncate\">{{ column.label }}</span>\n </label>\n <span v-else class=\"min-w-0 flex-1 truncate\">{{ column.label }}</span>\n <span v-if=\"reorderable\" class=\"flex shrink-0 items-center\">\n <span\n :id=\"`${idBase}-${column.name}-position`\"\n class=\"sr-only\"\n data-slot=\"column-manager-position\"\n >{{ positionText(column.name) }}</span\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"(positions[column.name]?.position ?? 0) <= 1\"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_up', { column: column.label }, `Move ${column.label} up`)\n \"\n @click=\"move(column.name, -1, $event)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"\n (positions[column.name]?.position ?? 0) >= (positions[column.name]?.count ?? 0)\n \"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_down', { column: column.label }, `Move ${column.label} down`)\n \"\n @click=\"move(column.name, 1, $event)\"\n ><ChevronDownIcon\n /></Button>\n </span>\n </li>\n </ul>\n <div\n v-if=\"reorderable\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n class=\"sr-only\"\n data-slot=\"column-manager-announcement\"\n >\n {{ announcement }}\n </div>\n <div\n v-if=\"(!inHeader && resetView) || applyView\"\n class=\"mt-1 flex items-center justify-end gap-2\"\n >\n <ResetButton v-if=\"!inHeader\" />\n <TableTriggerButton\n v-if=\"applyView\"\n :view=\"applyView\"\n data-slot=\"column-manager-apply\"\n :disabled=\"!draftChanged && !orderChanged\"\n @click=\"apply\"\n />\n </div>\n </div>\n </DefineBody>\n <Sheet\n v-if=\"props.table.columnManagerLayout === 'modal' && modal?.slideOver\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <SheetTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </SheetTrigger>\n <SheetContent\n :side=\"slideOverSide(modal.slideOverPosition, direction)\"\n :class=\"cn('flex w-full flex-col gap-0 p-0', modalWidthClass ?? 'sm:max-w-md')\"\n data-slot=\"column-manager\"\n data-slide-over=\"\"\n >\n <SheetHeader class=\"border-b\">\n <SheetTitle>{{ modalHeading }}</SheetTitle>\n <SheetDescription :class=\"modal.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</SheetDescription>\n </SheetHeader>\n <div class=\"flex-1 overflow-y-auto p-4\"><ManagerBody /></div>\n </SheetContent>\n </Sheet>\n <Dialog\n v-else-if=\"props.table.columnManagerLayout === 'modal'\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <DialogTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </DialogTrigger>\n <DialogContent :class=\"modalWidthClass ?? 'sm:max-w-lg'\" data-slot=\"column-manager\">\n <DialogHeader>\n <DialogTitle>{{ modalHeading }}</DialogTitle>\n <DialogDescription :class=\"modal?.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</DialogDescription>\n </DialogHeader>\n <div class=\"max-h-[60vh] overflow-y-auto\"><ManagerBody /></div>\n </DialogContent>\n </Dialog>\n <Popover v-else :open=\"open\" @update:open=\"setOpen\">\n <PopoverTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n :class=\"cn('p-2', props.table.columnManagerColumns ? 'w-auto min-w-64' : 'w-64')\"\n data-slot=\"column-manager\"\n >\n <ManagerBody />\n </PopoverContent>\n </Popover>\n </template>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"ColumnManager.js","names":["_sfc_main","ColumnManager_vue_vue_type_script_setup_true_lang_default","ColumnManager_default"],"sources":["../../../src/components/table/ColumnManager.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { TableSchema } from '@alfakit/core'\nimport {\n columnDraftChanged,\n columnManagerPosition,\n columnOrderChanged,\n defaultVisibleColumns,\n FILTERS_MODAL_WIDTH_CLASSES,\n gridColumnsClasses,\n keepMoveButtonFocus,\n moveColumnInManager,\n moveColumnTo,\n orderColumnsBy,\n saveColumnOrder,\n slideOverSide,\n toggleVisibleColumn,\n triggerButtonView,\n visitTable,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon, Columns3Icon, GripVerticalIcon } from '@lucide/vue'\nimport { createReusableTemplate } from '@vueuse/core'\nimport { computed, ref, useId, watch } from 'vue'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { showToast } from '../notifications/flash-toasts'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport DialogTrigger from '../ui/DialogTrigger.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport TableTriggerButton from './TableTriggerButton.vue'\n\n/**\n * The column manager: show / hide toggleable columns (kept in the query string) and, with\n * `reorderableColumns()`, move columns (stored per user on the server) by dragging a row\n * onto another or with the move up / down buttons (the keyboard path).\n *\n * `deferColumnManager()` keeps toggles in a draft until \"Apply\"; `columnManagerLayout()`\n * opens it in a dialog; `columnManagerColumns()` lays the list out in a grid.\n */\nconst props = defineProps<{ table: TableSchema; token: string; component: string }>()\nconst t = useT()\nconst panel = usePanel()\nconst direction = useDirection()\nconst open = ref(false)\n// `columnManagerTriggerAction()` may set `slideOver()`, `modalWidth()` and the heading.\nconst modal = computed(() => props.table.triggerActions?.columnManager?.modal)\nconst modalHeading = computed(() => modal.value?.heading ?? t('table.columns', {}, 'Columns'))\nconst modalDescription = computed(() => modal.value?.description ?? props.table.pluralModelLabel)\nconst modalWidthClass = computed(() =>\n modal.value?.width ? FILTERS_MODAL_WIDTH_CLASSES[modal.value.width] : undefined,\n)\nconst saving = ref(false)\nconst dragging = ref<string | null>(null)\nconst dropTarget = ref<string | null>(null)\n// Toggles of a deferred column manager wait here until \"Apply\".\nconst draft = ref<string[] | null>(null)\nconst reorderable = computed(() =>\n Boolean(props.table.reorderableColumns && panel.value.endpoints.tableColumns),\n)\nconst toggleable = computed(() => Boolean(props.table.toggleableColumns))\nconst deferred = computed(() => Boolean(props.table.deferColumnManager))\n// A moved column order: the draft of a deferred column manager, or shown at once while\n// it is saved.\nconst orderDraft = ref<string[] | null>(null)\n// Screen-reader announcement of the last move.\nconst announcement = ref('')\nconst idBase = useId()\nconst columns = computed(() =>\n orderColumnsBy(\n reorderable.value\n ? props.table.columns\n : props.table.columns.filter((column) => column.toggleable),\n orderDraft.value,\n ),\n)\nconst appliedNames = computed(() => props.table.columns.map((column) => column.name))\nconst names = computed(() => orderDraft.value ?? appliedNames.value)\nconst orderChanged = computed(\n () => orderDraft.value !== null && columnOrderChanged(appliedNames.value, orderDraft.value),\n)\nconst positions = computed(() =>\n Object.fromEntries(\n columns.value.map((column) => [\n column.name,\n columnManagerPosition(names.value, column.name, props.table.columnGroups),\n ]),\n ),\n)\n\n// The server's order replaces the one shown while saving.\nwatch(\n () => props.table.columns,\n () => {\n if (!deferred.value) orderDraft.value = null\n },\n)\nconst visible = computed(() => draft.value ?? props.table.visibleColumns)\n\nconst trigger = computed(() =>\n triggerButtonView(props.table, 'columnManager', {\n label: t('table.columns', {}, 'Columns'),\n showLabel: false,\n }),\n)\nconst resetView = computed(() =>\n triggerButtonView(props.table, 'columnManagerReset', {\n label: toggleable.value\n ? t('table.reset_columns', {}, 'Reset')\n : t('table.reset_column_order', {}, 'Reset column order'),\n variant: 'ghost',\n }),\n)\nconst applyView = computed(() =>\n deferred.value\n ? triggerButtonView(props.table, 'columnManagerApply', {\n label: t('table_filters.apply', {}, 'Apply'),\n variant: 'default',\n })\n : null,\n)\nconst inHeader = computed(() => props.table.columnManagerResetActionPosition === 'header')\nconst draftChanged = computed(\n () => draft.value !== null && columnDraftChanged(props.table.visibleColumns, draft.value),\n)\n\nconst toggle = (name: string) => {\n const next = toggleVisibleColumn(visible.value, name)\n\n if (deferred.value) {\n draft.value = next\n } else {\n visitTable(props.table.identifier, { columns: next }, ['page'])\n }\n}\n\nconst dragStart = (event: DragEvent, name: string) => {\n if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'\n dragging.value = name\n}\n\nconst dragOver = (event: DragEvent, name: string) => {\n if (dragging.value === null) return\n\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n dropTarget.value = name\n}\n\nconst drop = (name: string) => {\n if (dragging.value !== null && dragging.value !== name) {\n reorder(dragging.value, moveColumnTo(names.value, dragging.value, name))\n }\n\n dragging.value = null\n dropTarget.value = null\n}\n\nconst save = async (order: string[], options: { reload?: boolean } = {}): Promise<boolean> => {\n const endpoint = panel.value.endpoints.tableColumns\n\n if (!endpoint) return false\n\n saving.value = true\n\n try {\n await saveColumnOrder(endpoint, props.token, props.component, order, options)\n\n return true\n } catch (error) {\n showToast({\n id: 'alfakit-column-order-failed',\n title: t('table.column_order_failed', {}, \"Couldn't save the column order\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n\n return false\n } finally {\n saving.value = false\n }\n}\n\nconst positionText = (name: string) => {\n const { position, count, group } = positions.value[name] ?? { position: 0, count: 0 }\n\n return group\n ? t(\n 'table.column_manager.position_in_group',\n { position, count, group },\n `Position ${position} of ${count} in ${group}.`,\n )\n : t('table.column_manager.position', { position, count }, `Position ${position} of ${count}.`)\n}\n\nconst announce = (name: string, order: string[]) => {\n const { position, count, group } = columnManagerPosition(order, name, props.table.columnGroups)\n const label = props.table.columns.find((column) => column.name === name)?.label ?? name\n const replace = { column: label, position, count, group: group ?? '' }\n\n announcement.value = group\n ? deferred.value\n ? t(\n 'table.column_manager.reordered_in_group_deferred',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered_in_group',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}.`,\n )\n : deferred.value\n ? t(\n 'table.column_manager.reordered_deferred',\n replace,\n `${label} moved to position ${position} of ${count}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered',\n replace,\n `${label} moved to position ${position} of ${count}.`,\n )\n}\n\n// A new order: kept as a draft until \"Apply\" (`deferColumnManager()`), else saved now.\nconst reorder = (name: string, order: string[]) => {\n if (saving.value || !columnOrderChanged(names.value, order)) return\n\n orderDraft.value = order\n announcement.value = ''\n\n if (deferred.value) {\n announce(name, order)\n\n return\n }\n\n void save(order).then((saved) => {\n if (saved) announce(name, order)\n else orderDraft.value = null\n })\n}\n\nconst move = (name: string, offset: -1 | 1, event: MouseEvent) => {\n keepMoveButtonFocus(event.currentTarget as HTMLElement | null)\n reorder(name, moveColumnInManager(names.value, name, offset, props.table.columnGroups))\n}\n\n// The order is saved before the visibility visit: both requests share the session, and a\n// visit running alongside the save would write the old order back when it finishes.\nconst apply = async () => {\n const order = orderDraft.value && orderChanged.value ? orderDraft.value : null\n const columns =\n draft.value && columnDraftChanged(props.table.visibleColumns, draft.value) ? draft.value : null\n\n draft.value = null\n orderDraft.value = null\n announcement.value = ''\n open.value = false\n\n // The visibility visit renders the new order too: no second reload racing it.\n if (order) await save(order, { reload: !columns })\n\n if (columns) visitTable(props.table.identifier, { columns }, ['page'])\n}\n\n// Reset: the defined column order and, for toggleable columns, the default visibility.\nconst reset = async () => {\n if (reorderable.value) {\n orderDraft.value = null\n // The visibility visit below renders the defined order too.\n await save([], { reload: !toggleable.value })\n }\n\n if (toggleable.value) {\n draft.value = null\n visitTable(props.table.identifier, { columns: defaultVisibleColumns(props.table) }, ['page'])\n }\n}\n\nconst setOpen = (next: boolean) => {\n // Closing without \"Apply\" drops the draft.\n if (!next) {\n draft.value = null\n if (deferred.value) orderDraft.value = null\n announcement.value = ''\n }\n open.value = next\n}\n\nconst [DefineBody, ManagerBody] = createReusableTemplate()\nconst [DefineReset, ResetButton] = createReusableTemplate()\n</script>\n\n<template>\n <template v-if=\"(toggleable || reorderable) && trigger\">\n <DefineReset>\n <TableTriggerButton\n v-if=\"resetView\"\n :view=\"resetView\"\n :disabled=\"saving\"\n data-slot=\"column-manager-reset\"\n :class=\"cn(!applyView && 'w-full')\"\n @click=\"reset\"\n />\n </DefineReset>\n <DefineBody>\n <div class=\"flex flex-col gap-1\">\n <div v-if=\"inHeader && resetView\" class=\"flex justify-end\"><ResetButton /></div>\n <ul\n :class=\"\n cn(\n props.table.columnManagerColumns\n ? ['grid gap-0.5', gridColumnsClasses(props.table.columnManagerColumns)]\n : 'flex flex-col gap-0.5',\n )\n \"\n :aria-label=\"t('table.columns', {}, 'Columns')\"\n >\n <li\n v-for=\"column in columns\"\n :key=\"column.name\"\n :data-column=\"column.name\"\n :draggable=\"reorderable && !saving\"\n :class=\"\n cn(\n 'flex items-center gap-2 rounded-md px-2 py-1 text-sm',\n reorderable && 'cursor-grab',\n dragging === column.name && 'opacity-50',\n dropTarget === column.name && dragging !== column.name && 'bg-muted',\n )\n \"\n @dragstart=\"dragStart($event, column.name)\"\n @dragover=\"dragOver($event, column.name)\"\n @dragleave=\"dropTarget === column.name && (dropTarget = null)\"\n @dragend=\"((dragging = null), (dropTarget = null))\"\n @drop.prevent=\"drop(column.name)\"\n >\n <GripVerticalIcon\n v-if=\"reorderable\"\n class=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n <label v-if=\"column.toggleable\" class=\"flex min-w-0 flex-1 items-center gap-2\">\n <Checkbox\n :model-value=\"visible.includes(column.name)\"\n @update:model-value=\"toggle(column.name)\"\n />\n <span class=\"truncate\">{{ column.label }}</span>\n </label>\n <span v-else class=\"min-w-0 flex-1 truncate\">{{ column.label }}</span>\n <span v-if=\"reorderable\" class=\"flex shrink-0 items-center\">\n <span\n :id=\"`${idBase}-${column.name}-position`\"\n class=\"sr-only\"\n data-slot=\"column-manager-position\"\n >{{ positionText(column.name) }}</span\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"(positions[column.name]?.position ?? 0) <= 1\"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_up', { column: column.label }, `Move ${column.label} up`)\n \"\n @click=\"move(column.name, -1, $event)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"\n (positions[column.name]?.position ?? 0) >= (positions[column.name]?.count ?? 0)\n \"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_down', { column: column.label }, `Move ${column.label} down`)\n \"\n @click=\"move(column.name, 1, $event)\"\n ><ChevronDownIcon\n /></Button>\n </span>\n </li>\n </ul>\n <div\n v-if=\"reorderable\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n class=\"sr-only\"\n data-slot=\"column-manager-announcement\"\n >\n {{ announcement }}\n </div>\n <div\n v-if=\"(!inHeader && resetView) || applyView\"\n class=\"mt-1 flex items-center justify-end gap-2\"\n >\n <ResetButton v-if=\"!inHeader\" />\n <TableTriggerButton\n v-if=\"applyView\"\n :view=\"applyView\"\n data-slot=\"column-manager-apply\"\n :disabled=\"!draftChanged && !orderChanged\"\n @click=\"apply\"\n />\n </div>\n </div>\n </DefineBody>\n <Sheet\n v-if=\"props.table.columnManagerLayout === 'modal' && modal?.slideOver\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <SheetTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </SheetTrigger>\n <SheetContent\n :side=\"slideOverSide(modal.slideOverPosition, direction)\"\n :class=\"cn('flex w-full flex-col gap-0 p-0', modalWidthClass ?? 'sm:max-w-md')\"\n data-slot=\"column-manager\"\n data-slide-over=\"\"\n >\n <SheetHeader class=\"border-b\">\n <SheetTitle>{{ modalHeading }}</SheetTitle>\n <SheetDescription :class=\"modal.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</SheetDescription>\n </SheetHeader>\n <div class=\"flex-1 overflow-y-auto p-4\"><ManagerBody /></div>\n </SheetContent>\n </Sheet>\n <Dialog\n v-else-if=\"props.table.columnManagerLayout === 'modal'\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <DialogTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </DialogTrigger>\n <DialogContent :class=\"modalWidthClass ?? 'sm:max-w-lg'\" data-slot=\"column-manager\">\n <DialogHeader>\n <DialogTitle>{{ modalHeading }}</DialogTitle>\n <DialogDescription :class=\"modal?.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</DialogDescription>\n </DialogHeader>\n <div class=\"max-h-[60vh] overflow-y-auto\"><ManagerBody /></div>\n </DialogContent>\n </Dialog>\n <Popover v-else :open=\"open\" @update:open=\"setOpen\">\n <PopoverTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n :class=\"cn('p-2', props.table.columnManagerColumns ? 'w-auto min-w-64' : 'w-64')\"\n data-slot=\"column-manager\"\n >\n <ManagerBody />\n </PopoverContent>\n </Popover>\n </template>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnManager.vue.d.ts","sourceRoot":"","sources":["../../../src/components/table/ColumnManager.vue"],"names":[],"mappings":"AAgfA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AA4ChD;;;;;;;GAOG;AACH,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;;AAs8B5E,wBAMG"}
1
+ {"version":3,"file":"ColumnManager.vue.d.ts","sourceRoot":"","sources":["../../../src/components/table/ColumnManager.vue"],"names":[],"mappings":"AAkfA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AA4ChD;;;;;;;GAOG;AACH,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;;AAw8B5E,wBAMG"}
@@ -84,12 +84,12 @@ var Ie = { class: "flex flex-col gap-1" }, Le = {
84
84
  N.value !== null && (e.preventDefault(), e.dataTransfer && (e.dataTransfer.dropEffect = "move"), P.value = t);
85
85
  }, it = (e) => {
86
86
  N.value !== null && N.value !== e && st(N.value, Ce(U.value, N.value, e)), N.value = null, P.value = null;
87
- }, Z = async (e) => {
88
- let t = Ye.value.endpoints.tableColumns;
89
- if (!t) return !1;
87
+ }, Z = async (e, t = {}) => {
88
+ let n = Ye.value.endpoints.tableColumns;
89
+ if (!n) return !1;
90
90
  M.value = !0;
91
91
  try {
92
- return await Te(t, D.token, D.component, e), !0;
92
+ return await Te(n, D.token, D.component, e, t), !0;
93
93
  } catch (e) {
94
94
  return o({
95
95
  id: "alfakit-column-order-failed",
@@ -136,9 +136,9 @@ var Ie = { class: "flex flex-col gap-1" }, Le = {
136
136
  xe(n.currentTarget), st(e, Se(U.value, e, t, D.table.columnGroups));
137
137
  }, lt = async () => {
138
138
  let e = z.value && W.value ? z.value : null, t = F.value && c(D.table.visibleColumns, F.value) ? F.value : null;
139
- F.value = null, z.value = null, B.value = "", k.value = !1, e && await Z(e), t && u(D.table.identifier, { columns: t }, ["page"]);
139
+ F.value = null, z.value = null, B.value = "", k.value = !1, e && await Z(e, { reload: !t }), t && u(D.table.identifier, { columns: t }, ["page"]);
140
140
  }, ut = async () => {
141
- I.value && (z.value = null, await Z([])), L.value && (F.value = null, u(D.table.identifier, { columns: ye(D.table) }, ["page"]));
141
+ I.value && (z.value = null, await Z([], { reload: !L.value })), L.value && (F.value = null, u(D.table.identifier, { columns: ye(D.table) }, ["page"]));
142
142
  }, Q = (e) => {
143
143
  e || (F.value = null, R.value && (z.value = null), B.value = ""), k.value = e;
144
144
  }, [dt, $] = E(), [ft, pt] = E();
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnManager.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_withCtx","_createBlock","TableTriggerButton","_normalizeClass","_createCommentVNode","_createElementVNode","_renderList","_withModifiers","Checkbox","_toDisplayString","Button","Sheet","SheetTrigger","Icon","SheetContent","SheetHeader","SheetTitle","_createTextVNode","SheetDescription","Dialog","DialogTrigger","DialogContent","DialogHeader","DialogTitle","DialogDescription","Popover","PopoverTrigger","PopoverContent","Icon_default","Button_default","Checkbox_default","Dialog_default","DialogContent_default","DialogDescription_default","DialogHeader_default","DialogTitle_default","DialogTrigger_default","Popover_default","PopoverContent_default","PopoverTrigger_default","Sheet_default","SheetContent_default","SheetDescription_default","SheetHeader_default","SheetTitle_default","SheetTrigger_default","TableTriggerButton_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","ColumnManager_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","panel","usePanel","direction","useDirection","open","ref","modal","computed","modalHeading","modalDescription","modalWidthClass","FILTERS_MODAL_WIDTH_CLASSES","saving","dragging","dropTarget","draft","reorderable","toggleable","deferred","orderDraft","announcement","idBase","useId","columns","orderColumnsBy","column","appliedNames","names","orderChanged","columnOrderChanged","positions","columnManagerPosition","visible","trigger","triggerButtonView","resetView","applyView","inHeader","draftChanged","columnDraftChanged","toggle","next","toggleVisibleColumn","name","visitTable","dragStart","event","dragOver","drop","reorder","moveColumnTo","save","endpoint","saveColumnOrder","order","error","showToast","positionText","group","position","count","announce","label","replace","saved","move","keepMoveButtonFocus","moveColumnInManager","offset","apply","reset","defaultVisibleColumns","setOpen","DefineBody","ManagerBody","createReusableTemplate","DefineReset","ResetButton","openBlock","createElementBlock","Fragment","createVNode","unref","withCtx","createBlock","normalizeClass","cn","createCommentVNode","createElementVNode","gridColumnsClasses","renderList","$event","_cache","withModifiers","GripVerticalIcon","toDisplayString","ChevronUpIcon","ChevronDownIcon","Columns3Icon","slideOverSide","createTextVNode"],"sources":["../../../src/components/table/ColumnManager.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { TableSchema } from '@alfakit/core'\nimport {\n columnDraftChanged,\n columnManagerPosition,\n columnOrderChanged,\n defaultVisibleColumns,\n FILTERS_MODAL_WIDTH_CLASSES,\n gridColumnsClasses,\n keepMoveButtonFocus,\n moveColumnInManager,\n moveColumnTo,\n orderColumnsBy,\n saveColumnOrder,\n slideOverSide,\n toggleVisibleColumn,\n triggerButtonView,\n visitTable,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon, Columns3Icon, GripVerticalIcon } from '@lucide/vue'\nimport { createReusableTemplate } from '@vueuse/core'\nimport { computed, ref, useId, watch } from 'vue'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { showToast } from '../notifications/flash-toasts'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport DialogTrigger from '../ui/DialogTrigger.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport TableTriggerButton from './TableTriggerButton.vue'\n\n/**\n * The column manager: show / hide toggleable columns (kept in the query string) and, with\n * `reorderableColumns()`, move columns (stored per user on the server) by dragging a row\n * onto another or with the move up / down buttons (the keyboard path).\n *\n * `deferColumnManager()` keeps toggles in a draft until \"Apply\"; `columnManagerLayout()`\n * opens it in a dialog; `columnManagerColumns()` lays the list out in a grid.\n */\nconst props = defineProps<{ table: TableSchema; token: string; component: string }>()\nconst t = useT()\nconst panel = usePanel()\nconst direction = useDirection()\nconst open = ref(false)\n// `columnManagerTriggerAction()` may set `slideOver()`, `modalWidth()` and the heading.\nconst modal = computed(() => props.table.triggerActions?.columnManager?.modal)\nconst modalHeading = computed(() => modal.value?.heading ?? t('table.columns', {}, 'Columns'))\nconst modalDescription = computed(() => modal.value?.description ?? props.table.pluralModelLabel)\nconst modalWidthClass = computed(() =>\n modal.value?.width ? FILTERS_MODAL_WIDTH_CLASSES[modal.value.width] : undefined,\n)\nconst saving = ref(false)\nconst dragging = ref<string | null>(null)\nconst dropTarget = ref<string | null>(null)\n// Toggles of a deferred column manager wait here until \"Apply\".\nconst draft = ref<string[] | null>(null)\nconst reorderable = computed(() =>\n Boolean(props.table.reorderableColumns && panel.value.endpoints.tableColumns),\n)\nconst toggleable = computed(() => Boolean(props.table.toggleableColumns))\nconst deferred = computed(() => Boolean(props.table.deferColumnManager))\n// A moved column order: the draft of a deferred column manager, or shown at once while\n// it is saved.\nconst orderDraft = ref<string[] | null>(null)\n// Screen-reader announcement of the last move.\nconst announcement = ref('')\nconst idBase = useId()\nconst columns = computed(() =>\n orderColumnsBy(\n reorderable.value\n ? props.table.columns\n : props.table.columns.filter((column) => column.toggleable),\n orderDraft.value,\n ),\n)\nconst appliedNames = computed(() => props.table.columns.map((column) => column.name))\nconst names = computed(() => orderDraft.value ?? appliedNames.value)\nconst orderChanged = computed(\n () => orderDraft.value !== null && columnOrderChanged(appliedNames.value, orderDraft.value),\n)\nconst positions = computed(() =>\n Object.fromEntries(\n columns.value.map((column) => [\n column.name,\n columnManagerPosition(names.value, column.name, props.table.columnGroups),\n ]),\n ),\n)\n\n// The server's order replaces the one shown while saving.\nwatch(\n () => props.table.columns,\n () => {\n if (!deferred.value) orderDraft.value = null\n },\n)\nconst visible = computed(() => draft.value ?? props.table.visibleColumns)\n\nconst trigger = computed(() =>\n triggerButtonView(props.table, 'columnManager', {\n label: t('table.columns', {}, 'Columns'),\n showLabel: false,\n }),\n)\nconst resetView = computed(() =>\n triggerButtonView(props.table, 'columnManagerReset', {\n label: toggleable.value\n ? t('table.reset_columns', {}, 'Reset')\n : t('table.reset_column_order', {}, 'Reset column order'),\n variant: 'ghost',\n }),\n)\nconst applyView = computed(() =>\n deferred.value\n ? triggerButtonView(props.table, 'columnManagerApply', {\n label: t('table_filters.apply', {}, 'Apply'),\n variant: 'default',\n })\n : null,\n)\nconst inHeader = computed(() => props.table.columnManagerResetActionPosition === 'header')\nconst draftChanged = computed(\n () => draft.value !== null && columnDraftChanged(props.table.visibleColumns, draft.value),\n)\n\nconst toggle = (name: string) => {\n const next = toggleVisibleColumn(visible.value, name)\n\n if (deferred.value) {\n draft.value = next\n } else {\n visitTable(props.table.identifier, { columns: next }, ['page'])\n }\n}\n\nconst dragStart = (event: DragEvent, name: string) => {\n if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'\n dragging.value = name\n}\n\nconst dragOver = (event: DragEvent, name: string) => {\n if (dragging.value === null) return\n\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n dropTarget.value = name\n}\n\nconst drop = (name: string) => {\n if (dragging.value !== null && dragging.value !== name) {\n reorder(dragging.value, moveColumnTo(names.value, dragging.value, name))\n }\n\n dragging.value = null\n dropTarget.value = null\n}\n\nconst save = async (order: string[]): Promise<boolean> => {\n const endpoint = panel.value.endpoints.tableColumns\n\n if (!endpoint) return false\n\n saving.value = true\n\n try {\n await saveColumnOrder(endpoint, props.token, props.component, order)\n\n return true\n } catch (error) {\n showToast({\n id: 'alfakit-column-order-failed',\n title: t('table.column_order_failed', {}, \"Couldn't save the column order\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n\n return false\n } finally {\n saving.value = false\n }\n}\n\nconst positionText = (name: string) => {\n const { position, count, group } = positions.value[name] ?? { position: 0, count: 0 }\n\n return group\n ? t(\n 'table.column_manager.position_in_group',\n { position, count, group },\n `Position ${position} of ${count} in ${group}.`,\n )\n : t('table.column_manager.position', { position, count }, `Position ${position} of ${count}.`)\n}\n\nconst announce = (name: string, order: string[]) => {\n const { position, count, group } = columnManagerPosition(order, name, props.table.columnGroups)\n const label = props.table.columns.find((column) => column.name === name)?.label ?? name\n const replace = { column: label, position, count, group: group ?? '' }\n\n announcement.value = group\n ? deferred.value\n ? t(\n 'table.column_manager.reordered_in_group_deferred',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered_in_group',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}.`,\n )\n : deferred.value\n ? t(\n 'table.column_manager.reordered_deferred',\n replace,\n `${label} moved to position ${position} of ${count}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered',\n replace,\n `${label} moved to position ${position} of ${count}.`,\n )\n}\n\n// A new order: kept as a draft until \"Apply\" (`deferColumnManager()`), else saved now.\nconst reorder = (name: string, order: string[]) => {\n if (saving.value || !columnOrderChanged(names.value, order)) return\n\n orderDraft.value = order\n announcement.value = ''\n\n if (deferred.value) {\n announce(name, order)\n\n return\n }\n\n void save(order).then((saved) => {\n if (saved) announce(name, order)\n else orderDraft.value = null\n })\n}\n\nconst move = (name: string, offset: -1 | 1, event: MouseEvent) => {\n keepMoveButtonFocus(event.currentTarget as HTMLElement | null)\n reorder(name, moveColumnInManager(names.value, name, offset, props.table.columnGroups))\n}\n\n// The order is saved before the visibility visit: both requests share the session, and a\n// visit running alongside the save would write the old order back when it finishes.\nconst apply = async () => {\n const order = orderDraft.value && orderChanged.value ? orderDraft.value : null\n const columns =\n draft.value && columnDraftChanged(props.table.visibleColumns, draft.value) ? draft.value : null\n\n draft.value = null\n orderDraft.value = null\n announcement.value = ''\n open.value = false\n\n if (order) await save(order)\n\n if (columns) visitTable(props.table.identifier, { columns }, ['page'])\n}\n\n// Reset: the defined column order and, for toggleable columns, the default visibility.\nconst reset = async () => {\n if (reorderable.value) {\n orderDraft.value = null\n await save([])\n }\n\n if (toggleable.value) {\n draft.value = null\n visitTable(props.table.identifier, { columns: defaultVisibleColumns(props.table) }, ['page'])\n }\n}\n\nconst setOpen = (next: boolean) => {\n // Closing without \"Apply\" drops the draft.\n if (!next) {\n draft.value = null\n if (deferred.value) orderDraft.value = null\n announcement.value = ''\n }\n open.value = next\n}\n\nconst [DefineBody, ManagerBody] = createReusableTemplate()\nconst [DefineReset, ResetButton] = createReusableTemplate()\n</script>\n\n<template>\n <template v-if=\"(toggleable || reorderable) && trigger\">\n <DefineReset>\n <TableTriggerButton\n v-if=\"resetView\"\n :view=\"resetView\"\n :disabled=\"saving\"\n data-slot=\"column-manager-reset\"\n :class=\"cn(!applyView && 'w-full')\"\n @click=\"reset\"\n />\n </DefineReset>\n <DefineBody>\n <div class=\"flex flex-col gap-1\">\n <div v-if=\"inHeader && resetView\" class=\"flex justify-end\"><ResetButton /></div>\n <ul\n :class=\"\n cn(\n props.table.columnManagerColumns\n ? ['grid gap-0.5', gridColumnsClasses(props.table.columnManagerColumns)]\n : 'flex flex-col gap-0.5',\n )\n \"\n :aria-label=\"t('table.columns', {}, 'Columns')\"\n >\n <li\n v-for=\"column in columns\"\n :key=\"column.name\"\n :data-column=\"column.name\"\n :draggable=\"reorderable && !saving\"\n :class=\"\n cn(\n 'flex items-center gap-2 rounded-md px-2 py-1 text-sm',\n reorderable && 'cursor-grab',\n dragging === column.name && 'opacity-50',\n dropTarget === column.name && dragging !== column.name && 'bg-muted',\n )\n \"\n @dragstart=\"dragStart($event, column.name)\"\n @dragover=\"dragOver($event, column.name)\"\n @dragleave=\"dropTarget === column.name && (dropTarget = null)\"\n @dragend=\"((dragging = null), (dropTarget = null))\"\n @drop.prevent=\"drop(column.name)\"\n >\n <GripVerticalIcon\n v-if=\"reorderable\"\n class=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n <label v-if=\"column.toggleable\" class=\"flex min-w-0 flex-1 items-center gap-2\">\n <Checkbox\n :model-value=\"visible.includes(column.name)\"\n @update:model-value=\"toggle(column.name)\"\n />\n <span class=\"truncate\">{{ column.label }}</span>\n </label>\n <span v-else class=\"min-w-0 flex-1 truncate\">{{ column.label }}</span>\n <span v-if=\"reorderable\" class=\"flex shrink-0 items-center\">\n <span\n :id=\"`${idBase}-${column.name}-position`\"\n class=\"sr-only\"\n data-slot=\"column-manager-position\"\n >{{ positionText(column.name) }}</span\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"(positions[column.name]?.position ?? 0) <= 1\"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_up', { column: column.label }, `Move ${column.label} up`)\n \"\n @click=\"move(column.name, -1, $event)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"\n (positions[column.name]?.position ?? 0) >= (positions[column.name]?.count ?? 0)\n \"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_down', { column: column.label }, `Move ${column.label} down`)\n \"\n @click=\"move(column.name, 1, $event)\"\n ><ChevronDownIcon\n /></Button>\n </span>\n </li>\n </ul>\n <div\n v-if=\"reorderable\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n class=\"sr-only\"\n data-slot=\"column-manager-announcement\"\n >\n {{ announcement }}\n </div>\n <div\n v-if=\"(!inHeader && resetView) || applyView\"\n class=\"mt-1 flex items-center justify-end gap-2\"\n >\n <ResetButton v-if=\"!inHeader\" />\n <TableTriggerButton\n v-if=\"applyView\"\n :view=\"applyView\"\n data-slot=\"column-manager-apply\"\n :disabled=\"!draftChanged && !orderChanged\"\n @click=\"apply\"\n />\n </div>\n </div>\n </DefineBody>\n <Sheet\n v-if=\"props.table.columnManagerLayout === 'modal' && modal?.slideOver\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <SheetTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </SheetTrigger>\n <SheetContent\n :side=\"slideOverSide(modal.slideOverPosition, direction)\"\n :class=\"cn('flex w-full flex-col gap-0 p-0', modalWidthClass ?? 'sm:max-w-md')\"\n data-slot=\"column-manager\"\n data-slide-over=\"\"\n >\n <SheetHeader class=\"border-b\">\n <SheetTitle>{{ modalHeading }}</SheetTitle>\n <SheetDescription :class=\"modal.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</SheetDescription>\n </SheetHeader>\n <div class=\"flex-1 overflow-y-auto p-4\"><ManagerBody /></div>\n </SheetContent>\n </Sheet>\n <Dialog\n v-else-if=\"props.table.columnManagerLayout === 'modal'\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <DialogTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </DialogTrigger>\n <DialogContent :class=\"modalWidthClass ?? 'sm:max-w-lg'\" data-slot=\"column-manager\">\n <DialogHeader>\n <DialogTitle>{{ modalHeading }}</DialogTitle>\n <DialogDescription :class=\"modal?.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</DialogDescription>\n </DialogHeader>\n <div class=\"max-h-[60vh] overflow-y-auto\"><ManagerBody /></div>\n </DialogContent>\n </Dialog>\n <Popover v-else :open=\"open\" @update:open=\"setOpen\">\n <PopoverTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n :class=\"cn('p-2', props.table.columnManagerColumns ? 'w-auto min-w-64' : 'w-64')\"\n data-slot=\"column-manager\"\n >\n <ManagerBody />\n </PopoverContent>\n </Popover>\n </template>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"ColumnManager.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_withCtx","_createBlock","TableTriggerButton","_normalizeClass","_createCommentVNode","_createElementVNode","_renderList","_withModifiers","Checkbox","_toDisplayString","Button","Sheet","SheetTrigger","Icon","SheetContent","SheetHeader","SheetTitle","_createTextVNode","SheetDescription","Dialog","DialogTrigger","DialogContent","DialogHeader","DialogTitle","DialogDescription","Popover","PopoverTrigger","PopoverContent","Icon_default","Button_default","Checkbox_default","Dialog_default","DialogContent_default","DialogDescription_default","DialogHeader_default","DialogTitle_default","DialogTrigger_default","Popover_default","PopoverContent_default","PopoverTrigger_default","Sheet_default","SheetContent_default","SheetDescription_default","SheetHeader_default","SheetTitle_default","SheetTrigger_default","TableTriggerButton_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","ColumnManager_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","panel","usePanel","direction","useDirection","open","ref","modal","computed","modalHeading","modalDescription","modalWidthClass","FILTERS_MODAL_WIDTH_CLASSES","saving","dragging","dropTarget","draft","reorderable","toggleable","deferred","orderDraft","announcement","idBase","useId","columns","orderColumnsBy","column","appliedNames","names","orderChanged","columnOrderChanged","positions","columnManagerPosition","visible","trigger","triggerButtonView","resetView","applyView","inHeader","draftChanged","columnDraftChanged","toggle","next","toggleVisibleColumn","name","visitTable","dragStart","event","dragOver","drop","reorder","moveColumnTo","save","endpoint","saveColumnOrder","order","options","error","showToast","positionText","group","position","count","announce","label","replace","saved","move","keepMoveButtonFocus","moveColumnInManager","offset","apply","reset","defaultVisibleColumns","setOpen","DefineBody","ManagerBody","createReusableTemplate","DefineReset","ResetButton","openBlock","createElementBlock","Fragment","createVNode","unref","withCtx","createBlock","normalizeClass","cn","createCommentVNode","createElementVNode","gridColumnsClasses","renderList","$event","_cache","withModifiers","GripVerticalIcon","toDisplayString","ChevronUpIcon","ChevronDownIcon","Columns3Icon","slideOverSide","createTextVNode"],"sources":["../../../src/components/table/ColumnManager.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { TableSchema } from '@alfakit/core'\nimport {\n columnDraftChanged,\n columnManagerPosition,\n columnOrderChanged,\n defaultVisibleColumns,\n FILTERS_MODAL_WIDTH_CLASSES,\n gridColumnsClasses,\n keepMoveButtonFocus,\n moveColumnInManager,\n moveColumnTo,\n orderColumnsBy,\n saveColumnOrder,\n slideOverSide,\n toggleVisibleColumn,\n triggerButtonView,\n visitTable,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon, Columns3Icon, GripVerticalIcon } from '@lucide/vue'\nimport { createReusableTemplate } from '@vueuse/core'\nimport { computed, ref, useId, watch } from 'vue'\nimport { useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { showToast } from '../notifications/flash-toasts'\nimport Button from '../ui/Button.vue'\nimport Checkbox from '../ui/Checkbox.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport DialogTrigger from '../ui/DialogTrigger.vue'\nimport Popover from '../ui/Popover.vue'\nimport PopoverContent from '../ui/PopoverContent.vue'\nimport PopoverTrigger from '../ui/PopoverTrigger.vue'\nimport Sheet from '../ui/Sheet.vue'\nimport SheetContent from '../ui/SheetContent.vue'\nimport SheetDescription from '../ui/SheetDescription.vue'\nimport SheetHeader from '../ui/SheetHeader.vue'\nimport SheetTitle from '../ui/SheetTitle.vue'\nimport SheetTrigger from '../ui/SheetTrigger.vue'\nimport TableTriggerButton from './TableTriggerButton.vue'\n\n/**\n * The column manager: show / hide toggleable columns (kept in the query string) and, with\n * `reorderableColumns()`, move columns (stored per user on the server) by dragging a row\n * onto another or with the move up / down buttons (the keyboard path).\n *\n * `deferColumnManager()` keeps toggles in a draft until \"Apply\"; `columnManagerLayout()`\n * opens it in a dialog; `columnManagerColumns()` lays the list out in a grid.\n */\nconst props = defineProps<{ table: TableSchema; token: string; component: string }>()\nconst t = useT()\nconst panel = usePanel()\nconst direction = useDirection()\nconst open = ref(false)\n// `columnManagerTriggerAction()` may set `slideOver()`, `modalWidth()` and the heading.\nconst modal = computed(() => props.table.triggerActions?.columnManager?.modal)\nconst modalHeading = computed(() => modal.value?.heading ?? t('table.columns', {}, 'Columns'))\nconst modalDescription = computed(() => modal.value?.description ?? props.table.pluralModelLabel)\nconst modalWidthClass = computed(() =>\n modal.value?.width ? FILTERS_MODAL_WIDTH_CLASSES[modal.value.width] : undefined,\n)\nconst saving = ref(false)\nconst dragging = ref<string | null>(null)\nconst dropTarget = ref<string | null>(null)\n// Toggles of a deferred column manager wait here until \"Apply\".\nconst draft = ref<string[] | null>(null)\nconst reorderable = computed(() =>\n Boolean(props.table.reorderableColumns && panel.value.endpoints.tableColumns),\n)\nconst toggleable = computed(() => Boolean(props.table.toggleableColumns))\nconst deferred = computed(() => Boolean(props.table.deferColumnManager))\n// A moved column order: the draft of a deferred column manager, or shown at once while\n// it is saved.\nconst orderDraft = ref<string[] | null>(null)\n// Screen-reader announcement of the last move.\nconst announcement = ref('')\nconst idBase = useId()\nconst columns = computed(() =>\n orderColumnsBy(\n reorderable.value\n ? props.table.columns\n : props.table.columns.filter((column) => column.toggleable),\n orderDraft.value,\n ),\n)\nconst appliedNames = computed(() => props.table.columns.map((column) => column.name))\nconst names = computed(() => orderDraft.value ?? appliedNames.value)\nconst orderChanged = computed(\n () => orderDraft.value !== null && columnOrderChanged(appliedNames.value, orderDraft.value),\n)\nconst positions = computed(() =>\n Object.fromEntries(\n columns.value.map((column) => [\n column.name,\n columnManagerPosition(names.value, column.name, props.table.columnGroups),\n ]),\n ),\n)\n\n// The server's order replaces the one shown while saving.\nwatch(\n () => props.table.columns,\n () => {\n if (!deferred.value) orderDraft.value = null\n },\n)\nconst visible = computed(() => draft.value ?? props.table.visibleColumns)\n\nconst trigger = computed(() =>\n triggerButtonView(props.table, 'columnManager', {\n label: t('table.columns', {}, 'Columns'),\n showLabel: false,\n }),\n)\nconst resetView = computed(() =>\n triggerButtonView(props.table, 'columnManagerReset', {\n label: toggleable.value\n ? t('table.reset_columns', {}, 'Reset')\n : t('table.reset_column_order', {}, 'Reset column order'),\n variant: 'ghost',\n }),\n)\nconst applyView = computed(() =>\n deferred.value\n ? triggerButtonView(props.table, 'columnManagerApply', {\n label: t('table_filters.apply', {}, 'Apply'),\n variant: 'default',\n })\n : null,\n)\nconst inHeader = computed(() => props.table.columnManagerResetActionPosition === 'header')\nconst draftChanged = computed(\n () => draft.value !== null && columnDraftChanged(props.table.visibleColumns, draft.value),\n)\n\nconst toggle = (name: string) => {\n const next = toggleVisibleColumn(visible.value, name)\n\n if (deferred.value) {\n draft.value = next\n } else {\n visitTable(props.table.identifier, { columns: next }, ['page'])\n }\n}\n\nconst dragStart = (event: DragEvent, name: string) => {\n if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'\n dragging.value = name\n}\n\nconst dragOver = (event: DragEvent, name: string) => {\n if (dragging.value === null) return\n\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n dropTarget.value = name\n}\n\nconst drop = (name: string) => {\n if (dragging.value !== null && dragging.value !== name) {\n reorder(dragging.value, moveColumnTo(names.value, dragging.value, name))\n }\n\n dragging.value = null\n dropTarget.value = null\n}\n\nconst save = async (order: string[], options: { reload?: boolean } = {}): Promise<boolean> => {\n const endpoint = panel.value.endpoints.tableColumns\n\n if (!endpoint) return false\n\n saving.value = true\n\n try {\n await saveColumnOrder(endpoint, props.token, props.component, order, options)\n\n return true\n } catch (error) {\n showToast({\n id: 'alfakit-column-order-failed',\n title: t('table.column_order_failed', {}, \"Couldn't save the column order\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n\n return false\n } finally {\n saving.value = false\n }\n}\n\nconst positionText = (name: string) => {\n const { position, count, group } = positions.value[name] ?? { position: 0, count: 0 }\n\n return group\n ? t(\n 'table.column_manager.position_in_group',\n { position, count, group },\n `Position ${position} of ${count} in ${group}.`,\n )\n : t('table.column_manager.position', { position, count }, `Position ${position} of ${count}.`)\n}\n\nconst announce = (name: string, order: string[]) => {\n const { position, count, group } = columnManagerPosition(order, name, props.table.columnGroups)\n const label = props.table.columns.find((column) => column.name === name)?.label ?? name\n const replace = { column: label, position, count, group: group ?? '' }\n\n announcement.value = group\n ? deferred.value\n ? t(\n 'table.column_manager.reordered_in_group_deferred',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered_in_group',\n replace,\n `${label} moved to position ${position} of ${count} in ${group}.`,\n )\n : deferred.value\n ? t(\n 'table.column_manager.reordered_deferred',\n replace,\n `${label} moved to position ${position} of ${count}. Apply columns to save your changes.`,\n )\n : t(\n 'table.column_manager.reordered',\n replace,\n `${label} moved to position ${position} of ${count}.`,\n )\n}\n\n// A new order: kept as a draft until \"Apply\" (`deferColumnManager()`), else saved now.\nconst reorder = (name: string, order: string[]) => {\n if (saving.value || !columnOrderChanged(names.value, order)) return\n\n orderDraft.value = order\n announcement.value = ''\n\n if (deferred.value) {\n announce(name, order)\n\n return\n }\n\n void save(order).then((saved) => {\n if (saved) announce(name, order)\n else orderDraft.value = null\n })\n}\n\nconst move = (name: string, offset: -1 | 1, event: MouseEvent) => {\n keepMoveButtonFocus(event.currentTarget as HTMLElement | null)\n reorder(name, moveColumnInManager(names.value, name, offset, props.table.columnGroups))\n}\n\n// The order is saved before the visibility visit: both requests share the session, and a\n// visit running alongside the save would write the old order back when it finishes.\nconst apply = async () => {\n const order = orderDraft.value && orderChanged.value ? orderDraft.value : null\n const columns =\n draft.value && columnDraftChanged(props.table.visibleColumns, draft.value) ? draft.value : null\n\n draft.value = null\n orderDraft.value = null\n announcement.value = ''\n open.value = false\n\n // The visibility visit renders the new order too: no second reload racing it.\n if (order) await save(order, { reload: !columns })\n\n if (columns) visitTable(props.table.identifier, { columns }, ['page'])\n}\n\n// Reset: the defined column order and, for toggleable columns, the default visibility.\nconst reset = async () => {\n if (reorderable.value) {\n orderDraft.value = null\n // The visibility visit below renders the defined order too.\n await save([], { reload: !toggleable.value })\n }\n\n if (toggleable.value) {\n draft.value = null\n visitTable(props.table.identifier, { columns: defaultVisibleColumns(props.table) }, ['page'])\n }\n}\n\nconst setOpen = (next: boolean) => {\n // Closing without \"Apply\" drops the draft.\n if (!next) {\n draft.value = null\n if (deferred.value) orderDraft.value = null\n announcement.value = ''\n }\n open.value = next\n}\n\nconst [DefineBody, ManagerBody] = createReusableTemplate()\nconst [DefineReset, ResetButton] = createReusableTemplate()\n</script>\n\n<template>\n <template v-if=\"(toggleable || reorderable) && trigger\">\n <DefineReset>\n <TableTriggerButton\n v-if=\"resetView\"\n :view=\"resetView\"\n :disabled=\"saving\"\n data-slot=\"column-manager-reset\"\n :class=\"cn(!applyView && 'w-full')\"\n @click=\"reset\"\n />\n </DefineReset>\n <DefineBody>\n <div class=\"flex flex-col gap-1\">\n <div v-if=\"inHeader && resetView\" class=\"flex justify-end\"><ResetButton /></div>\n <ul\n :class=\"\n cn(\n props.table.columnManagerColumns\n ? ['grid gap-0.5', gridColumnsClasses(props.table.columnManagerColumns)]\n : 'flex flex-col gap-0.5',\n )\n \"\n :aria-label=\"t('table.columns', {}, 'Columns')\"\n >\n <li\n v-for=\"column in columns\"\n :key=\"column.name\"\n :data-column=\"column.name\"\n :draggable=\"reorderable && !saving\"\n :class=\"\n cn(\n 'flex items-center gap-2 rounded-md px-2 py-1 text-sm',\n reorderable && 'cursor-grab',\n dragging === column.name && 'opacity-50',\n dropTarget === column.name && dragging !== column.name && 'bg-muted',\n )\n \"\n @dragstart=\"dragStart($event, column.name)\"\n @dragover=\"dragOver($event, column.name)\"\n @dragleave=\"dropTarget === column.name && (dropTarget = null)\"\n @dragend=\"((dragging = null), (dropTarget = null))\"\n @drop.prevent=\"drop(column.name)\"\n >\n <GripVerticalIcon\n v-if=\"reorderable\"\n class=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n <label v-if=\"column.toggleable\" class=\"flex min-w-0 flex-1 items-center gap-2\">\n <Checkbox\n :model-value=\"visible.includes(column.name)\"\n @update:model-value=\"toggle(column.name)\"\n />\n <span class=\"truncate\">{{ column.label }}</span>\n </label>\n <span v-else class=\"min-w-0 flex-1 truncate\">{{ column.label }}</span>\n <span v-if=\"reorderable\" class=\"flex shrink-0 items-center\">\n <span\n :id=\"`${idBase}-${column.name}-position`\"\n class=\"sr-only\"\n data-slot=\"column-manager-position\"\n >{{ positionText(column.name) }}</span\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"(positions[column.name]?.position ?? 0) <= 1\"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_up', { column: column.label }, `Move ${column.label} up`)\n \"\n @click=\"move(column.name, -1, $event)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :disabled=\"\n (positions[column.name]?.position ?? 0) >= (positions[column.name]?.count ?? 0)\n \"\n :aria-disabled=\"saving || undefined\"\n :aria-describedby=\"`${idBase}-${column.name}-position`\"\n :aria-label=\"\n t('table.move_column_down', { column: column.label }, `Move ${column.label} down`)\n \"\n @click=\"move(column.name, 1, $event)\"\n ><ChevronDownIcon\n /></Button>\n </span>\n </li>\n </ul>\n <div\n v-if=\"reorderable\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n class=\"sr-only\"\n data-slot=\"column-manager-announcement\"\n >\n {{ announcement }}\n </div>\n <div\n v-if=\"(!inHeader && resetView) || applyView\"\n class=\"mt-1 flex items-center justify-end gap-2\"\n >\n <ResetButton v-if=\"!inHeader\" />\n <TableTriggerButton\n v-if=\"applyView\"\n :view=\"applyView\"\n data-slot=\"column-manager-apply\"\n :disabled=\"!draftChanged && !orderChanged\"\n @click=\"apply\"\n />\n </div>\n </div>\n </DefineBody>\n <Sheet\n v-if=\"props.table.columnManagerLayout === 'modal' && modal?.slideOver\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <SheetTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </SheetTrigger>\n <SheetContent\n :side=\"slideOverSide(modal.slideOverPosition, direction)\"\n :class=\"cn('flex w-full flex-col gap-0 p-0', modalWidthClass ?? 'sm:max-w-md')\"\n data-slot=\"column-manager\"\n data-slide-over=\"\"\n >\n <SheetHeader class=\"border-b\">\n <SheetTitle>{{ modalHeading }}</SheetTitle>\n <SheetDescription :class=\"modal.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</SheetDescription>\n </SheetHeader>\n <div class=\"flex-1 overflow-y-auto p-4\"><ManagerBody /></div>\n </SheetContent>\n </Sheet>\n <Dialog\n v-else-if=\"props.table.columnManagerLayout === 'modal'\"\n :open=\"open\"\n @update:open=\"setOpen\"\n >\n <DialogTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </DialogTrigger>\n <DialogContent :class=\"modalWidthClass ?? 'sm:max-w-lg'\" data-slot=\"column-manager\">\n <DialogHeader>\n <DialogTitle>{{ modalHeading }}</DialogTitle>\n <DialogDescription :class=\"modal?.description ? undefined : 'sr-only'\">{{\n modalDescription\n }}</DialogDescription>\n </DialogHeader>\n <div class=\"max-h-[60vh] overflow-y-auto\"><ManagerBody /></div>\n </DialogContent>\n </Dialog>\n <Popover v-else :open=\"open\" @update:open=\"setOpen\">\n <PopoverTrigger as-child>\n <TableTriggerButton :view=\"trigger\">\n <template #icon\n ><Icon name=\"alfakit::tables.actions.column-manager\" :fallback=\"Columns3Icon\"\n /></template>\n </TableTriggerButton>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n :class=\"cn('p-2', props.table.columnManagerColumns ? 'w-auto min-w-64' : 'w-64')\"\n data-slot=\"column-manager\"\n >\n <ManagerBody />\n </PopoverContent>\n </Popover>\n </template>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDA,IAAMkE,IAAQC,GACRC,IAAIC,EAAK,GACTC,KAAQC,EAAS,GACjBC,KAAYC,EAAa,GACzBC,IAAOC,EAAI,EAAK,GAEhBC,IAAQC,QAAeX,EAAM,MAAM,gBAAgB,eAAe,KAAK,GACvEY,IAAeD,QAAeD,EAAM,OAAO,WAAWR,EAAE,iBAAiB,CAAC,GAAG,SAAS,CAAC,GACvFW,KAAmBF,QAAeD,EAAM,OAAO,eAAeV,EAAM,MAAM,gBAAgB,GAC1Fc,KAAkBH,QACtBD,EAAM,OAAO,QAAQK,GAA4BL,EAAM,MAAM,SAAS,KAAA,CACxE,GACMM,IAASP,EAAI,EAAK,GAClBQ,IAAWR,EAAmB,IAAI,GAClCS,IAAaT,EAAmB,IAAI,GAEpCU,IAAQV,EAAqB,IAAI,GACjCW,IAAcT,QAClB,GAAQX,EAAM,MAAM,sBAAsBI,GAAM,MAAM,UAAU,aAClE,GACMiB,IAAaV,QAAe,EAAQX,EAAM,MAAM,iBAAkB,GAClEsB,IAAWX,QAAe,EAAQX,EAAM,MAAM,kBAAmB,GAGjEuB,IAAad,EAAqB,IAAI,GAEtCe,IAAef,EAAI,EAAE,GACrBgB,IAASC,GAAM,GACfC,KAAUhB,QACdiB,GACER,EAAY,QACRpB,EAAM,MAAM,UACZA,EAAM,MAAM,QAAQ,QAAQ,MAAW6B,EAAO,UAAU,GAC5DN,EAAW,KACb,CACF,GACMO,IAAenB,QAAeX,EAAM,MAAM,QAAQ,KAAK,MAAW6B,EAAO,IAAI,CAAC,GAC9EE,IAAQpB,QAAeY,EAAW,SAASO,EAAa,KAAK,GAC7DE,IAAerB,QACbY,EAAW,UAAU,QAAQU,GAAmBH,EAAa,OAAOP,EAAW,KAAK,CAC5F,GACMW,IAAYvB,QAChB,OAAO,YACLgB,GAAQ,MAAM,KAAK,MAAW,CAC5BE,EAAO,MACPM,GAAsBJ,EAAM,OAAOF,EAAO,MAAM7B,EAAM,MAAM,YAAY,CAC1E,CAAC,CACH,CACF;EAGA,SACQA,EAAM,MAAM,eACZ;GACJ,AAAKsB,EAAS,UAAO,EAAW,QAAQ;EAC1C,CACF;EACA,IAAMc,IAAUzB,QAAeQ,EAAM,SAASnB,EAAM,MAAM,cAAc,GAElEqC,IAAU1B,QACd2B,EAAkBtC,EAAM,OAAO,iBAAiB;GAC9C,OAAOE,EAAE,iBAAiB,CAAC,GAAG,SAAS;GACvC,WAAW;EACb,CAAC,CACH,GACMqC,IAAY5B,QAChB2B,EAAkBtC,EAAM,OAAO,sBAAsB;GACnD,OAAOqB,EAAW,QACdnB,EAAE,uBAAuB,CAAC,GAAG,OAAO,IACpCA,EAAE,4BAA4B,CAAC,GAAG,oBAAoB;GAC1D,SAAS;EACX,CAAC,CACH,GACMsC,IAAY7B,QAChBW,EAAS,QACLgB,EAAkBtC,EAAM,OAAO,sBAAsB;GACnD,OAAOE,EAAE,uBAAuB,CAAC,GAAG,OAAO;GAC3C,SAAS;EACX,CAAC,IACD,IACN,GACMuC,IAAW9B,QAAeX,EAAM,MAAM,qCAAqC,QAAQ,GACnF0C,KAAe/B,QACbQ,EAAM,UAAU,QAAQwB,EAAmB3C,EAAM,MAAM,gBAAgBmB,EAAM,KAAK,CAC1F,GAEMyB,MAAU,MAAiB;GAC/B,IAAMC,IAAOC,GAAoBV,EAAQ,OAAOW,CAAI;GAEpD,AAAIzB,EAAS,QACX,EAAM,QAAQuB,IAEdG,EAAWhD,EAAM,MAAM,YAAY,EAAE,SAAS6C,EAAK,GAAG,CAAC,MAAM,CAAC;EAElE,GAEMI,MAAa,GAAkB,MAAiB;GAEpD,AADIC,EAAM,iBAAc,EAAM,aAAa,gBAAgB,SAC3D,EAAS,QAAQH;EACnB,GAEMI,MAAY,GAAkB,MAAiB;GACnD,AAAIlC,EAAS,UAAU,SAEvBiC,EAAM,eAAe,GACjBA,EAAM,iBAAc,EAAM,aAAa,aAAa,SACxD,EAAW,QAAQH;EACrB,GAEMK,MAAQ,MAAiB;GAM7B,AALInC,EAAS,UAAU,QAAQA,EAAS,UAAU8B,KAChDM,GAAQpC,EAAS,OAAOqC,GAAavB,EAAM,OAAOd,EAAS,OAAO8B,CAAI,CAAC,GAGzE,EAAS,QAAQ,MACjB,EAAW,QAAQ;EACrB,GAEMQ,IAAO,OAAO,GAAiB,IAAgC,CAAC,MAAwB;GAC5F,IAAMC,IAAWpD,GAAM,MAAM,UAAU;GAEvC,IAAI,CAACoD,GAAU,OAAO;GAEtB,EAAO,QAAQ;GAEf,IAAI;IAGF,OAFA,MAAMC,GAAgBD,GAAUxD,EAAM,OAAOA,EAAM,WAAW0D,GAAOC,CAAO,GAErE;GACT,SAASC,GAAO;IASd,OARAC,EAAU;KACR,IAAI;KACJ,OAAO3D,EAAE,6BAA6B,CAAC,GAAG,gCAAgC;KAC1E,MAAM0D,aAAiB,QAAQA,EAAM,UAAU,OAAOA,CAAK;KAC3D,QAAQ;KACR,QAAQ;IACV,CAAC,GAEM;GACT,UAAU;IACR,EAAO,QAAQ;GACjB;EACF,GAEME,MAAgB,MAAiB;GACrC,IAAM,EAAE,aAAU,UAAO,aAAU5B,EAAU,MAAMa,MAAS;IAAE,UAAU;IAAG,OAAO;GAAE;GAEpF,OAAOgB,IACH7D,EACE,0CACA;IAAE;IAAU;IAAO;GAAM,GACzB,YAAY8D,EAAS,MAAMC,EAAM,MAAMF,EAAM,EAC/C,IACA7D,EAAE,iCAAiC;IAAE;IAAU;GAAM,GAAG,YAAY8D,EAAS,MAAMC,EAAM,EAAE;EACjG,GAEMC,MAAY,GAAc,MAAoB;GAClD,IAAM,EAAE,aAAU,UAAO,aAAU/B,GAAsBuB,GAAOX,GAAM/C,EAAM,MAAM,YAAY,GACxFmE,IAAQnE,EAAM,MAAM,QAAQ,MAAM,MAAW6B,EAAO,SAASkB,CAAI,CAAC,EAAE,SAASA,GAC7EqB,IAAU;IAAE,QAAQD;IAAO;IAAU;IAAO,OAAOJ,KAAS;GAAG;GAErE,EAAa,QAAQA,IACjBzC,EAAS,QACPpB,EACE,oDACAkE,GACA,GAAGD,EAAM,qBAAqBH,EAAS,MAAMC,EAAM,MAAMF,EAAM,sCACjE,IACA7D,EACE,2CACAkE,GACA,GAAGD,EAAM,qBAAqBH,EAAS,MAAMC,EAAM,MAAMF,EAAM,EACjE,IACFzC,EAAS,QACPpB,EACE,2CACAkE,GACA,GAAGD,EAAM,qBAAqBH,EAAS,MAAMC,EAAM,sCACrD,IACA/D,EACE,kCACAkE,GACA,GAAGD,EAAM,qBAAqBH,EAAS,MAAMC,EAAM,EACrD;EACR,GAGMZ,MAAW,GAAc,MAAoB;GACjD,IAAI,GAAO,SAAUpB,GAAmBF,EAAM,OAAO2B,CAAK,GAK1D;QAHA,EAAW,QAAQA,GACnB,EAAa,QAAQ,IAEjBpC,EAAS,OAAO;KAClB,GAASyB,GAAMW,CAAK;KAEpB;IACF;IAEA,EAAUA,CAAK,CAAC,CAAC,MAAM,MAAU;KAC/B,AAAIW,IAAOH,GAASnB,GAAMW,CAAK,IAC1B,EAAW,QAAQ;IAC1B,CAAC;GALD;EAMF,GAEMY,MAAQ,GAAc,GAAgB,MAAsB;GAEhE,AADAC,GAAoBrB,EAAM,aAAmC,GAC7DG,GAAQN,GAAMyB,GAAoBzC,EAAM,OAAOgB,GAAM0B,GAAQzE,EAAM,MAAM,YAAY,CAAC;EACxF,GAIM0E,KAAQ,YAAY;GACxB,IAAMhB,IAAQnC,EAAW,SAASS,EAAa,QAAQT,EAAW,QAAQ,MACpEI,IACJR,EAAM,SAASwB,EAAmB3C,EAAM,MAAM,gBAAgBmB,EAAM,KAAK,IAAIA,EAAM,QAAQ;GAU7F,AARA,EAAM,QAAQ,MACd,EAAW,QAAQ,MACnB,EAAa,QAAQ,IACrB,EAAK,QAAQ,IAGTuC,KAAO,MAAMH,EAAKG,GAAO,EAAE,QAAQ,CAAC/B,EAAQ,CAAC,GAE7CA,KAASqB,EAAWhD,EAAM,MAAM,YAAY,EAAE,WAAQ,GAAG,CAAC,MAAM,CAAC;EACvE,GAGM2E,KAAQ,YAAY;GAOxB,AANIvD,EAAY,UACd,EAAW,QAAQ,MAEnB,MAAMmC,EAAK,CAAC,GAAG,EAAE,QAAQ,CAAClC,EAAW,MAAM,CAAC,IAG1CA,EAAW,UACb,EAAM,QAAQ,MACd2B,EAAWhD,EAAM,MAAM,YAAY,EAAE,SAAS4E,GAAsB5E,EAAM,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC;EAEhG,GAEM6E,KAAW,MAAkB;GAOjC,AALKhC,MACH,EAAM,QAAQ,MACVvB,EAAS,UAAO,EAAW,QAAQ,OACvC,EAAa,QAAQ,KAEvB,EAAK,QAAQuB;EACf,GAEM,CAACiC,IAAYC,KAAeC,EAAuB,GACnD,CAACC,IAAaC,MAAeF,EAAuB;oBAIvC3D,EAAA,SAAcD,EAAA,UAAgBiB,EAAA,SAA/CvG,EAAA,GAAAC,EAwLWC,IAAA,EAAA,KAAA,EAAA,GAAA;GAvLTC,EAScC,EAAA+I,EAAA,GAAA,MAAA;IARZ,SAAA9I,QAOE,CANMoG,EAAA,SADRzG,EAAA,GAAAM,EAOEC,GAAA;;KALC,MAAMkG,EAAA;KACN,UAAUvB,EAAA;KACX,aAAU;KACT,OAAK1E,EAAEJ,EAAAyJ,CAAA,CAAE,CAAA,CAAEnD,EAAA,SAAS,QAAA,CAAA;KACpB,SAAOmC;;;;;;;;GAGZ1I,EA2GaC,EAAA4I,EAAA,GAAA,MAAA;IA1GX,SAAA3I,QAyGM,CAzGNK,EAyGM,OAzGN0C,IAyGM;KAxGOuD,EAAA,SAAYF,EAAA,SAAvBzG,EAAA,GAAAC,EAAgF,OAAhFoD,IAAgF,CAArBlD,EAAeC,EAAAgJ,EAAA,CAAA,CAAA,CAAA,KAAAU,EAAA,IAAA,EAAA;KAC1EpJ,EA+EK,MAAA;MA9EF,OAAKF,EAAeJ,EAAAyJ,CAAA,CAAE,CAAgB3F,EAAM,MAAM,uBAAwD,CAAA,gBAAA9D,EAAA4J,EAAA,CAAkB,CAAC9F,EAAM,MAAM,oBAAoB,CAAA,IAAA,uBAAA,CAAA;MAO7J,cAAY9D,EAAAgE,CAAA,CAAC,CAAA,iBAAA,CAAA,GAAA,SAAA;KAEdpE,GAAAA,EAAAA,EAAA,EAAA,GAAAC,EAoEKC,IAAA,MAAAS,GAnEckF,GAAA,QAAV,OADT7F,EAAA,GAAAC,EAoEK,MAAA;MAlEF,KAAK8F,EAAO;MACZ,eAAaA,EAAO;MACpB,WAAWT,EAAA,SAAW,CAAKJ,EAAA;MAC3B,OAAK1E,EAAiBJ,EAAAyJ,CAAA,CAAE,CAAA,wDAA0FvE,EAAA,SAAW,eAAmCH,EAAA,UAAaY,EAAO,QAAI,cAAkCX,EAAA,UAAeW,EAAO,QAAQZ,EAAA,UAAaY,EAAO,QAAI,UAAA,CAAA;MAQhR,cAAS,MAAEoB,GAAU+C,GAAQnE,EAAO,IAAI;MACxC,aAAQ,MAAEsB,GAAS6C,GAAQnE,EAAO,IAAI;MACtC,cAAS,MAAEX,EAAA,UAAeW,EAAO,SAAS,EAAA,QAAU;MACpD,WAAO,AAAAoE,EAAA,QAAA,OAAI,EAAA,QAAQ,MAAW,EAAA,QAAU;MACxC,QAAIvJ,IAAA,MAAU0G,GAAKvB,EAAO,IAAI,GAAA,CAAA,SAAA,CAAA;;MAGvBT,EAAA,SADRtF,EAAA,GAAAM,EAIEF,EAAAiK,EAAA,GAAA;;OAFA,OAAM;OACN,eAAY;;MAEDtE,EAAO,cAApB/F,EAAA,GAAAC,EAMQ,SANRuD,IAMQ,CALNrD,EAGEU,IAAA;OAFC,eAAayF,EAAA,MAAQ,SAASP,EAAO,IAAI;OACzC,wBAAkB,MAAEe,GAAOf,EAAO,IAAI;MAEzCrF,GAAAA,MAAAA,GAAAA,CAAAA,eAAAA,qBAAAA,CAAAA,GAAAA,EAAgD,QAAhD+C,IAAgD3C,EAAtBiF,EAAO,KAAK,GAAA,CAAA,CAAA,CAAA,MAExC/F,EAAA,GAAAC,EAAsE,QAAtEyD,IAAsE5C,EAAtBiF,EAAO,KAAK,GAAA,CAAA;MAChDT,EAAA,SAAZtF,EAAA,GAAAC,EAmCO,QAnCP0D,IAmCO;OAlCLjD,EAKC,QAAA;QAJE,IAAE,GAAKN,EAAAuF,CAAA,EAAM,GAAII,EAAO,KAAI;QAC7B,OAAM;QACN,aAAU;OACN,GAAAjF,EAAAkH,GAAajC,EAAO,IAAI,CAAA,GAAA,GAAAnC,EAAA;OAE9BzD,EAYWY,GAAA;QAXT,MAAK;QACL,SAAQ;QACR,MAAK;QACJ,WAAWqF,EAAA,MAAUL,EAAO,KAAI,EAAG,YAAQ,MAAA;QAC3C,iBAAeb,EAAA,SAAU,KAAA;QACzB,oBAAgB,GAAK9E,EAAAuF,CAAA,EAAM,GAAII,EAAO,KAAI;QAC1C,cAA+B3F,EAAAgE,CAAA,CAAC,CAAA,wBAAA,EAAA,QAAmC2B,EAAO,MAAK,GAAA,QAAYA,EAAO,MAAK,IAAA;QAGvG,UAAK,MAAEyC,GAAKzC,EAAO,MAAI,IAAMmE,CAAM;;QACnC,SAAA7J,QACD,CADCF,EACDC,EAAAmK,EAAA,CAAA,CAAA,CAAA;;;;;;;;;OACFpK,EAcWY,GAAA;QAbT,MAAK;QACL,SAAQ;QACR,MAAK;QACJ,WAA8BqF,EAAA,MAAUL,EAAO,KAAI,EAAG,YAAQ,OAAWK,EAAA,MAAUL,EAAO,KAAI,EAAG,SAAK;QAGtG,iBAAeb,EAAA,SAAU,KAAA;QACzB,oBAAgB,GAAK9E,EAAAuF,CAAA,EAAM,GAAII,EAAO,KAAI;QAC1C,cAA+B3F,EAAAgE,CAAA,CAAC,CAAA,0BAAA,EAAA,QAAqC2B,EAAO,MAAK,GAAA,QAAYA,EAAO,MAAK,MAAA;QAGzG,UAAK,MAAEyC,GAAKzC,EAAO,MAAI,GAAKmE,CAAM;;QAClC,SAAA7J,QACD,CADCF,EACDC,EAAAoK,EAAA,CAAA,CAAA,CAAA;;;;;;;;;;;KAKAlF,EAAA,SADRtF,EAAA,GAAAC,EASM,OATN4D,IASM/C,EADD4E,EAAA,KAAY,GAAA,CAAA,KAAAoE,EAAA,IAAA,EAAA;KAGP,CAAAnD,EAAA,SAAYF,EAAA,SAAcC,EAAA,SADpC1G,EAAA,GAAAC,EAYM,OAZN6D,IAYM,CARgB6C,EAAA,QAAYmD,EAAA,IAAA,EAAA,KAAhC9J,EAAA,GAAAM,EAAgCF,EAAAgJ,EAAA,GAAA,EAAA,KAAA,EAAA,CAAA,IAExB1C,EAAA,SADR1G,EAAA,GAAAM,EAMEC,GAAA;;MAJC,MAAMmG,EAAA;MACP,aAAU;MACT,UAAQ,CAAGE,GAAA,SAAY,CAAKV,EAAA;MAC5B,SAAO0C;;;;;GAMR1E,EAAM,MAAM,wBAAmB,WAAgBU,EAAA,OAAO,aAD9D5E,EAAA,GAAAM,EA0BQU,IAAA;;IAxBL,MAAM0D,EAAA;IACN,iBAAaqE;;IAEd,SAAA1I,QAMe,CANfF,EAMec,IAAA,EAND,YAAA,GAAQ,GAAA;KACpB,SAAAZ,QAIqB,CAJrBF,EAIqBI,GAAA,EAJA,MAAMgG,EAAA,MAAO,GAAA;MACrB,MAAIlG,QAEb,CADCF,EACDC,EAAAc,CAAA,GAAA;OADO,MAAK;OAA0C,UAAUd,EAAAqK,CAAA;;;;;IAItEtK,CAAAA,GAAAA,EAaegB,IAAA;KAZZ,MAAMf,EAAAsK,EAAA,CAAa,CAAC9F,EAAA,MAAM,mBAAmBxE,EAAAoE,EAAA,CAAS;KACtD,OAAKhE,EAAEJ,EAAAyJ,CAAA,CAAE,CAAA,kCAAmC7E,GAAA,SAAe,aAAA,CAAA;KAC5D,aAAU;KACV,mBAAgB;;KAEhB,SAAA3E,QAKc,CALdF,EAKciB,IAAA,EALD,OAAM,WAAU,GAAA;MAC3B,SAAAf,QAA2C,CAA3CF,EAA2CkB,IAAA,MAAA;OAA/B,SAAAhB,QAAkB,CAAfiB,EAAAR,EAAAgE,EAAA,KAAY,GAAA,CAAA,CAAA,CAAA;;MAC3B3E,CAAAA,GAAAA,EAEqBoB,IAAA,EAFF,OAAKf,EAAEoE,EAAA,MAAM,cAAc,KAAA,IAAS,SAAA,EAAA,GAAA;OAAc,SAAAvE,QAEnE,CADAiB,EAAAR,EAAAiE,GAAA,KAAgB,GAAA,CAAA,CAAA,CAAA;;;;KAGpBrE,CAAAA,GAAAA,EAA6D,OAA7DqD,IAA6D,CAArB5D,EAAeC,EAAA6I,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;GAI9C,GAAA,GAAA,CAAA,MAAA,CAAA,KAAA/E,EAAM,MAAM,wBAAmB,WAD5ClE,EAAA,GAAAM,EAqBSkB,IAAA;;IAnBN,MAAMkD,EAAA;IACN,iBAAaqE;;IAEd,SAAA1I,QAMgB,CANhBF,EAMgBsB,IAAA,EAND,YAAA,GAAQ,GAAA;KACrB,SAAApB,QAIqB,CAJrBF,EAIqBI,GAAA,EAJA,MAAMgG,EAAA,MAAO,GAAA;MACrB,MAAIlG,QAEb,CADCF,EACDC,EAAAc,CAAA,GAAA;OADO,MAAK;OAA0C,UAAUd,EAAAqK,CAAA;;;;;IAItEtK,CAAAA,GAAAA,EAQgBuB,IAAA;KARA,OAAKlB,EAAEwE,GAAA,SAAe,aAAA;KAAmB,aAAU;;KACjE,SAAA3E,QAKe,CALfF,EAKewB,IAAA,MAAA;MAJb,SAAAtB,QAA6C,CAA7CF,EAA6CyB,IAAA,MAAA;OAAhC,SAAAvB,QAAkB,CAAfiB,EAAAR,EAAAgE,EAAA,KAAY,GAAA,CAAA,CAAA,CAAA;;MAC5B3E,CAAAA,GAAAA,EAEsB0B,IAAA,EAFF,OAAKrB,EAAEoE,EAAA,OAAO,cAAc,KAAA,IAAS,SAAA,EAAA,GAAA;OAAc,SAAAvE,QAErE,CADAiB,EAAAR,EAAAiE,GAAA,KAAgB,GAAA,CAAA,CAAA,CAAA;;;;KAGpBrE,CAAAA,GAAAA,EAA+D,OAA/DsD,IAA+D,CAArB7D,EAAeC,EAAA6I,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;GAG7DjJ,GAAAA,GAAAA,CAAAA,MAAAA,CAAAA,MAAAA,EAAA,GAAAM,EAeUwB,IAAA;;IAfO,MAAM4C,EAAA;IAAO,iBAAaqE;;IACzC,SAAA1I,QAMiB,CANjBF,EAMiB4B,IAAA,EAND,YAAA,GAAQ,GAAA;KACtB,SAAA1B,QAIqB,CAJrBF,EAIqBI,GAAA,EAJA,MAAMgG,EAAA,MAAO,GAAA;MACrB,MAAIlG,QAEb,CADCF,EACDC,EAAAc,CAAA,GAAA;OADO,MAAK;OAA0C,UAAUd,EAAAqK,CAAA;;;;;IAItEtK,CAAAA,GAAAA,EAMiB6B,IAAA;KALf,OAAM;KACL,OAAKxB,EAAEJ,EAAAyJ,CAAA,CAAE,CAAA,OAAQ3F,EAAM,MAAM,uBAAoB,oBAAA,MAAA,CAAA;KAClD,aAAU;;KAEV,SAAA7D,QAAe,CAAfF,EAAeC,EAAA6I,CAAA,CAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Spreadsheet.js","names":["_sfc_main","Spreadsheet_vue_vue_type_script_setup_true_lang_default","Spreadsheet_default"],"sources":["../../../src/components/table/Spreadsheet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type {\n PastePlan,\n SpreadsheetAnnouncement,\n SpreadsheetSaveResult,\n TableSchema,\n} from '@alfakit/core'\nimport {\n SPREADSHEET_CLASSES,\n SPREADSHEET_ISSUE_MESSAGES,\n SpreadsheetGrid,\n VIRTUAL_ESTIMATES,\n inertiaReload,\n saveSpreadsheetChanges,\n spreadsheetAnnouncement,\n spreadsheetAria,\n spreadsheetCellClass,\n spreadsheetCellId,\n spreadsheetColumns,\n spreadsheetRows,\n spreadsheetSelectionSize,\n virtualizeOptions,\n} from '@alfakit/core'\nimport { CheckIcon } from '@lucide/vue'\nimport { computed, nextTick, ref, useId, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useVirtualList } from '../../composables/use-virtual-list'\nimport { useChoice, useDirection, usePanel, useT } from '../../context'\nimport { showToast } from '../notifications/flash-toasts'\nimport VirtualSpacerRow from '../schema/VirtualSpacerRow.vue'\nimport Button from '../ui/Button.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogFooter from '../ui/DialogFooter.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport Spinner from '../ui/Spinner.vue'\n\n/**\n * Spreadsheet mode of a `Table::spreadsheet()` table (loaded on first use): a keyboard\n * grid over the page's records. Edits stay local (highlighted) until \"Save\" sends them in\n * one request; the server validates each cell with its column's rules and the record's\n * `update` policy, and its errors show on the cells.\n */\nconst props = defineProps<{ table: TableSchema; token: string; component: string }>()\nconst emit = defineEmits<{ close: [] }>()\n\ninterface PastePreview {\n plan: PastePlan\n errors: SpreadsheetSaveResult['errors']\n validating: boolean\n}\n\nconst t = useT()\nconst choice = useChoice()\nconst direction = useDirection()\nconst panel = usePanel()\nconst baseId = `spreadsheet-${useId()}`\nconst columns = computed(() => spreadsheetColumns(props.table))\nconst rows = computed(() => spreadsheetRows(props.table.records ?? [], columns.value))\nconst grid = new SpreadsheetGrid(rows.value, columns.value)\nconst state = useStore(grid.store)\nconst announcement = ref('')\nconst preview = ref<PastePreview | null>(null)\nconst gridElement = ref<HTMLTableElement | null>(null)\nconst helpId = `${baseId}-help`\n\n// A reload (save, live update, polling) brings new records; edits of rows still on the\n// page are kept.\nwatch([rows, columns], ([nextRows, nextColumns]) => grid.setData(nextRows, nextColumns))\n\nconst virtual = useVirtualList(\n () => rows.value.length,\n () => virtualizeOptions(props.table.virtualize, VIRTUAL_ESTIMATES.row),\n)\n\nconst endpoint = computed(() => panel.value.endpoints.tableCells)\nconst errorList = computed(() => {\n void state.value\n\n return grid.errorCells()\n})\n\nfunction announce(message: SpreadsheetAnnouncement | null) {\n if (message) announcement.value = choice(message.key, message.count, {}, message.fallback)\n}\n\nfunction focusCell(row: number, col: number) {\n void nextTick(() => {\n const cell = document.getElementById(spreadsheetCellId(baseId, row, col))\n\n if (cell) {\n cell.focus()\n cell.scrollIntoView?.({ block: 'nearest', inline: 'nearest' })\n } else {\n virtual.list.scrollToIndex(row)\n }\n })\n}\n\n// Keep focus on the active cell (roving tabindex).\nwatch(\n () => [state.value.active, state.value.editing] as const,\n ([active, editing]) => {\n if (editing || !gridElement.value?.contains(document.activeElement)) return\n\n focusCell(active.row, active.col)\n },\n)\n\nasync function save() {\n const changes = grid.changes()\n\n if (!endpoint.value || changes.length === 0 || state.value.saving) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(\n endpoint.value,\n props.token,\n props.component,\n changes,\n )\n\n grid.applySaveResult(result)\n\n if (result.saved.length > 0) {\n announce(spreadsheetAnnouncement('saved', result.saved.length))\n inertiaReload()\n }\n\n if (result.errors.length > 0) announce(spreadsheetAnnouncement('failed', result.errors.length))\n } catch (error) {\n showToast({\n id: 'alfakit-spreadsheet-failed',\n title: t('table.spreadsheet.request_failed', {}, \"Couldn't save the changes\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n } finally {\n grid.setSaving(false)\n }\n}\n\nasync function undoSave() {\n const changes = grid.undoSaveChanges()\n\n if (!endpoint.value || changes.length === 0) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(\n endpoint.value,\n props.token,\n props.component,\n changes,\n )\n\n grid.applySaveResult(result)\n announce(spreadsheetAnnouncement('undo', result.saved.length))\n\n if (result.saved.length > 0) inertiaReload()\n } finally {\n grid.setSaving(false)\n }\n}\n\nfunction close() {\n if (\n grid.dirtyCount > 0 &&\n !window.confirm(t('table.spreadsheet.discard_confirm', {}, 'Discard your unsaved changes?'))\n ) {\n return\n }\n\n grid.discard()\n emit('close')\n}\n\nfunction onKeyDown(event: KeyboardEvent) {\n const result = grid.handleKey(event, direction.value)\n\n if (result === 'ignored') return\n\n event.preventDefault()\n\n if (result === 'save') {\n void save()\n } else if (result === 'undo') {\n announce(spreadsheetAnnouncement('undo', grid.undo()))\n } else if (result === 'fill' || result === 'clear') {\n announce(spreadsheetAnnouncement(result, grid.lastApplied))\n }\n\n if (result === 'commit' || result === 'cancel' || result === 'toggle') {\n focusCell(grid.state.active.row, grid.state.active.col)\n }\n}\n\nfunction onCopy(event: ClipboardEvent) {\n if (grid.state.editing || !event.clipboardData) return\n\n event.preventDefault()\n event.clipboardData.setData('text/plain', grid.copyText())\n announce(spreadsheetAnnouncement('copy', spreadsheetSelectionSize(grid.bounds())))\n}\n\nfunction onPaste(event: ClipboardEvent) {\n if (grid.state.editing || !event.clipboardData) return\n\n event.preventDefault()\n\n const plan = grid.planPaste(event.clipboardData.getData('text/plain'))\n\n if (plan.changes.length === 0 && plan.issues.length === 0) return\n\n const url = endpoint.value\n\n preview.value = { plan, errors: [], validating: Boolean(url && plan.changes.length > 0) }\n\n if (!url || plan.changes.length === 0) return\n\n // Validate the pasted values on the server before they are applied.\n saveSpreadsheetChanges(\n url,\n props.token,\n props.component,\n plan.changes.map((change) => ({\n record: grid.getRows()[change.row]?.key ?? '',\n column: grid.getColumns()[change.col]?.name ?? '',\n state: change.value,\n })),\n { dryRun: true },\n )\n .then((result) => {\n if (preview.value)\n preview.value = { ...preview.value, errors: result.errors, validating: false }\n })\n .catch(() => {\n if (preview.value) preview.value = { ...preview.value, validating: false }\n })\n}\n\nfunction applyPaste() {\n const current = preview.value\n\n if (!current) return\n\n const count = grid.apply(current.plan.changes)\n\n if (current.errors.length > 0) grid.setErrors(current.errors)\n\n announce(spreadsheetAnnouncement('paste', count))\n preview.value = null\n}\n\nfunction issueText(issue: PastePlan['issues'][number]): string {\n const message = SPREADSHEET_ISSUE_MESSAGES[issue.reason]\n\n return t(\n message.key,\n { text: issue.text, column: columns.value[issue.col]?.label ?? '', row: issue.row + 1 },\n message.fallback,\n )\n}\n\nfunction errorText(record: SpreadsheetSaveResult['errors'][number]): string {\n const position = grid.position(record.record, record.column)\n\n return t(\n 'table.spreadsheet.cell_error',\n {\n row: (position?.row ?? -1) + 1,\n column: columns.value.find((column) => column.name === record.column)?.label ?? record.column,\n message: record.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )\n}\n\nfunction draft(): string {\n const value = state.value.editing?.value\n\n return value === null || value === undefined ? '' : String(value)\n}\n\nfunction isEditing(row: number, col: number): boolean {\n return state.value.editing?.row === row && state.value.editing.col === col\n}\n\nfunction onSelectChange(event: Event, row: number, col: number) {\n grid.updateDraft((event.target as HTMLSelectElement).value)\n grid.commitEdit()\n focusCell(row, col)\n}\n\nconst optionText = (label: string) => label.replace(/<[^>]*>/g, '')\n\n/** Focus an editor as soon as it is shown. */\nconst vFocus = { mounted: (element: HTMLElement) => element.focus() }\n</script>\n\n<template>\n <div data-slot=\"spreadsheet\" class=\"flex flex-col gap-3\">\n <div data-slot=\"spreadsheet-toolbar\" class=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n :disabled=\"grid.dirtyCount === 0 || state.saving\"\n @click=\"save\"\n >\n <Spinner v-if=\"state.saving\" />\n {{ t('table.spreadsheet.save', {}, 'Save changes') }}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n :disabled=\"!grid.canUndo || state.saving\"\n @click=\"announce(spreadsheetAnnouncement('undo', grid.undo()))\"\n >\n {{ t('table.spreadsheet.undo', {}, 'Undo') }}\n </Button>\n <Button\n v-if=\"grid.canUndoSave\"\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n :disabled=\"state.saving\"\n @click=\"undoSave\"\n >\n {{ t('table.spreadsheet.undo_save', {}, 'Undo last save') }}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n :disabled=\"grid.dirtyCount === 0 || state.saving\"\n @click=\"grid.discard()\"\n >\n {{ t('table.spreadsheet.discard', {}, 'Discard') }}\n </Button>\n <span class=\"text-muted-foreground text-sm\" aria-live=\"polite\">\n <template v-if=\"grid.dirtyCount > 0\">{{\n choice(\n 'table.spreadsheet.unsaved',\n grid.dirtyCount,\n {},\n ':count unsaved change|:count unsaved changes',\n )\n }}</template>\n <span v-if=\"grid.errorCount > 0\" class=\"text-destructive ms-2\">{{\n choice('table.spreadsheet.errors', grid.errorCount, {}, ':count error|:count errors')\n }}</span>\n </span>\n <span class=\"flex-1\" />\n <Button type=\"button\" size=\"sm\" variant=\"outline\" @click=\"close\">\n {{ t('table.spreadsheet.close', {}, 'Done') }}\n </Button>\n </div>\n <p :id=\"helpId\" class=\"sr-only\">\n {{\n t(\n 'table.spreadsheet.help',\n {},\n 'Arrow keys move between cells. Enter or F2 edits a cell, Escape cancels, Tab moves to the next cell. Ctrl+C copies, Ctrl+V pastes, Ctrl+D fills down, Ctrl+Z undoes and Ctrl+S saves.',\n )\n }}\n </p>\n <div data-surface=\"table\" :class=\"SPREADSHEET_CLASSES.root\" style=\"max-height: 70vh\">\n <table\n ref=\"gridElement\"\n role=\"grid\"\n :aria-label=\"props.table.heading ?? t('table.spreadsheet.label', {}, 'Spreadsheet')\"\n :aria-describedby=\"helpId\"\n :aria-rowcount=\"rows.length + 1\"\n :aria-colcount=\"columns.length\"\n aria-multiselectable=\"true\"\n :aria-busy=\"state.saving || undefined\"\n data-slot=\"spreadsheet-grid\"\n :class=\"SPREADSHEET_CLASSES.table\"\n @keydown=\"onKeyDown\"\n @copy=\"onCopy\"\n @paste=\"onPaste\"\n >\n <thead>\n <tr aria-rowindex=\"1\">\n <th\n v-for=\"(column, col) in columns\"\n :key=\"column.name\"\n role=\"columnheader\"\n scope=\"col\"\n :aria-colindex=\"col + 1\"\n :class=\"SPREADSHEET_CLASSES.header\"\n >\n {{ column.label }}\n </th>\n </tr>\n </thead>\n <tbody :ref=\"virtual.attach\">\n <VirtualSpacerRow :height=\"virtual.range.value.before\" :col-span=\"columns.length\" />\n <template v-for=\"row in virtual.indexes.value\" :key=\"String(rows[row]?.key ?? row)\">\n <tr v-if=\"rows[row]\" :ref=\"virtual.item\" :data-index=\"row\" :aria-rowindex=\"row + 2\">\n <td\n v-for=\"(column, col) in columns\"\n :id=\"spreadsheetCellId(baseId, row, col)\"\n :key=\"column.name\"\n role=\"gridcell\"\n v-bind=\"spreadsheetAria(row, col)\"\n :tabindex=\"grid.isActive(row, col) ? 0 : -1\"\n :aria-selected=\"grid.isSelected(row, col)\"\n :aria-readonly=\"!grid.isEditable(row, col) || undefined\"\n :aria-invalid=\"grid.errorsAt(row, col).length > 0 || undefined\"\n :title=\"grid.errorsAt(row, col).join(' ') || undefined\"\n data-slot=\"spreadsheet-cell\"\n :data-dirty=\"grid.isDirty(row, col) || undefined\"\n :data-active=\"grid.isActive(row, col) || undefined\"\n :class=\"spreadsheetCellClass(grid, row, col)\"\n @mousedown=\"!isEditing(row, col) && grid.moveTo(row, col, $event.shiftKey)\"\n @dblclick=\"grid.beginEdit()\"\n >\n <select\n v-if=\"isEditing(row, col) && column.kind === 'select'\"\n v-focus\n :class=\"SPREADSHEET_CLASSES.editor\"\n :aria-label=\"column.label\"\n :value=\"draft()\"\n @change=\"onSelectChange($event, row, col)\"\n @blur=\"grid.cancelEdit()\"\n >\n <option value=\"\">{{ t('table.spreadsheet.no_value', {}, '—') }}</option>\n <option\n v-for=\"option in column.options\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ optionText(option.label) }}\n </option>\n </select>\n <input\n v-else-if=\"isEditing(row, col)\"\n v-focus\n :type=\"column.kind === 'number' ? 'text' : (column.inputType ?? 'text')\"\n :inputmode=\"column.kind === 'number' ? 'decimal' : undefined\"\n :class=\"SPREADSHEET_CLASSES.editor\"\n :aria-label=\"column.label\"\n :value=\"draft()\"\n @input=\"grid.updateDraft(($event.target as HTMLInputElement).value)\"\n @blur=\"grid.commitEdit()\"\n />\n <span v-else-if=\"column.kind === 'boolean'\" class=\"inline-flex items-center gap-1\">\n <span\n aria-hidden=\"true\"\n class=\"border-input data-[checked=true]:bg-primary data-[checked=true]:text-primary-foreground inline-flex size-4 items-center justify-center rounded-[4px] border\"\n :data-checked=\"Boolean(grid.value(row, col))\"\n >\n <CheckIcon v-if=\"grid.value(row, col)\" class=\"size-3\" />\n </span>\n <span class=\"sr-only\">{{\n grid.value(row, col)\n ? t('table.spreadsheet.yes', {}, 'Yes')\n : t('table.spreadsheet.no', {}, 'No')\n }}</span>\n </span>\n <template v-else>{{ grid.text(row, col) }}</template>\n <span v-if=\"grid.errorsAt(row, col).length > 0\" class=\"sr-only\">{{\n grid.errorsAt(row, col).join(' ')\n }}</span>\n </td>\n </tr>\n </template>\n <VirtualSpacerRow :height=\"virtual.range.value.after\" :col-span=\"columns.length\" />\n </tbody>\n </table>\n <p v-if=\"rows.length === 0\" class=\"text-muted-foreground p-6 text-center text-sm\">\n {{ t('table.spreadsheet.empty', {}, 'No records to edit.') }}\n </p>\n </div>\n <ul\n v-if=\"errorList.length > 0\"\n data-slot=\"spreadsheet-errors\"\n class=\"text-destructive flex flex-col gap-1 text-sm\"\n >\n <li v-for=\"error in errorList\" :key=\"error.key\">\n <button\n type=\"button\"\n class=\"text-start hover:underline\"\n @click=\"\n () => {\n grid.moveTo(error.row, error.col)\n focusCell(error.row, error.col)\n }\n \"\n >\n {{\n t(\n 'table.spreadsheet.cell_error',\n {\n row: error.row + 1,\n column: columns[error.col]?.label ?? '',\n message: error.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )\n }}\n </button>\n </li>\n </ul>\n <span\n aria-live=\"polite\"\n aria-atomic=\"true\"\n class=\"sr-only\"\n data-slot=\"spreadsheet-announcement\"\n >{{ announcement }}</span\n >\n\n <Dialog :open=\"preview !== null\" @update:open=\"(value) => !value && (preview = null)\">\n <DialogContent class=\"sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>{{ t('table.spreadsheet.paste_title', {}, 'Paste cells') }}</DialogTitle>\n <DialogDescription>\n {{\n choice(\n 'table.spreadsheet.paste_summary',\n preview?.plan.changes.length ?? 0,\n {},\n ':count cell will change|:count cells will change',\n )\n }}\n <template v-if=\"(preview?.plan.skipped ?? 0) > 0\">\n {{\n choice(\n 'table.spreadsheet.paste_skipped',\n preview?.plan.skipped ?? 0,\n {},\n ':count read-only cell is skipped|:count read-only cells are skipped',\n )\n }}\n </template>\n </DialogDescription>\n </DialogHeader>\n <div data-slot=\"spreadsheet-paste\" class=\"flex flex-col gap-3\">\n <p\n v-if=\"preview?.validating\"\n class=\"text-muted-foreground flex items-center gap-2 text-sm\"\n >\n <Spinner />\n {{ t('table.spreadsheet.paste_validating', {}, 'Checking the values…') }}\n </p>\n <ul\n v-if=\"preview && (preview.plan.issues.length > 0 || preview.errors.length > 0)\"\n class=\"text-destructive flex max-h-48 flex-col gap-1 overflow-auto text-sm\"\n >\n <li v-for=\"issue in preview.plan.issues\" :key=\"`issue-${issue.row}-${issue.col}`\">\n {{ issueText(issue) }}\n </li>\n <li\n v-for=\"error in preview.errors\"\n :key=\"`error-${String(error.record)}-${error.column}`\"\n >\n {{ errorText(error) }}\n </li>\n </ul>\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" @click=\"preview = null\">{{\n t('cancel', {}, 'Cancel')\n }}</Button>\n <Button\n type=\"button\"\n :disabled=\"!preview || preview.plan.changes.length === 0\"\n @click=\"applyPaste\"\n >\n {{ t('table.spreadsheet.paste_apply', {}, 'Apply') }}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"Spreadsheet.js","names":["_sfc_main","Spreadsheet_vue_vue_type_script_setup_true_lang_default","Spreadsheet_default"],"sources":["../../../src/components/table/Spreadsheet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type {\n PastePlan,\n SpreadsheetAnnouncement,\n SpreadsheetSaveResult,\n TableSchema,\n} from '@alfakit/core'\nimport {\n SPREADSHEET_CLASSES,\n SPREADSHEET_ISSUE_MESSAGES,\n SpreadsheetGrid,\n VIRTUAL_ESTIMATES,\n inertiaReload,\n saveSpreadsheetChanges,\n spreadsheetAnnouncement,\n spreadsheetAria,\n spreadsheetCellClass,\n spreadsheetCellId,\n spreadsheetColumns,\n spreadsheetRows,\n spreadsheetSelectionSize,\n virtualizeOptions,\n} from '@alfakit/core'\nimport { CheckIcon } from '@lucide/vue'\nimport { computed, nextTick, ref, useId, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useVirtualList } from '../../composables/use-virtual-list'\nimport { useChoice, useDirection, usePanel, useT } from '../../context'\nimport { showToast } from '../notifications/flash-toasts'\nimport VirtualSpacerRow from '../schema/VirtualSpacerRow.vue'\nimport Button from '../ui/Button.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogFooter from '../ui/DialogFooter.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport Spinner from '../ui/Spinner.vue'\n\n/**\n * Spreadsheet mode of a `Table::spreadsheet()` table (loaded on first use): a keyboard\n * grid over the page's records. Edits stay local (highlighted) until \"Save\" sends them in\n * one request; the server validates each cell with its column's rules and the record's\n * `update` policy, and its errors show on the cells.\n */\nconst props = defineProps<{ table: TableSchema; token: string; component: string }>()\nconst emit = defineEmits<{ close: [] }>()\n\ninterface PastePreview {\n plan: PastePlan\n errors: SpreadsheetSaveResult['errors']\n validating: boolean\n}\n\nconst t = useT()\nconst choice = useChoice()\nconst direction = useDirection()\nconst panel = usePanel()\nconst baseId = `spreadsheet-${useId()}`\nconst columns = computed(() => spreadsheetColumns(props.table))\nconst rows = computed(() => spreadsheetRows(props.table.records ?? [], columns.value))\nconst grid = new SpreadsheetGrid(rows.value, columns.value)\nconst state = useStore(grid.store)\nconst announcement = ref('')\nconst preview = ref<PastePreview | null>(null)\nconst gridElement = ref<HTMLTableElement | null>(null)\nconst helpId = `${baseId}-help`\n\n// A reload (save, live update, polling) brings new records; edits of rows still on the\n// page are kept.\nwatch([rows, columns], ([nextRows, nextColumns]) => grid.setData(nextRows, nextColumns))\n\nconst virtual = useVirtualList(\n () => rows.value.length,\n () => virtualizeOptions(props.table.virtualize, VIRTUAL_ESTIMATES.row),\n)\n\nconst endpoint = computed(() => panel.value.endpoints.tableCells)\nconst errorList = computed(() => {\n void state.value\n\n return grid.errorCells()\n})\n\nfunction announce(message: SpreadsheetAnnouncement | null) {\n if (message) announcement.value = choice(message.key, message.count, {}, message.fallback)\n}\n\nfunction focusCell(row: number, col: number) {\n void nextTick(() => {\n const cell = document.getElementById(spreadsheetCellId(baseId, row, col))\n\n if (cell) {\n cell.focus()\n cell.scrollIntoView?.({ block: 'nearest', inline: 'nearest' })\n } else {\n virtual.list.scrollToIndex(row)\n }\n })\n}\n\n// Keep focus on the active cell (roving tabindex).\nwatch(\n () => [state.value.active, state.value.editing] as const,\n ([active, editing]) => {\n if (editing || !gridElement.value?.contains(document.activeElement)) return\n\n focusCell(active.row, active.col)\n },\n)\n\nasync function save() {\n const changes = grid.changes()\n\n if (!endpoint.value || changes.length === 0 || state.value.saving) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(\n endpoint.value,\n props.token,\n props.component,\n changes,\n )\n\n grid.applySaveResult(result)\n\n if (result.saved.length > 0) {\n announce(spreadsheetAnnouncement('saved', result.saved.length))\n inertiaReload()\n }\n\n if (result.errors.length > 0) announce(spreadsheetAnnouncement('failed', result.errors.length))\n } catch (error) {\n showToast({\n id: 'alfakit-spreadsheet-failed',\n title: t('table.spreadsheet.request_failed', {}, \"Couldn't save the changes\"),\n body: error instanceof Error ? error.message : String(error),\n status: 'danger',\n format: 'alfakit',\n })\n } finally {\n grid.setSaving(false)\n }\n}\n\nasync function undoSave() {\n const changes = grid.undoSaveChanges()\n\n if (!endpoint.value || changes.length === 0) return\n\n grid.setSaving(true)\n\n try {\n const result = await saveSpreadsheetChanges(\n endpoint.value,\n props.token,\n props.component,\n changes,\n )\n\n grid.applySaveResult(result)\n announce(spreadsheetAnnouncement('undo', result.saved.length))\n\n if (result.saved.length > 0) inertiaReload()\n } finally {\n grid.setSaving(false)\n }\n}\n\nfunction close() {\n if (\n grid.dirtyCount > 0 &&\n !window.confirm(t('table.spreadsheet.discard_confirm', {}, 'Discard your unsaved changes?'))\n ) {\n return\n }\n\n grid.discard()\n emit('close')\n}\n\nfunction onKeyDown(event: KeyboardEvent) {\n const result = grid.handleKey(event, direction.value)\n\n if (result === 'ignored') return\n\n event.preventDefault()\n\n if (result === 'save') {\n void save()\n } else if (result === 'undo') {\n announce(spreadsheetAnnouncement('undo', grid.undo()))\n } else if (result === 'fill' || result === 'clear') {\n announce(spreadsheetAnnouncement(result, grid.lastApplied))\n }\n\n if (result === 'commit' || result === 'cancel' || result === 'toggle') {\n focusCell(grid.state.active.row, grid.state.active.col)\n }\n}\n\nfunction onCopy(event: ClipboardEvent) {\n if (grid.state.editing || !event.clipboardData) return\n\n event.preventDefault()\n event.clipboardData.setData('text/plain', grid.copyText())\n announce(spreadsheetAnnouncement('copy', spreadsheetSelectionSize(grid.bounds())))\n}\n\nfunction onPaste(event: ClipboardEvent) {\n if (grid.state.editing || !event.clipboardData) return\n\n event.preventDefault()\n\n const plan = grid.planPaste(event.clipboardData.getData('text/plain'))\n\n if (plan.changes.length === 0 && plan.issues.length === 0) return\n\n const url = endpoint.value\n\n preview.value = { plan, errors: [], validating: Boolean(url && plan.changes.length > 0) }\n\n if (!url || plan.changes.length === 0) return\n\n // Validate the pasted values on the server before they are applied.\n saveSpreadsheetChanges(\n url,\n props.token,\n props.component,\n plan.changes.map((change) => ({\n record: grid.getRows()[change.row]?.key ?? '',\n column: grid.getColumns()[change.col]?.name ?? '',\n state: change.value,\n })),\n { dryRun: true },\n )\n .then((result) => {\n if (preview.value)\n preview.value = { ...preview.value, errors: result.errors, validating: false }\n })\n .catch(() => {\n if (preview.value) preview.value = { ...preview.value, validating: false }\n })\n}\n\nfunction applyPaste() {\n const current = preview.value\n\n if (!current) return\n\n const count = grid.apply(current.plan.changes)\n\n if (current.errors.length > 0) grid.setErrors(current.errors)\n\n announce(spreadsheetAnnouncement('paste', count))\n preview.value = null\n}\n\nfunction issueText(issue: PastePlan['issues'][number]): string {\n const message = SPREADSHEET_ISSUE_MESSAGES[issue.reason]\n\n return t(\n message.key,\n { text: issue.text, column: columns.value[issue.col]?.label ?? '', row: issue.row + 1 },\n message.fallback,\n )\n}\n\nfunction errorText(record: SpreadsheetSaveResult['errors'][number]): string {\n const position = grid.position(record.record, record.column)\n\n return t(\n 'table.spreadsheet.cell_error',\n {\n row: (position?.row ?? -1) + 1,\n column: columns.value.find((column) => column.name === record.column)?.label ?? record.column,\n message: record.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )\n}\n\nfunction draft(): string {\n const value = state.value.editing?.value\n\n return value === null || value === undefined ? '' : String(value)\n}\n\nfunction isEditing(row: number, col: number): boolean {\n return state.value.editing?.row === row && state.value.editing.col === col\n}\n\nfunction onSelectChange(event: Event, row: number, col: number) {\n grid.updateDraft((event.target as HTMLSelectElement).value)\n grid.commitEdit()\n focusCell(row, col)\n}\n\nconst optionText = (label: string) => label.replace(/<[^>]*>/g, '')\n\n/** Focus an editor as soon as it is shown. */\nconst vFocus = { mounted: (element: HTMLElement) => element.focus() }\n</script>\n\n<template>\n <div data-slot=\"spreadsheet\" class=\"flex flex-col gap-3\">\n <div data-slot=\"spreadsheet-toolbar\" class=\"flex flex-wrap items-center gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n :disabled=\"grid.dirtyCount === 0 || state.saving\"\n @click=\"save\"\n >\n <Spinner v-if=\"state.saving\" />\n {{ t('table.spreadsheet.save', {}, 'Save changes') }}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n :disabled=\"!grid.canUndo || state.saving\"\n @click=\"announce(spreadsheetAnnouncement('undo', grid.undo()))\"\n >\n {{ t('table.spreadsheet.undo', {}, 'Undo') }}\n </Button>\n <Button\n v-if=\"grid.canUndoSave\"\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n :disabled=\"state.saving\"\n @click=\"undoSave\"\n >\n {{ t('table.spreadsheet.undo_save', {}, 'Undo last save') }}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n :disabled=\"grid.dirtyCount === 0 || state.saving\"\n @click=\"grid.discard()\"\n >\n {{ t('table.spreadsheet.discard', {}, 'Discard') }}\n </Button>\n <span class=\"text-muted-foreground text-sm\" aria-live=\"polite\">\n <template v-if=\"grid.dirtyCount > 0\">{{\n choice(\n 'table.spreadsheet.unsaved',\n grid.dirtyCount,\n {},\n ':count unsaved change|:count unsaved changes',\n )\n }}</template>\n <span v-if=\"grid.errorCount > 0\" class=\"text-destructive ms-2\">{{\n choice('table.spreadsheet.errors', grid.errorCount, {}, ':count error|:count errors')\n }}</span>\n </span>\n <span class=\"flex-1\" />\n <Button type=\"button\" size=\"sm\" variant=\"outline\" @click=\"close\">\n {{ t('table.spreadsheet.close', {}, 'Done') }}\n </Button>\n </div>\n <p :id=\"helpId\" class=\"sr-only\">\n {{\n t(\n 'table.spreadsheet.help',\n {},\n 'Arrow keys move between cells. Enter or F2 edits a cell, Escape cancels, Tab moves to the next cell. Ctrl+C copies, Ctrl+V pastes, Ctrl+D fills down, Ctrl+Z undoes and Ctrl+S saves.',\n )\n }}\n </p>\n <div data-surface=\"table\" :class=\"SPREADSHEET_CLASSES.root\" style=\"max-height: 70vh\">\n <table\n ref=\"gridElement\"\n role=\"grid\"\n :aria-label=\"props.table.heading ?? t('table.spreadsheet.label', {}, 'Spreadsheet')\"\n :aria-describedby=\"helpId\"\n :aria-rowcount=\"rows.length + 1\"\n :aria-colcount=\"columns.length\"\n aria-multiselectable=\"true\"\n :aria-busy=\"state.saving || undefined\"\n data-slot=\"spreadsheet-grid\"\n :class=\"SPREADSHEET_CLASSES.table\"\n @keydown=\"onKeyDown\"\n @copy=\"onCopy\"\n @paste=\"onPaste\"\n >\n <thead>\n <tr aria-rowindex=\"1\">\n <th\n v-for=\"(column, col) in columns\"\n :key=\"column.name\"\n role=\"columnheader\"\n scope=\"col\"\n :aria-colindex=\"col + 1\"\n :class=\"SPREADSHEET_CLASSES.header\"\n >\n {{ column.label }}\n </th>\n </tr>\n </thead>\n <tbody :ref=\"virtual.attach\">\n <VirtualSpacerRow :height=\"virtual.range.value.before\" :col-span=\"columns.length\" />\n <template v-for=\"row in virtual.indexes.value\" :key=\"String(rows[row]?.key ?? row)\">\n <tr v-if=\"rows[row]\" :ref=\"virtual.item\" :data-index=\"row\" :aria-rowindex=\"row + 2\">\n <td\n v-for=\"(column, col) in columns\"\n :id=\"spreadsheetCellId(baseId, row, col)\"\n :key=\"column.name\"\n role=\"gridcell\"\n v-bind=\"spreadsheetAria(row, col)\"\n :tabindex=\"grid.isActive(row, col) ? 0 : -1\"\n :aria-selected=\"grid.isSelected(row, col)\"\n :aria-readonly=\"!grid.isEditable(row, col) || undefined\"\n :aria-invalid=\"grid.errorsAt(row, col).length > 0 || undefined\"\n :title=\"grid.errorsAt(row, col).join(' ') || undefined\"\n data-slot=\"spreadsheet-cell\"\n :data-dirty=\"grid.isDirty(row, col) || undefined\"\n :data-active=\"grid.isActive(row, col) || undefined\"\n :class=\"spreadsheetCellClass(grid, row, col)\"\n @mousedown=\"!isEditing(row, col) && grid.moveTo(row, col, $event.shiftKey)\"\n @dblclick=\"grid.beginEdit()\"\n >\n <select\n v-if=\"isEditing(row, col) && column.kind === 'select'\"\n v-focus\n :class=\"SPREADSHEET_CLASSES.editor\"\n :aria-label=\"column.label\"\n :value=\"draft()\"\n @change=\"onSelectChange($event, row, col)\"\n @blur=\"grid.cancelEdit()\"\n >\n <option value=\"\">{{ t('table.spreadsheet.no_value', {}, '—') }}</option>\n <option\n v-for=\"option in column.options\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ optionText(option.label) }}\n </option>\n </select>\n <input\n v-else-if=\"isEditing(row, col)\"\n v-focus\n :type=\"column.kind === 'number' ? 'text' : (column.inputType ?? 'text')\"\n :inputmode=\"column.kind === 'number' ? 'decimal' : undefined\"\n :class=\"SPREADSHEET_CLASSES.editor\"\n :aria-label=\"column.label\"\n :value=\"draft()\"\n @input=\"grid.updateDraft(($event.target as HTMLInputElement).value)\"\n @blur=\"grid.commitEdit()\"\n />\n <span v-else-if=\"column.kind === 'boolean'\" class=\"inline-flex items-center gap-1\">\n <span\n aria-hidden=\"true\"\n class=\"border-input data-[checked=true]:bg-primary data-[checked=true]:text-primary-foreground inline-flex size-4 items-center justify-center rounded-[4px] border\"\n :data-checked=\"Boolean(grid.value(row, col))\"\n >\n <CheckIcon v-if=\"grid.value(row, col)\" class=\"size-3\" />\n </span>\n <span class=\"sr-only\">{{\n grid.value(row, col)\n ? t('table.spreadsheet.yes', {}, 'Yes')\n : t('table.spreadsheet.no', {}, 'No')\n }}</span>\n </span>\n <template v-else>{{ grid.text(row, col) }}</template>\n <span v-if=\"grid.errorsAt(row, col).length > 0\" class=\"sr-only\">{{\n grid.errorsAt(row, col).join(' ')\n }}</span>\n </td>\n </tr>\n </template>\n <VirtualSpacerRow :height=\"virtual.range.value.after\" :col-span=\"columns.length\" />\n </tbody>\n </table>\n <p v-if=\"rows.length === 0\" class=\"text-muted-foreground p-6 text-center text-sm\">\n {{ t('table.spreadsheet.empty', {}, 'No records to edit.') }}\n </p>\n </div>\n <ul\n v-if=\"errorList.length > 0\"\n data-slot=\"spreadsheet-errors\"\n class=\"text-destructive flex flex-col gap-1 text-sm\"\n >\n <li v-for=\"error in errorList\" :key=\"error.key\">\n <button\n type=\"button\"\n class=\"text-start hover:underline\"\n @click=\"\n () => {\n grid.moveTo(error.row, error.col)\n focusCell(error.row, error.col)\n }\n \"\n >\n {{\n t(\n 'table.spreadsheet.cell_error',\n {\n row: error.row + 1,\n column: columns[error.col]?.label ?? '',\n message: error.messages.join(' '),\n },\n 'Row :row, :column: :message',\n )\n }}\n </button>\n </li>\n </ul>\n <span\n aria-live=\"polite\"\n aria-atomic=\"true\"\n class=\"sr-only\"\n data-slot=\"spreadsheet-announcement\"\n >{{ announcement }}</span\n >\n\n <Dialog :open=\"preview !== null\" @update:open=\"(value) => !value && (preview = null)\">\n <DialogContent class=\"sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>{{ t('table.spreadsheet.paste_title', {}, 'Paste cells') }}</DialogTitle>\n <DialogDescription>\n <!-- One line per count: translations can't join two sentences. -->\n <span class=\"block\">{{\n choice(\n 'table.spreadsheet.paste_summary',\n preview?.plan.changes.length ?? 0,\n {},\n ':count cell will change|:count cells will change',\n )\n }}</span>\n <span\n v-if=\"(preview?.plan.skipped ?? 0) > 0\"\n class=\"block\"\n data-slot=\"spreadsheet-paste-skipped\"\n >\n {{\n choice(\n 'table.spreadsheet.paste_skipped',\n preview?.plan.skipped ?? 0,\n {},\n ':count read-only cell is skipped|:count read-only cells are skipped',\n )\n }}\n </span>\n </DialogDescription>\n </DialogHeader>\n <div data-slot=\"spreadsheet-paste\" class=\"flex flex-col gap-3\">\n <p\n v-if=\"preview?.validating\"\n class=\"text-muted-foreground flex items-center gap-2 text-sm\"\n >\n <Spinner />\n {{ t('table.spreadsheet.paste_validating', {}, 'Checking the values…') }}\n </p>\n <ul\n v-if=\"preview && (preview.plan.issues.length > 0 || preview.errors.length > 0)\"\n class=\"text-destructive flex max-h-48 flex-col gap-1 overflow-auto text-sm\"\n >\n <li v-for=\"issue in preview.plan.issues\" :key=\"`issue-${issue.row}-${issue.col}`\">\n {{ issueText(issue) }}\n </li>\n <li\n v-for=\"error in preview.errors\"\n :key=\"`error-${String(error.record)}-${error.column}`\"\n >\n {{ errorText(error) }}\n </li>\n </ul>\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" @click=\"preview = null\">{{\n t('cancel', {}, 'Cancel')\n }}</Button>\n <Button\n type=\"button\"\n :disabled=\"!preview || preview.plan.changes.length === 0\"\n @click=\"applyPaste\"\n >\n {{ t('table.spreadsheet.paste_apply', {}, 'Apply') }}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"Spreadsheet.vue.d.ts","sourceRoot":"","sources":["../../../src/components/table/Spreadsheet.vue"],"names":[],"mappings":"AA2kBA,OAAO,KAAK,EAIV,WAAW,EACZ,MAAM,eAAe,CAAA;AAiCtB;;;;;GAKG;AACH,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;;;;;;AAu7B5E,wBAOG"}
1
+ {"version":3,"file":"Spreadsheet.vue.d.ts","sourceRoot":"","sources":["../../../src/components/table/Spreadsheet.vue"],"names":[],"mappings":"AAglBA,OAAO,KAAK,EAIV,WAAW,EACZ,MAAM,eAAe,CAAA;AAiCtB;;;;;GAKG;AACH,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;;;;;;AAg8B5E,wBAOG"}