@alfakit/vue 0.1.2 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/AlfakitRoot.js.map +1 -1
- package/dist/AlfakitRoot.vue.d.ts.map +1 -1
- package/dist/AlfakitRoot.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/AlfakitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/actions/ActionGroupMenu.js.map +1 -1
- package/dist/components/actions/ActionGroupMenu.vue.d.ts.map +1 -1
- package/dist/components/actions/ActionGroupMenu.vue_vue_type_script_setup_true_lang.js +69 -65
- package/dist/components/actions/ActionGroupMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/actions/ActionModal.js.map +1 -1
- package/dist/components/actions/ActionModal.vue.d.ts.map +1 -1
- package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js +17 -15
- package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ai/AiCopilot.js.map +1 -1
- package/dist/components/ai/AiCopilot.vue.d.ts +2 -0
- package/dist/components/ai/AiCopilot.vue.d.ts.map +1 -1
- package/dist/components/ai/AiCopilot.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/components/ai/AiCopilot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cms/CmsPage.vue_vue_type_script_setup_true_lang.js +19 -19
- package/dist/components/cms/CmsPage.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cms/LivePreview.js.map +1 -1
- package/dist/components/cms/LivePreview.vue.d.ts.map +1 -1
- package/dist/components/cms/LivePreview.vue_vue_type_script_setup_true_lang.js +83 -83
- package/dist/components/cms/LivePreview.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/BuilderField.js.map +1 -1
- package/dist/components/fields/BuilderField.vue.d.ts.map +1 -1
- package/dist/components/fields/BuilderField.vue_vue_type_script_setup_true_lang.js +162 -157
- package/dist/components/fields/BuilderField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/ImageEditorDialog.js.map +1 -1
- package/dist/components/fields/ImageEditorDialog.vue.d.ts.map +1 -1
- package/dist/components/fields/ImageEditorDialog.vue_vue_type_script_setup_true_lang.js +46 -46
- package/dist/components/fields/ImageEditorDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/KeyValueField.js.map +1 -1
- package/dist/components/fields/KeyValueField.vue.d.ts.map +1 -1
- package/dist/components/fields/KeyValueField.vue_vue_type_script_setup_true_lang.js +66 -66
- package/dist/components/fields/KeyValueField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/ModalTablePicker.js.map +1 -1
- package/dist/components/fields/ModalTablePicker.vue.d.ts.map +1 -1
- package/dist/components/fields/ModalTablePicker.vue_vue_type_script_setup_true_lang.js +113 -113
- package/dist/components/fields/ModalTablePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/RepeaterField.js.map +1 -1
- package/dist/components/fields/RepeaterField.vue.d.ts.map +1 -1
- package/dist/components/fields/RepeaterField.vue_vue_type_script_setup_true_lang.js +12 -12
- package/dist/components/fields/RepeaterField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/RichEditorInput.js.map +1 -1
- package/dist/components/fields/RichEditorInput.vue.d.ts.map +1 -1
- package/dist/components/fields/RichEditorInput.vue_vue_type_script_setup_true_lang.js +166 -165
- package/dist/components/fields/RichEditorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/SliderField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/item-actions.d.ts +2 -2
- package/dist/components/fields/item-actions.d.ts.map +1 -1
- package/dist/components/fields/item-actions.js +31 -31
- package/dist/components/fields/item-actions.js.map +1 -1
- package/dist/components/form/FormBlock.js.map +1 -1
- package/dist/components/form/FormBlock.vue.d.ts.map +1 -1
- package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/form-context.js +25 -25
- package/dist/components/form/form-context.js.map +1 -1
- package/dist/components/kanban/KanbanBoard.js.map +1 -1
- package/dist/components/kanban/KanbanBoard.vue.d.ts.map +1 -1
- package/dist/components/kanban/KanbanBoard.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/kanban/KanbanBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/kanban/KanbanColumnHeader.js.map +1 -1
- package/dist/components/kanban/KanbanColumnHeader.vue.d.ts.map +1 -1
- package/dist/components/kanban/KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js +64 -64
- package/dist/components/kanban/KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/layout/SectionComponent.js.map +1 -1
- package/dist/components/layout/SectionComponent.vue.d.ts.map +1 -1
- package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js +23 -23
- package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/DebugPanel.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/panel/DebugPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/GlobalSearchPalette.js.map +1 -1
- package/dist/components/panel/GlobalSearchPalette.vue.d.ts.map +1 -1
- package/dist/components/panel/GlobalSearchPalette.vue_vue_type_script_setup_true_lang.js +102 -96
- package/dist/components/panel/GlobalSearchPalette.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavGroupFlyout.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/components/panel/NavGroupFlyout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js +16 -16
- package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js +35 -35
- package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/Topbar.vue_vue_type_script_setup_true_lang.js +11 -11
- package/dist/components/panel/Topbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/realtime/use-live-updates.d.ts.map +1 -1
- package/dist/components/realtime/use-live-updates.js +24 -23
- package/dist/components/realtime/use-live-updates.js.map +1 -1
- package/dist/components/table/BooleanCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/BooleanCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/ColumnHeader.js.map +1 -1
- package/dist/components/table/ColumnHeader.vue.d.ts.map +1 -1
- package/dist/components/table/ColumnHeader.vue_vue_type_script_setup_true_lang.js +55 -49
- package/dist/components/table/ColumnHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/ColumnManager.js.map +1 -1
- package/dist/components/table/ColumnManager.vue.d.ts.map +1 -1
- package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js +5 -4
- package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/ContentLayoutSort.js.map +1 -1
- package/dist/components/table/ContentLayoutSort.vue.d.ts.map +1 -1
- package/dist/components/table/ContentLayoutSort.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/components/table/ContentLayoutSort.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/SelectComboboxCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/SelectComboboxCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TableCellContent.js.map +1 -1
- package/dist/components/table/TableCellContent.vue.d.ts.map +1 -1
- package/dist/components/table/TableCellContent.vue_vue_type_script_setup_true_lang.js +4 -3
- package/dist/components/table/TableCellContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TablePagination.js.map +1 -1
- package/dist/components/table/TablePagination.vue.d.ts.map +1 -1
- package/dist/components/table/TablePagination.vue_vue_type_script_setup_true_lang.js +87 -87
- package/dist/components/table/TablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/cell-update.d.ts +6 -0
- package/dist/components/table/cell-update.d.ts.map +1 -1
- package/dist/components/table/cell-update.js.map +1 -1
- package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/CommandAutoHighlight.js +7 -0
- package/dist/components/ui/CommandAutoHighlight.js.map +1 -0
- package/dist/components/ui/CommandAutoHighlight.vue.d.ts +21 -0
- package/dist/components/ui/CommandAutoHighlight.vue.d.ts.map +1 -0
- package/dist/components/ui/CommandAutoHighlight.vue_vue_type_script_setup_true_lang.js +18 -0
- package/dist/components/ui/CommandAutoHighlight.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/ui/DialogContent.js.map +1 -1
- package/dist/components/ui/DialogContent.vue.d.ts.map +1 -1
- package/dist/components/ui/DialogContent.vue_vue_type_script_setup_true_lang.js +13 -12
- package/dist/components/ui/DialogContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/PopoverContent.js.map +1 -1
- package/dist/components/ui/PopoverContent.vue.d.ts.map +1 -1
- package/dist/components/ui/PopoverContent.vue_vue_type_script_setup_true_lang.js +9 -8
- package/dist/components/ui/PopoverContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/SheetContent.js.map +1 -1
- package/dist/components/ui/SheetContent.vue.d.ts.map +1 -1
- package/dist/components/ui/SheetContent.vue_vue_type_script_setup_true_lang.js +13 -12
- package/dist/components/ui/SheetContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/TooltipContent.js.map +1 -1
- package/dist/components/ui/TooltipContent.vue.d.ts.map +1 -1
- package/dist/components/ui/TooltipContent.vue_vue_type_script_setup_true_lang.js +9 -8
- package/dist/components/ui/TooltipContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/context.d.ts +7 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +29 -26
- package/dist/context.js.map +1 -1
- package/dist/create-alfakit.d.ts.map +1 -1
- package/dist/create-alfakit.js +33 -31
- package/dist/create-alfakit.js.map +1 -1
- package/dist/eject-manifest.json +11 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +219 -217
- package/dist/layouts/AppLayout.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/layouts/AppLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layouts/AuthLayout.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/layouts/FullscreenLayout.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/layouts/FullscreenLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js +15 -15
- package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layouts/lazy-layouts.d.ts +10 -0
- package/dist/layouts/lazy-layouts.d.ts.map +1 -0
- package/dist/layouts/lazy-layouts.js +8 -0
- package/dist/layouts/lazy-layouts.js.map +1 -0
- package/dist/layouts/panel-layouts.d.ts +8 -0
- package/dist/layouts/panel-layouts.d.ts.map +1 -0
- package/dist/layouts/panel-layouts.js +15 -0
- package/dist/layouts/panel-layouts.js.map +1 -0
- package/dist/lib/lazy.d.ts.map +1 -1
- package/dist/lib/lazy.js +2 -2
- package/dist/lib/lazy.js.map +1 -1
- package/dist/pages/PageShell.js.map +1 -1
- package/dist/pages/PageShell.vue.d.ts.map +1 -1
- package/dist/pages/PageShell.vue_vue_type_script_setup_true_lang.js +39 -42
- package/dist/pages/PageShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/standalone/AlfakitComponent.js.map +1 -1
- package/dist/standalone/AlfakitComponent.vue.d.ts.map +1 -1
- package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js +56 -52
- package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/standalone.css +7 -0
- package/dist/starter-kit/AlfakitStarterKitRoot.js.map +1 -1
- package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts +2 -2
- package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts.map +1 -1
- package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js +17 -12
- package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/starter-kit/dashboard-widgets.d.ts +54 -0
- package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
- package/dist/starter-kit/dashboard-widgets.js +54 -0
- package/dist/starter-kit/dashboard-widgets.js.map +1 -0
- package/dist/starter-kit/index.d.ts +2 -1
- package/dist/starter-kit/index.d.ts.map +1 -1
- package/dist/starter-kit/index.js +5 -4
- package/dist/starter-kit/runtime.d.ts +6 -0
- package/dist/starter-kit/runtime.d.ts.map +1 -1
- package/dist/starter-kit/runtime.js +19 -15
- package/dist/starter-kit/runtime.js.map +1 -1
- package/dist/starter-kit/starter-kit.d.ts.map +1 -1
- package/dist/starter-kit/starter-kit.js +8 -8
- package/dist/starter-kit/starter-kit.js.map +1 -1
- package/dist/starter-kit/widgets/CopilotTrigger.js +7 -0
- package/dist/starter-kit/widgets/CopilotTrigger.js.map +1 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue.d.ts +12 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue.d.ts.map +1 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue_vue_type_script_setup_true_lang.js +23 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/starter-kit/widgets/LoadedCopilot.js +7 -0
- package/dist/starter-kit/widgets/LoadedCopilot.js.map +1 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue.d.ts +8 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue.d.ts.map +1 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue_vue_type_script_setup_true_lang.js +31 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.js +7 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.js.map +1 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue.d.ts +8 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue.d.ts.map +1 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue_vue_type_script_setup_true_lang.js +34 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/starter-kit/widgets/index.d.ts +40 -9
- package/dist/starter-kit/widgets/index.d.ts.map +1 -1
- package/dist/starter-kit/widgets/index.js +21 -18
- package/dist/starter-kit/widgets/index.js.map +1 -1
- package/dist/starter-kit/widgets/loaded.d.ts +10 -0
- package/dist/starter-kit/widgets/loaded.d.ts.map +1 -0
- package/dist/starter-kit/widgets/loaded.js +5 -0
- package/dist/styles.css +9 -2
- package/dist/themes.css +6 -1
- package/package.json +2 -2
- package/src/AlfakitRoot.vue +9 -1
- package/src/components/actions/ActionGroupMenu.vue +13 -1
- package/src/components/actions/ActionModal.vue +9 -0
- package/src/components/ai/AiCopilot.vue +7 -1
- package/src/components/cms/LivePreview.vue +8 -2
- package/src/components/fields/BuilderField.vue +15 -2
- package/src/components/fields/ImageEditorDialog.vue +7 -3
- package/src/components/fields/KeyValueField.vue +3 -2
- package/src/components/fields/ModalTablePicker.vue +7 -2
- package/src/components/fields/RepeaterField.vue +2 -3
- package/src/components/fields/RichEditorInput.vue +3 -0
- package/src/components/fields/item-actions.ts +31 -10
- package/src/components/form/FormBlock.vue +2 -1
- package/src/components/form/form-context.ts +2 -2
- package/src/components/kanban/KanbanBoard.vue +15 -3
- package/src/components/kanban/KanbanColumnHeader.vue +6 -4
- package/src/components/layout/SectionComponent.vue +10 -4
- package/src/components/panel/GlobalSearchPalette.vue +2 -0
- package/src/components/realtime/use-live-updates.ts +3 -1
- package/src/components/table/ColumnHeader.vue +23 -12
- package/src/components/table/ColumnManager.vue +12 -8
- package/src/components/table/ContentLayoutSort.vue +7 -1
- package/src/components/table/TableCellContent.vue +4 -2
- package/src/components/table/TablePagination.vue +12 -7
- package/src/components/table/cell-update.ts +6 -0
- package/src/components/ui/CommandAutoHighlight.vue +27 -0
- package/src/components/ui/DialogContent.vue +5 -1
- package/src/components/ui/PopoverContent.vue +5 -1
- package/src/components/ui/SheetContent.vue +5 -1
- package/src/components/ui/TooltipContent.vue +5 -1
- package/src/context.ts +10 -0
- package/src/create-alfakit.ts +5 -0
- package/src/index.ts +2 -0
- package/src/layouts/lazy-layouts.ts +14 -0
- package/src/layouts/panel-layouts.ts +17 -0
- package/src/lib/lazy.ts +11 -1
- package/src/pages/PageShell.vue +5 -6
- package/src/standalone/AlfakitComponent.vue +17 -6
- package/src/starter-kit/AlfakitStarterKitRoot.vue +12 -3
- package/src/starter-kit/dashboard-widgets.ts +93 -0
- package/src/starter-kit/index.ts +7 -1
- package/src/starter-kit/runtime.ts +17 -1
- package/src/starter-kit/starter-kit.ts +2 -1
- package/src/starter-kit/widgets/CopilotTrigger.vue +58 -0
- package/src/starter-kit/widgets/LoadedCopilot.vue +29 -0
- package/src/starter-kit/widgets/StarterKitImpersonationBanner.vue +57 -0
- package/src/starter-kit/widgets/index.ts +56 -11
- package/src/starter-kit/widgets/loaded.ts +9 -0
- package/src/styles.css +9 -2
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
import { useStore as e } from "../../composables/use-store.js";
|
|
2
|
-
import { fieldAria as t, fieldDomId as n } from "@alfakit/core";
|
|
3
|
-
import { computed as
|
|
2
|
+
import { fieldAria as t, fieldDomId as n, fieldError as r } from "@alfakit/core";
|
|
3
|
+
import { computed as i, inject as a, provide as o, toValue as s } from "vue";
|
|
4
4
|
//#region src/components/form/form-context.ts
|
|
5
|
-
var
|
|
6
|
-
function
|
|
7
|
-
|
|
5
|
+
var c = Symbol("alfakit.form");
|
|
6
|
+
function l(e) {
|
|
7
|
+
o(c, e);
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
let e =
|
|
9
|
+
function u() {
|
|
10
|
+
let e = a(c, null);
|
|
11
11
|
if (!e) throw Error("Form fields must be rendered inside provideForm().");
|
|
12
12
|
return e;
|
|
13
13
|
}
|
|
14
|
-
function u() {
|
|
15
|
-
return i(s, null);
|
|
16
|
-
}
|
|
17
14
|
function d() {
|
|
18
|
-
return
|
|
15
|
+
return a(c, null);
|
|
16
|
+
}
|
|
17
|
+
function f() {
|
|
18
|
+
return e(u().store);
|
|
19
19
|
}
|
|
20
|
-
function
|
|
21
|
-
let
|
|
22
|
-
let e =
|
|
23
|
-
for (let t of
|
|
20
|
+
function p(a) {
|
|
21
|
+
let o = u(), c = e(o.store), l = s(a).statePath, d = i(() => {
|
|
22
|
+
let e = c.value.values;
|
|
23
|
+
for (let t of l.split(".")) {
|
|
24
24
|
if (typeof e != "object" || !e) return;
|
|
25
25
|
e = e[t];
|
|
26
26
|
}
|
|
27
27
|
return e;
|
|
28
|
-
}),
|
|
28
|
+
}), f = i(() => r(c.value.errors, l)), p = i(() => !!s(a).disabled), m = i(() => !!s(a).readOnly), h = s(a).id ?? n(o.idPrefix, l);
|
|
29
29
|
return {
|
|
30
|
-
value:
|
|
31
|
-
setValue: (e) =>
|
|
32
|
-
blur: () =>
|
|
33
|
-
error:
|
|
34
|
-
id:
|
|
35
|
-
disabled:
|
|
36
|
-
readOnly:
|
|
37
|
-
aria:
|
|
30
|
+
value: d,
|
|
31
|
+
setValue: (e) => o.setValue(l, e),
|
|
32
|
+
blur: () => o.blur(l),
|
|
33
|
+
error: f,
|
|
34
|
+
id: h,
|
|
35
|
+
disabled: p,
|
|
36
|
+
readOnly: m,
|
|
37
|
+
aria: i(() => t(h, s(a), f.value))
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
//#endregion
|
|
41
|
-
export {
|
|
41
|
+
export { c as FORM_STORE_KEY, l as provideForm, p as useField, f as useFormState, u as useFormStore, d as useOptionalFormStore };
|
|
42
42
|
|
|
43
43
|
//# sourceMappingURL=form-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-context.js","names":["FORM_STORE_KEY","provideForm","store","useFormStore","inject","useOptionalFormStore","useFormState","useStore","useField","state","path","toValue","field","value","computed","current","segment","error","disabled","readOnly","id","fieldDomId","next","fieldAria"],"sources":["../../../src/components/form/form-context.ts"],"sourcesContent":["import type { BaseField, FieldAriaAttributes, FormState, FormStore } from '@alfakit/core'\nimport { fieldAria, fieldDomId } from '@alfakit/core'\nimport {\n computed,\n inject,\n provide,\n toValue,\n type ComputedRef,\n type InjectionKey,\n type MaybeRefOrGetter,\n type ShallowRef,\n} from 'vue'\nimport { useStore } from '../../composables/use-store'\n\nexport const FORM_STORE_KEY: InjectionKey<FormStore> = Symbol('alfakit.form')\n\nexport function provideForm(store: FormStore): void {\n provide(FORM_STORE_KEY, store)\n}\n\nexport function useFormStore(): FormStore {\n const store = inject(FORM_STORE_KEY, null)\n\n if (!store) {\n throw new Error('Form fields must be rendered inside provideForm().')\n }\n\n return store\n}\n\nexport function useOptionalFormStore(): FormStore | null {\n return inject(FORM_STORE_KEY, null)\n}\n\nexport function useFormState(): ShallowRef<FormState> {\n return useStore(useFormStore().store)\n}\n\nexport interface FieldBinding<T = unknown> {\n value: ComputedRef<T>\n setValue: (value: T) => void\n blur: () => void\n error: ComputedRef<string | undefined>\n id: string\n /** The field cannot be interacted with at all (`disabled()`). */\n disabled: ComputedRef<boolean>\n /** The field shows its value but the user cannot change it (`readOnly()`). */\n readOnly: ComputedRef<boolean>\n /** `aria-describedby` (hint, helper text, error), `aria-invalid` and `aria-required` for the control. */\n aria: ComputedRef<FieldAriaAttributes>\n}\n\n/** Bind a field schema to the form store. */\nexport function useField<T = unknown>(field: MaybeRefOrGetter<BaseField>): FieldBinding<T> {\n const store = useFormStore()\n const state = useStore(store.store)\n const path = toValue(field).statePath\n\n const value = computed(() => {\n let current: unknown = state.value.values\n\n for (const segment of path.split('.')) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined as T\n }\n\n current = (current as Record<string, unknown>)[segment]\n }\n\n return current as T\n })\n\n const error = computed(() => state.value.errors
|
|
1
|
+
{"version":3,"file":"form-context.js","names":["FORM_STORE_KEY","provideForm","store","useFormStore","inject","useOptionalFormStore","useFormState","useStore","useField","state","path","toValue","field","value","computed","current","segment","error","fieldError","disabled","readOnly","id","fieldDomId","next","fieldAria"],"sources":["../../../src/components/form/form-context.ts"],"sourcesContent":["import type { BaseField, FieldAriaAttributes, FormState, FormStore } from '@alfakit/core'\nimport { fieldAria, fieldDomId, fieldError } from '@alfakit/core'\nimport {\n computed,\n inject,\n provide,\n toValue,\n type ComputedRef,\n type InjectionKey,\n type MaybeRefOrGetter,\n type ShallowRef,\n} from 'vue'\nimport { useStore } from '../../composables/use-store'\n\nexport const FORM_STORE_KEY: InjectionKey<FormStore> = Symbol('alfakit.form')\n\nexport function provideForm(store: FormStore): void {\n provide(FORM_STORE_KEY, store)\n}\n\nexport function useFormStore(): FormStore {\n const store = inject(FORM_STORE_KEY, null)\n\n if (!store) {\n throw new Error('Form fields must be rendered inside provideForm().')\n }\n\n return store\n}\n\nexport function useOptionalFormStore(): FormStore | null {\n return inject(FORM_STORE_KEY, null)\n}\n\nexport function useFormState(): ShallowRef<FormState> {\n return useStore(useFormStore().store)\n}\n\nexport interface FieldBinding<T = unknown> {\n value: ComputedRef<T>\n setValue: (value: T) => void\n blur: () => void\n error: ComputedRef<string | undefined>\n id: string\n /** The field cannot be interacted with at all (`disabled()`). */\n disabled: ComputedRef<boolean>\n /** The field shows its value but the user cannot change it (`readOnly()`). */\n readOnly: ComputedRef<boolean>\n /** `aria-describedby` (hint, helper text, error), `aria-invalid` and `aria-required` for the control. */\n aria: ComputedRef<FieldAriaAttributes>\n}\n\n/** Bind a field schema to the form store. */\nexport function useField<T = unknown>(field: MaybeRefOrGetter<BaseField>): FieldBinding<T> {\n const store = useFormStore()\n const state = useStore(store.store)\n const path = toValue(field).statePath\n\n const value = computed(() => {\n let current: unknown = state.value.values\n\n for (const segment of path.split('.')) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined as T\n }\n\n current = (current as Record<string, unknown>)[segment]\n }\n\n return current as T\n })\n\n const error = computed(() => fieldError(state.value.errors, path))\n // Fields stay enabled during a live refresh: the store keeps edits made while the request\n // is in flight, so locking inputs would only swallow keystrokes.\n const disabled = computed(() => Boolean(toValue(field).disabled))\n const readOnly = computed(() => Boolean(toValue(field).readOnly))\n const id = toValue(field).id ?? fieldDomId(store.idPrefix, path)\n const aria = computed(() => fieldAria(id, toValue(field), error.value))\n\n return {\n value,\n setValue: (next: T) => store.setValue(path, next),\n blur: () => store.blur(path),\n error,\n id,\n disabled,\n readOnly,\n aria,\n }\n}\n"],"mappings":";;;;AAcA,IAAaA,IAA0C,OAAO,cAAc;AAE5E,SAAgBC,EAAY,GAAwB;CAClD,EAAQD,GAAgBE,CAAK;AAC/B;AAEA,SAAgBC,IAA0B;CACxC,IAAMD,IAAQE,EAAOJ,GAAgB,IAAI;CAEzC,IAAI,CAACE,GACH,MAAU,MAAM,oDAAoD;CAGtE,OAAOA;AACT;AAEA,SAAgBG,IAAyC;CACvD,OAAOD,EAAOJ,GAAgB,IAAI;AACpC;AAEA,SAAgBM,IAAsC;CACpD,OAAOC,EAASJ,EAAa,CAAC,CAAC,KAAK;AACtC;AAiBA,SAAgBK,EAAsB,GAAqD;CACzF,IAAMN,IAAQC,EAAa,GACrBM,IAAQF,EAASL,EAAM,KAAK,GAC5BQ,IAAOC,EAAQC,CAAK,CAAC,CAAC,WAEtBC,IAAQC,QAAe;EAC3B,IAAIC,IAAmBN,EAAM,MAAM;EAEnC,KAAK,IAAMO,KAAWN,EAAK,MAAM,GAAG,GAAG;GACrC,IAAiD,OAAOK,KAAY,aAAhEA,GACF;GAGF,IAAWA,EAAoCC;EACjD;EAEA,OAAOD;CACT,CAAC,GAEKE,IAAQH,QAAeI,EAAWT,EAAM,MAAM,QAAQC,CAAI,CAAC,GAG3DS,IAAWL,QAAe,EAAQH,EAAQC,CAAK,CAAC,CAAC,QAAS,GAC1DQ,IAAWN,QAAe,EAAQH,EAAQC,CAAK,CAAC,CAAC,QAAS,GAC1DS,IAAKV,EAAQC,CAAK,CAAC,CAAC,MAAMU,EAAWpB,EAAM,UAAUQ,CAAI;CAG/D,OAAO;EACL;EACA,WAAW,MAAYR,EAAM,SAASQ,GAAMa,CAAI;EAChD,YAAYrB,EAAM,KAAKQ,CAAI;EAC3B;EACA;EACA;EACA;EACA,MAVWI,QAAeU,EAAUH,GAAIV,EAAQC,CAAK,GAAGK,EAAM,KAAK,CAUnE;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KanbanBoard.js","names":["_sfc_main","KanbanBoard_vue_vue_type_script_setup_true_lang_default","KanbanBoard_default"],"sources":["../../../src/components/kanban/KanbanBoard.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { KanbanEnvironment, KanbanSchema } from '@alfakit/core'\nimport {\n KanbanController,\n attachKanbanPointer,\n clientErrorNotification,\n createKanbanFiltersStore,\n kanbanActiveFilters,\n kanbanCardsIn,\n kanbanInitials,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { ChevronRightIcon, SearchIcon } from '@lucide/vue'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, toRaw, useId, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useActionRunner, useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { showToast } from '../notifications/flash-toasts'\nimport Avatar from '../ui/Avatar.vue'\nimport AvatarFallback from '../ui/AvatarFallback.vue'\nimport AvatarImage from '../ui/AvatarImage.vue'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\nimport Card from '../ui/Card.vue'\nimport CardTitle from '../ui/CardTitle.vue'\nimport Input from '../ui/Input.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport KanbanCard from './KanbanCard.vue'\nimport KanbanColumnHeader from './KanbanColumnHeader.vue'\nimport KanbanFilters from './KanbanFilters.vue'\n\n/**\n * Cards move by dragging (mouse, pen, touch) or with the keyboard, and every move is\n * saved in one request.\n */\nconst props = defineProps<{ board: KanbanSchema }>()\n\nconst runner = useActionRunner()\nconst page = usePageActionContext()\nconst panel = usePanel()\nconst t = useT()\nconst direction = useDirection()\nconst labelId = useId()\nconst instructionsId = useId()\n\nconst environment = (): KanbanEnvironment => ({\n runner,\n token: page.token,\n t,\n notify: (notifications) => notifications.forEach((notification) => showToast(notification)),\n error: (message) => showToast(clientErrorNotification('kanban', message)),\n visit: (url) => router.visit(url),\n})\n\nconst controller = new KanbanController(toRaw(props.board), environment())\nconst filters = createKanbanFiltersStore(\n toRaw(props.board),\n page.token,\n panel.value.endpoints.schemaOptions,\n)\nconst state = useStore(controller.store)\nconst root = ref<{ $el: HTMLElement } | null>(null)\nconst cards = new Map<string, HTMLElement>()\nconst focused = ref<string | null>(null)\nconst search = ref(state.value.search)\nlet detach: (() => void) | null = null\nlet stopPolling: (() => void) | null = null\n\nwatch(\n () => props.board,\n (board) => controller.setBoard(toRaw(board)),\n)\nwatch(\n () => state.value.search,\n (value) => {\n if (value !== search.value) search.value = value\n },\n)\n\nonMounted(() => {\n const element = root.value?.$el\n\n if (element instanceof HTMLElement) detach = attachKanbanPointer(element, controller)\n\n stopPolling = controller.startPolling()\n})\n\nonBeforeUnmount(() => {\n detach?.()\n stopPolling?.()\n controller.destroy()\n filters?.destroy()\n})\n\nconst schema = computed(() => {\n // Re-read when the state changes (the controller swaps its schema with the board).\n void state.value.columns\n\n return controller.schema\n})\nconst lanes = computed(() => {\n void state.value.columns\n\n return controller.lanes()\n})\nconst filtered = computed(\n () => state.value.search !== '' || kanbanActiveFilters(state.value.filters) > 0,\n)\nconst keys = computed(() =>\n state.value.columns.flatMap((column) => column.cards.map((card) => card.key)),\n)\nconst current = computed(() =>\n focused.value !== null && keys.value.includes(focused.value)\n ? focused.value\n : (keys.value[0] ?? null),\n)\nconst template = computed(() =>\n state.value.columns\n .map((column) => (state.value.collapsed.has(column.key) ? '3.25rem' : 'minmax(16rem, 20rem)'))\n .join(' '),\n)\n\nconst setCard = (key: string) => (element: unknown) => {\n if (element instanceof HTMLElement) cards.set(key, element)\n else cards.delete(key)\n}\n\nconst focus = (key: string | undefined) => {\n if (!key) return\n focused.value = key\n void nextTick(() => cards.get(key)?.focus())\n}\n\n// A card picked up with the keyboard moves to another list: keep the focus on it.\nwatch(\n () => state.value.picked,\n (picked) => {\n if (picked?.via !== 'keyboard') return\n\n void nextTick(() => {\n const element = cards.get(picked.key)\n\n if (element && document.activeElement !== element) element.focus()\n })\n },\n)\n\nconst onKeyDown = (key: string, event: KeyboardEvent) => {\n if (event.target !== event.currentTarget) return\n\n const result = controller.handleKey(key, event, direction.value)\n\n if (!result.handled) return\n\n event.preventDefault()\n\n if (result.open) controller.open(key)\n else focus(result.focus)\n}\n\nconst onSearch = (value: string) => {\n search.value = value\n controller.setSearch(value)\n}\n\nconst laneCount = (lane: string) =>\n state.value.columns.reduce((sum, column) => sum + kanbanCardsIn(column, lane).length, 0)\n</script>\n\n<template>\n <Card ref=\"root\" role=\"region\" :aria-labelledby=\"labelId\" class=\"gap-3 py-4\" data-slot=\"kanban\">\n <div class=\"flex flex-wrap items-center gap-2 px-4\" data-slot=\"kanban-toolbar\">\n <CardTitle v-if=\"schema.heading\" :id=\"labelId\" class=\"text-base\">{{\n schema.heading\n }}</CardTitle>\n <span v-else :id=\"labelId\" class=\"sr-only\">{{ t('kanban.label', {}, 'Kanban board') }}</span>\n <div class=\"ms-auto flex w-full flex-wrap items-center gap-2 sm:w-auto\">\n <Spinner v-if=\"state.loading\" class=\"size-4\" />\n <div v-if=\"schema.searchable\" class=\"relative w-full sm:w-64\">\n <SearchIcon\n class=\"text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n :model-value=\"search\"\n class=\"h-8 ps-8\"\n :placeholder=\"t('kanban.search_placeholder', {}, 'Search…')\"\n :aria-label=\"t('kanban.search', {}, 'Search cards')\"\n @update:model-value=\"onSearch\"\n />\n </div>\n <KanbanFilters v-if=\"filters\" :controller=\"controller\" :store=\"filters\" />\n </div>\n </div>\n <p :id=\"instructionsId\" class=\"sr-only\">\n {{\n t(\n 'kanban.instructions',\n {},\n 'Press Space to pick up a card. While it is picked up, use the arrow keys to move it, Space to drop it and Escape to cancel.',\n )\n }}\n </p>\n <div\n class=\"relative overflow-x-auto overscroll-x-contain px-4 pb-2\"\n data-slot=\"kanban-scroller\"\n >\n <div class=\"grid w-max min-w-full snap-x gap-3\" :style=\"{ gridTemplateColumns: template }\">\n <KanbanColumnHeader\n v-for=\"column in state.columns\"\n :id=\"`${labelId}-column-${column.key}`\"\n :key=\"column.key\"\n :column=\"column\"\n :collapsed=\"state.collapsed.has(column.key)\"\n :creatable=\"Boolean(column.creatable && schema.createAction)\"\n :filtered=\"filtered\"\n @toggle=\"controller.toggleColumn(column.key)\"\n @create=\"controller.create(column.key)\"\n />\n <template v-for=\"lane in lanes\" :key=\"lane?.key ?? '__board'\">\n <div\n v-if=\"lane\"\n class=\"flex items-center gap-2 pt-2\"\n style=\"grid-column: 1 / -1\"\n data-slot=\"kanban-lane\"\n :data-lane=\"lane.key\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-expanded=\"!state.collapsedLanes.has(lane.key)\"\n :aria-label=\"\n state.collapsedLanes.has(lane.key)\n ? t('kanban.expand_lane', { lane: lane.label }, 'Expand row :lane')\n : t('kanban.collapse_lane', { lane: lane.label }, 'Collapse row :lane')\n \"\n @click=\"controller.toggleLane(lane.key)\"\n >\n <ChevronRightIcon\n :class=\"\n cn(\n 'transition-transform rtl:rotate-180',\n !state.collapsedLanes.has(lane.key) && 'rotate-90 rtl:rotate-90',\n )\n \"\n aria-hidden=\"true\"\n />\n </Button>\n <Avatar v-if=\"lane.avatar\" class=\"size-6\">\n <AvatarImage :src=\"lane.avatar\" alt=\"\" />\n <AvatarFallback>{{ kanbanInitials(lane.label) }}</AvatarFallback>\n </Avatar>\n <Icon v-else-if=\"lane.icon\" :name=\"lane.icon\" class=\"text-muted-foreground size-4\" />\n <span :id=\"`${labelId}-lane-${lane.key}`\" class=\"text-sm font-semibold\">{{\n lane.label\n }}</span>\n <Badge variant=\"secondary\" class=\"h-5 px-1.5 tabular-nums\">{{\n laneCount(lane.key)\n }}</Badge>\n </div>\n <template v-if=\"!lane || !state.collapsedLanes.has(lane.key)\">\n <ul\n v-for=\"column in state.columns\"\n :key=\"column.key\"\n role=\"list\"\n :aria-labelledby=\"\n [\n `${labelId}-column-${column.key}`,\n lane ? `${labelId}-lane-${lane.key}` : undefined,\n ]\n .filter(Boolean)\n .join(' ')\n \"\n data-slot=\"kanban-dropzone\"\n :data-column=\"column.key\"\n :data-lane=\"lane?.key\"\n :data-refused=\"state.picked && state.refused?.column === column.key ? '' : undefined\"\n :class=\"\n cn(\n 'bg-muted/40 flex min-h-24 flex-col gap-2 rounded-lg p-2',\n lane === null && 'max-h-[70vh] overflow-y-auto',\n )\n \"\n >\n <template v-if=\"!state.collapsed.has(column.key)\">\n <KanbanCard\n v-for=\"card in kanbanCardsIn(column, lane?.key ?? null)\"\n :key=\"card.key\"\n :card=\"card\"\n :board=\"schema\"\n :token=\"page.token\"\n :current=\"current === card.key\"\n :picked=\"state.picked?.key === card.key ? state.picked.via : undefined\"\n :saving=\"state.saving.has(card.key)\"\n :described-by=\"instructionsId\"\n :set-ref=\"setCard(card.key)\"\n @focus=\"focused = card.key\"\n @keydown=\"onKeyDown(card.key, $event)\"\n @open=\"controller.open(card.key)\"\n />\n <li\n v-if=\"kanbanCardsIn(column, lane?.key ?? null).length === 0\"\n class=\"text-muted-foreground rounded-md border border-dashed px-2 py-6 text-center text-xs\"\n data-slot=\"kanban-empty\"\n >\n {{\n filtered\n ? t('kanban.no_results', {}, 'No cards match')\n : (column.emptyState ?? t('kanban.empty', {}, 'No cards'))\n }}\n </li>\n <li\n v-if=\"lane === null && column.total > column.cards.length\"\n class=\"text-muted-foreground px-2 text-center text-xs\"\n >\n {{\n t(\n 'kanban.more_cards',\n { count: column.total - column.cards.length },\n '+:count more',\n )\n }}\n </li>\n </template>\n </ul>\n </template>\n </template>\n </div>\n </div>\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\">{{ state.announcement }}</div>\n </Card>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"KanbanBoard.js","names":["_sfc_main","KanbanBoard_vue_vue_type_script_setup_true_lang_default","KanbanBoard_default"],"sources":["../../../src/components/kanban/KanbanBoard.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { KanbanEnvironment, KanbanSchema } from '@alfakit/core'\nimport {\n KanbanController,\n attachKanbanPointer,\n clientErrorNotification,\n createKanbanFiltersStore,\n kanbanActiveFilters,\n kanbanCardsIn,\n kanbanInitials,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { ChevronRightIcon, SearchIcon } from '@lucide/vue'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, toRaw, useId, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useActionRunner, useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { showToast } from '../notifications/flash-toasts'\nimport Avatar from '../ui/Avatar.vue'\nimport AvatarFallback from '../ui/AvatarFallback.vue'\nimport AvatarImage from '../ui/AvatarImage.vue'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\nimport Card from '../ui/Card.vue'\nimport CardTitle from '../ui/CardTitle.vue'\nimport Input from '../ui/Input.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport KanbanCard from './KanbanCard.vue'\nimport KanbanColumnHeader from './KanbanColumnHeader.vue'\nimport KanbanFilters from './KanbanFilters.vue'\n\n/**\n * Cards move by dragging (mouse, pen, touch) or with the keyboard, and every move is\n * saved in one request.\n */\nconst props = defineProps<{ board: KanbanSchema }>()\n\nconst runner = useActionRunner()\nconst page = usePageActionContext()\nconst panel = usePanel()\nconst t = useT()\nconst direction = useDirection()\nconst labelId = useId()\nconst instructionsId = useId()\n\nconst environment = (): KanbanEnvironment => ({\n runner,\n token: page.token,\n t,\n notify: (notifications) => notifications.forEach((notification) => showToast(notification)),\n error: (message) => showToast(clientErrorNotification('kanban', message)),\n visit: (url) => router.visit(url),\n})\n\nconst controller = new KanbanController(toRaw(props.board), environment())\nconst filters = createKanbanFiltersStore(\n toRaw(props.board),\n page.token,\n panel.value.endpoints.schemaOptions,\n)\nconst state = useStore(controller.store)\nconst root = ref<{ $el: HTMLElement } | null>(null)\nconst cards = new Map<string, HTMLElement>()\nconst focused = ref<string | null>(null)\nconst search = ref(state.value.search)\nlet detach: (() => void) | null = null\nlet stopPolling: (() => void) | null = null\n\nwatch(\n () => props.board,\n (board) => controller.setBoard(toRaw(board)),\n)\nwatch(\n () => state.value.search,\n (value) => {\n if (value !== search.value) search.value = value\n },\n)\n\nonMounted(() => {\n const element = root.value?.$el\n\n if (element instanceof HTMLElement) detach = attachKanbanPointer(element, controller)\n\n stopPolling = controller.startPolling()\n})\n\nonBeforeUnmount(() => {\n detach?.()\n stopPolling?.()\n controller.destroy()\n filters?.destroy()\n})\n\nconst schema = computed(() => {\n // Re-read when the state changes (the controller swaps its schema with the board).\n void state.value.columns\n\n return controller.schema\n})\nconst lanes = computed(() => {\n void state.value.columns\n\n return controller.lanes()\n})\nconst filtered = computed(\n () => state.value.search !== '' || kanbanActiveFilters(state.value.filters) > 0,\n)\nconst keys = computed(() =>\n state.value.columns.flatMap((column) => column.cards.map((card) => card.key)),\n)\nconst current = computed(() =>\n focused.value !== null && keys.value.includes(focused.value)\n ? focused.value\n : (keys.value[0] ?? null),\n)\nconst template = computed(() =>\n state.value.columns\n .map((column) => (state.value.collapsed.has(column.key) ? '3.25rem' : 'minmax(16rem, 20rem)'))\n .join(' '),\n)\n\n// A card moved to another column is mounted there before its old element is unmounted, so\n// an unmount only forgets the element it registered itself (else the moved card would lose\n// its entry and the keyboard focus).\nconst setCard = (key: string) => {\n let own: HTMLElement | null = null\n\n return (element: unknown) => {\n if (element instanceof HTMLElement) {\n own = element\n cards.set(key, element)\n } else if (own !== null) {\n if (cards.get(key) === own) cards.delete(key)\n own = null\n }\n }\n}\n\nconst focus = (key: string | undefined) => {\n if (!key) return\n focused.value = key\n void nextTick(() => cards.get(key)?.focus())\n}\n\n// A card picked up with the keyboard moves to another list: keep the focus on it.\nwatch(\n () => state.value.picked,\n (picked) => {\n if (picked?.via !== 'keyboard') return\n\n void nextTick(() => {\n const element = cards.get(picked.key)\n\n if (element && document.activeElement !== element) element.focus()\n })\n },\n)\n\nconst onKeyDown = (key: string, event: KeyboardEvent) => {\n if (event.target !== event.currentTarget) return\n\n const result = controller.handleKey(key, event, direction.value)\n\n if (!result.handled) return\n\n event.preventDefault()\n\n if (result.open) controller.open(key)\n else focus(result.focus)\n}\n\nconst onSearch = (value: string) => {\n search.value = value\n controller.setSearch(value)\n}\n\nconst laneCount = (lane: string) =>\n state.value.columns.reduce((sum, column) => sum + kanbanCardsIn(column, lane).length, 0)\n</script>\n\n<template>\n <Card ref=\"root\" role=\"region\" :aria-labelledby=\"labelId\" class=\"gap-3 py-4\" data-slot=\"kanban\">\n <div class=\"flex flex-wrap items-center gap-2 px-4\" data-slot=\"kanban-toolbar\">\n <CardTitle v-if=\"schema.heading\" :id=\"labelId\" class=\"text-base\">{{\n schema.heading\n }}</CardTitle>\n <span v-else :id=\"labelId\" class=\"sr-only\">{{ t('kanban.label', {}, 'Kanban board') }}</span>\n <div class=\"ms-auto flex w-full flex-wrap items-center gap-2 sm:w-auto\">\n <Spinner v-if=\"state.loading\" class=\"size-4\" />\n <div v-if=\"schema.searchable\" class=\"relative w-full sm:w-64\">\n <SearchIcon\n class=\"text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n :model-value=\"search\"\n class=\"h-8 ps-8\"\n :placeholder=\"t('kanban.search_placeholder', {}, 'Search…')\"\n :aria-label=\"t('kanban.search', {}, 'Search cards')\"\n @update:model-value=\"onSearch\"\n />\n </div>\n <KanbanFilters v-if=\"filters\" :controller=\"controller\" :store=\"filters\" />\n </div>\n </div>\n <p :id=\"instructionsId\" class=\"sr-only\">\n {{\n t(\n 'kanban.instructions',\n {},\n 'Press Space to pick up a card. While it is picked up, use the arrow keys to move it, Space to drop it and Escape to cancel.',\n )\n }}\n </p>\n <div\n class=\"relative overflow-x-auto overscroll-x-contain px-4 pb-2\"\n data-slot=\"kanban-scroller\"\n >\n <div class=\"grid w-max min-w-full snap-x gap-3\" :style=\"{ gridTemplateColumns: template }\">\n <KanbanColumnHeader\n v-for=\"column in state.columns\"\n :id=\"`${labelId}-column-${column.key}`\"\n :key=\"column.key\"\n :column=\"column\"\n :collapsed=\"state.collapsed.has(column.key)\"\n :creatable=\"Boolean(column.creatable && schema.createAction)\"\n :filtered=\"filtered\"\n @toggle=\"controller.toggleColumn(column.key)\"\n @create=\"controller.create(column.key)\"\n />\n <template v-for=\"lane in lanes\" :key=\"lane?.key ?? '__board'\">\n <div\n v-if=\"lane\"\n class=\"flex items-center gap-2 pt-2\"\n style=\"grid-column: 1 / -1\"\n data-slot=\"kanban-lane\"\n :data-lane=\"lane.key\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-expanded=\"!state.collapsedLanes.has(lane.key)\"\n :aria-label=\"\n state.collapsedLanes.has(lane.key)\n ? t('kanban.expand_lane', { lane: lane.label }, 'Expand row :lane')\n : t('kanban.collapse_lane', { lane: lane.label }, 'Collapse row :lane')\n \"\n @click=\"controller.toggleLane(lane.key)\"\n >\n <ChevronRightIcon\n :class=\"\n cn(\n 'transition-transform rtl:rotate-180',\n !state.collapsedLanes.has(lane.key) && 'rotate-90 rtl:rotate-90',\n )\n \"\n aria-hidden=\"true\"\n />\n </Button>\n <Avatar v-if=\"lane.avatar\" class=\"size-6\">\n <AvatarImage :src=\"lane.avatar\" alt=\"\" />\n <AvatarFallback>{{ kanbanInitials(lane.label) }}</AvatarFallback>\n </Avatar>\n <Icon v-else-if=\"lane.icon\" :name=\"lane.icon\" class=\"text-muted-foreground size-4\" />\n <span :id=\"`${labelId}-lane-${lane.key}`\" class=\"text-sm font-semibold\">{{\n lane.label\n }}</span>\n <Badge variant=\"secondary\" class=\"h-5 px-1.5 tabular-nums\">{{\n laneCount(lane.key)\n }}</Badge>\n </div>\n <template v-if=\"!lane || !state.collapsedLanes.has(lane.key)\">\n <ul\n v-for=\"column in state.columns\"\n :key=\"column.key\"\n role=\"list\"\n :aria-labelledby=\"\n [\n `${labelId}-column-${column.key}`,\n lane ? `${labelId}-lane-${lane.key}` : undefined,\n ]\n .filter(Boolean)\n .join(' ')\n \"\n data-slot=\"kanban-dropzone\"\n :data-column=\"column.key\"\n :data-lane=\"lane?.key\"\n :data-refused=\"state.picked && state.refused?.column === column.key ? '' : undefined\"\n :class=\"\n cn(\n 'bg-muted/40 flex min-h-24 flex-col gap-2 rounded-lg p-2',\n lane === null && 'max-h-[70vh] overflow-y-auto',\n )\n \"\n >\n <template v-if=\"!state.collapsed.has(column.key)\">\n <KanbanCard\n v-for=\"card in kanbanCardsIn(column, lane?.key ?? null)\"\n :key=\"card.key\"\n :card=\"card\"\n :board=\"schema\"\n :token=\"page.token\"\n :current=\"current === card.key\"\n :picked=\"state.picked?.key === card.key ? state.picked.via : undefined\"\n :saving=\"state.saving.has(card.key)\"\n :described-by=\"instructionsId\"\n :set-ref=\"setCard(card.key)\"\n @focus=\"focused = card.key\"\n @keydown=\"onKeyDown(card.key, $event)\"\n @open=\"controller.open(card.key)\"\n />\n <li\n v-if=\"kanbanCardsIn(column, lane?.key ?? null).length === 0\"\n class=\"text-muted-foreground rounded-md border border-dashed px-2 py-6 text-center text-xs\"\n data-slot=\"kanban-empty\"\n >\n {{\n filtered\n ? t('kanban.no_results', {}, 'No cards match')\n : (column.emptyState ?? t('kanban.empty', {}, 'No cards'))\n }}\n </li>\n <li\n v-if=\"lane === null && column.total > column.cards.length\"\n class=\"text-muted-foreground px-2 text-center text-xs\"\n >\n {{\n t(\n 'kanban.more_cards',\n { count: column.total - column.cards.length },\n '+:count more',\n )\n }}\n </li>\n </template>\n </ul>\n </template>\n </template>\n </div>\n </div>\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\">{{ state.announcement }}</div>\n </Card>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KanbanBoard.vue.d.ts","sourceRoot":"","sources":["../../../src/components/kanban/KanbanBoard.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"KanbanBoard.vue.d.ts","sourceRoot":"","sources":["../../../src/components/kanban/KanbanBoard.vue"],"names":[],"mappings":"AA8VA,OAAO,KAAK,EAAqB,YAAY,EAAE,MAAM,eAAe,CAAA;AAgCpE;;;GAGG;AACH,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;;AAmrB3C,wBAMG"}
|
|
@@ -66,8 +66,11 @@ var F = {
|
|
|
66
66
|
}), _e(() => {
|
|
67
67
|
Y?.(), X?.(), H.destroy(), U?.destroy();
|
|
68
68
|
});
|
|
69
|
-
let Z = m(() => (W.value.columns, H.schema)), Me = m(() => (W.value.columns, H.lanes())), Q = m(() => W.value.search !== "" || pe(W.value.filters) > 0), $ = m(() => W.value.columns.flatMap((e) => e.cards.map((e) => e.key))), Ne = m(() => q.value !== null && $.value.includes(q.value) ? q.value : $.value[0] ?? null), Pe = m(() => W.value.columns.map((e) => W.value.collapsed.has(e.key) ? "3.25rem" : "minmax(16rem, 20rem)").join(" ")), Fe = (e) =>
|
|
70
|
-
|
|
69
|
+
let Z = m(() => (W.value.columns, H.schema)), Me = m(() => (W.value.columns, H.lanes())), Q = m(() => W.value.search !== "" || pe(W.value.filters) > 0), $ = m(() => W.value.columns.flatMap((e) => e.cards.map((e) => e.key))), Ne = m(() => q.value !== null && $.value.includes(q.value) ? q.value : $.value[0] ?? null), Pe = m(() => W.value.columns.map((e) => W.value.collapsed.has(e.key) ? "3.25rem" : "minmax(16rem, 20rem)").join(" ")), Fe = (e) => {
|
|
70
|
+
let t = null;
|
|
71
|
+
return (n) => {
|
|
72
|
+
n instanceof HTMLElement ? (t = n, K.set(e, n)) : t !== null && (K.get(e) === t && K.delete(e), t = null);
|
|
73
|
+
};
|
|
71
74
|
}, Ie = (e) => {
|
|
72
75
|
e && (q.value = e, S(() => K.get(e)?.focus()));
|
|
73
76
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KanbanBoard.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Card","_unref","_withCtx","_createElementVNode","CardTitle","_createTextVNode","_toDisplayString","_createElementBlock","Spinner","_createCommentVNode","_createVNode","Input","KanbanFilters","_normalizeStyle","_Fragment","_renderList","KanbanColumnHeader","Button","_normalizeClass","Avatar","AvatarImage","AvatarFallback","Icon","Badge","KanbanCard","Icon_default","Badge_default","Button_default","Spinner_default","Input_default","Card_default","Avatar_default","AvatarFallback_default","AvatarImage_default","CardTitle_default","KanbanCard_default","KanbanColumnHeader_default","KanbanFilters_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","KanbanBoard_vue_vue_type_script_setup_true_lang_default","props","__props","runner","useActionRunner","page","usePageActionContext","panel","usePanel","t","useT","direction","useDirection","labelId","useId","instructionsId","controller","KanbanController","toRaw","notifications","showToast","notification","clientErrorNotification","message","router","url","filters","createKanbanFiltersStore","state","useStore","root","ref","cards","focused","search","detach","stopPolling","watch","board","value","onMounted","element","attachKanbanPointer","onBeforeUnmount","schema","computed","lanes","filtered","kanbanActiveFilters","keys","column","card","current","template","setCard","key","focus","nextTick","picked","onKeyDown","event","result","onSearch","laneCount","sum","kanbanCardsIn","lane","openBlock","createBlock","unref","withCtx","createElementVNode","createTextVNode","toDisplayString","createElementBlock","createCommentVNode","createVNode","SearchIcon","normalizeStyle","Fragment","renderList","ChevronRightIcon","normalizeClass","cn","kanbanInitials","$event"],"sources":["../../../src/components/kanban/KanbanBoard.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { KanbanEnvironment, KanbanSchema } from '@alfakit/core'\nimport {\n KanbanController,\n attachKanbanPointer,\n clientErrorNotification,\n createKanbanFiltersStore,\n kanbanActiveFilters,\n kanbanCardsIn,\n kanbanInitials,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { ChevronRightIcon, SearchIcon } from '@lucide/vue'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, toRaw, useId, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useActionRunner, useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { showToast } from '../notifications/flash-toasts'\nimport Avatar from '../ui/Avatar.vue'\nimport AvatarFallback from '../ui/AvatarFallback.vue'\nimport AvatarImage from '../ui/AvatarImage.vue'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\nimport Card from '../ui/Card.vue'\nimport CardTitle from '../ui/CardTitle.vue'\nimport Input from '../ui/Input.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport KanbanCard from './KanbanCard.vue'\nimport KanbanColumnHeader from './KanbanColumnHeader.vue'\nimport KanbanFilters from './KanbanFilters.vue'\n\n/**\n * Cards move by dragging (mouse, pen, touch) or with the keyboard, and every move is\n * saved in one request.\n */\nconst props = defineProps<{ board: KanbanSchema }>()\n\nconst runner = useActionRunner()\nconst page = usePageActionContext()\nconst panel = usePanel()\nconst t = useT()\nconst direction = useDirection()\nconst labelId = useId()\nconst instructionsId = useId()\n\nconst environment = (): KanbanEnvironment => ({\n runner,\n token: page.token,\n t,\n notify: (notifications) => notifications.forEach((notification) => showToast(notification)),\n error: (message) => showToast(clientErrorNotification('kanban', message)),\n visit: (url) => router.visit(url),\n})\n\nconst controller = new KanbanController(toRaw(props.board), environment())\nconst filters = createKanbanFiltersStore(\n toRaw(props.board),\n page.token,\n panel.value.endpoints.schemaOptions,\n)\nconst state = useStore(controller.store)\nconst root = ref<{ $el: HTMLElement } | null>(null)\nconst cards = new Map<string, HTMLElement>()\nconst focused = ref<string | null>(null)\nconst search = ref(state.value.search)\nlet detach: (() => void) | null = null\nlet stopPolling: (() => void) | null = null\n\nwatch(\n () => props.board,\n (board) => controller.setBoard(toRaw(board)),\n)\nwatch(\n () => state.value.search,\n (value) => {\n if (value !== search.value) search.value = value\n },\n)\n\nonMounted(() => {\n const element = root.value?.$el\n\n if (element instanceof HTMLElement) detach = attachKanbanPointer(element, controller)\n\n stopPolling = controller.startPolling()\n})\n\nonBeforeUnmount(() => {\n detach?.()\n stopPolling?.()\n controller.destroy()\n filters?.destroy()\n})\n\nconst schema = computed(() => {\n // Re-read when the state changes (the controller swaps its schema with the board).\n void state.value.columns\n\n return controller.schema\n})\nconst lanes = computed(() => {\n void state.value.columns\n\n return controller.lanes()\n})\nconst filtered = computed(\n () => state.value.search !== '' || kanbanActiveFilters(state.value.filters) > 0,\n)\nconst keys = computed(() =>\n state.value.columns.flatMap((column) => column.cards.map((card) => card.key)),\n)\nconst current = computed(() =>\n focused.value !== null && keys.value.includes(focused.value)\n ? focused.value\n : (keys.value[0] ?? null),\n)\nconst template = computed(() =>\n state.value.columns\n .map((column) => (state.value.collapsed.has(column.key) ? '3.25rem' : 'minmax(16rem, 20rem)'))\n .join(' '),\n)\n\nconst setCard = (key: string) => (element: unknown) => {\n if (element instanceof HTMLElement) cards.set(key, element)\n else cards.delete(key)\n}\n\nconst focus = (key: string | undefined) => {\n if (!key) return\n focused.value = key\n void nextTick(() => cards.get(key)?.focus())\n}\n\n// A card picked up with the keyboard moves to another list: keep the focus on it.\nwatch(\n () => state.value.picked,\n (picked) => {\n if (picked?.via !== 'keyboard') return\n\n void nextTick(() => {\n const element = cards.get(picked.key)\n\n if (element && document.activeElement !== element) element.focus()\n })\n },\n)\n\nconst onKeyDown = (key: string, event: KeyboardEvent) => {\n if (event.target !== event.currentTarget) return\n\n const result = controller.handleKey(key, event, direction.value)\n\n if (!result.handled) return\n\n event.preventDefault()\n\n if (result.open) controller.open(key)\n else focus(result.focus)\n}\n\nconst onSearch = (value: string) => {\n search.value = value\n controller.setSearch(value)\n}\n\nconst laneCount = (lane: string) =>\n state.value.columns.reduce((sum, column) => sum + kanbanCardsIn(column, lane).length, 0)\n</script>\n\n<template>\n <Card ref=\"root\" role=\"region\" :aria-labelledby=\"labelId\" class=\"gap-3 py-4\" data-slot=\"kanban\">\n <div class=\"flex flex-wrap items-center gap-2 px-4\" data-slot=\"kanban-toolbar\">\n <CardTitle v-if=\"schema.heading\" :id=\"labelId\" class=\"text-base\">{{\n schema.heading\n }}</CardTitle>\n <span v-else :id=\"labelId\" class=\"sr-only\">{{ t('kanban.label', {}, 'Kanban board') }}</span>\n <div class=\"ms-auto flex w-full flex-wrap items-center gap-2 sm:w-auto\">\n <Spinner v-if=\"state.loading\" class=\"size-4\" />\n <div v-if=\"schema.searchable\" class=\"relative w-full sm:w-64\">\n <SearchIcon\n class=\"text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n :model-value=\"search\"\n class=\"h-8 ps-8\"\n :placeholder=\"t('kanban.search_placeholder', {}, 'Search…')\"\n :aria-label=\"t('kanban.search', {}, 'Search cards')\"\n @update:model-value=\"onSearch\"\n />\n </div>\n <KanbanFilters v-if=\"filters\" :controller=\"controller\" :store=\"filters\" />\n </div>\n </div>\n <p :id=\"instructionsId\" class=\"sr-only\">\n {{\n t(\n 'kanban.instructions',\n {},\n 'Press Space to pick up a card. While it is picked up, use the arrow keys to move it, Space to drop it and Escape to cancel.',\n )\n }}\n </p>\n <div\n class=\"relative overflow-x-auto overscroll-x-contain px-4 pb-2\"\n data-slot=\"kanban-scroller\"\n >\n <div class=\"grid w-max min-w-full snap-x gap-3\" :style=\"{ gridTemplateColumns: template }\">\n <KanbanColumnHeader\n v-for=\"column in state.columns\"\n :id=\"`${labelId}-column-${column.key}`\"\n :key=\"column.key\"\n :column=\"column\"\n :collapsed=\"state.collapsed.has(column.key)\"\n :creatable=\"Boolean(column.creatable && schema.createAction)\"\n :filtered=\"filtered\"\n @toggle=\"controller.toggleColumn(column.key)\"\n @create=\"controller.create(column.key)\"\n />\n <template v-for=\"lane in lanes\" :key=\"lane?.key ?? '__board'\">\n <div\n v-if=\"lane\"\n class=\"flex items-center gap-2 pt-2\"\n style=\"grid-column: 1 / -1\"\n data-slot=\"kanban-lane\"\n :data-lane=\"lane.key\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-expanded=\"!state.collapsedLanes.has(lane.key)\"\n :aria-label=\"\n state.collapsedLanes.has(lane.key)\n ? t('kanban.expand_lane', { lane: lane.label }, 'Expand row :lane')\n : t('kanban.collapse_lane', { lane: lane.label }, 'Collapse row :lane')\n \"\n @click=\"controller.toggleLane(lane.key)\"\n >\n <ChevronRightIcon\n :class=\"\n cn(\n 'transition-transform rtl:rotate-180',\n !state.collapsedLanes.has(lane.key) && 'rotate-90 rtl:rotate-90',\n )\n \"\n aria-hidden=\"true\"\n />\n </Button>\n <Avatar v-if=\"lane.avatar\" class=\"size-6\">\n <AvatarImage :src=\"lane.avatar\" alt=\"\" />\n <AvatarFallback>{{ kanbanInitials(lane.label) }}</AvatarFallback>\n </Avatar>\n <Icon v-else-if=\"lane.icon\" :name=\"lane.icon\" class=\"text-muted-foreground size-4\" />\n <span :id=\"`${labelId}-lane-${lane.key}`\" class=\"text-sm font-semibold\">{{\n lane.label\n }}</span>\n <Badge variant=\"secondary\" class=\"h-5 px-1.5 tabular-nums\">{{\n laneCount(lane.key)\n }}</Badge>\n </div>\n <template v-if=\"!lane || !state.collapsedLanes.has(lane.key)\">\n <ul\n v-for=\"column in state.columns\"\n :key=\"column.key\"\n role=\"list\"\n :aria-labelledby=\"\n [\n `${labelId}-column-${column.key}`,\n lane ? `${labelId}-lane-${lane.key}` : undefined,\n ]\n .filter(Boolean)\n .join(' ')\n \"\n data-slot=\"kanban-dropzone\"\n :data-column=\"column.key\"\n :data-lane=\"lane?.key\"\n :data-refused=\"state.picked && state.refused?.column === column.key ? '' : undefined\"\n :class=\"\n cn(\n 'bg-muted/40 flex min-h-24 flex-col gap-2 rounded-lg p-2',\n lane === null && 'max-h-[70vh] overflow-y-auto',\n )\n \"\n >\n <template v-if=\"!state.collapsed.has(column.key)\">\n <KanbanCard\n v-for=\"card in kanbanCardsIn(column, lane?.key ?? null)\"\n :key=\"card.key\"\n :card=\"card\"\n :board=\"schema\"\n :token=\"page.token\"\n :current=\"current === card.key\"\n :picked=\"state.picked?.key === card.key ? state.picked.via : undefined\"\n :saving=\"state.saving.has(card.key)\"\n :described-by=\"instructionsId\"\n :set-ref=\"setCard(card.key)\"\n @focus=\"focused = card.key\"\n @keydown=\"onKeyDown(card.key, $event)\"\n @open=\"controller.open(card.key)\"\n />\n <li\n v-if=\"kanbanCardsIn(column, lane?.key ?? null).length === 0\"\n class=\"text-muted-foreground rounded-md border border-dashed px-2 py-6 text-center text-xs\"\n data-slot=\"kanban-empty\"\n >\n {{\n filtered\n ? t('kanban.no_results', {}, 'No cards match')\n : (column.emptyState ?? t('kanban.empty', {}, 'No cards'))\n }}\n </li>\n <li\n v-if=\"lane === null && column.total > column.cards.length\"\n class=\"text-muted-foreground px-2 text-center text-xs\"\n >\n {{\n t(\n 'kanban.more_cards',\n { count: column.total - column.cards.length },\n '+:count more',\n )\n }}\n </li>\n </template>\n </ul>\n </template>\n </template>\n </div>\n </div>\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\">{{ state.announcement }}</div>\n </Card>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KanbanBoard.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Card","_unref","_withCtx","_createElementVNode","CardTitle","_createTextVNode","_toDisplayString","_createElementBlock","Spinner","_createCommentVNode","_createVNode","Input","KanbanFilters","_normalizeStyle","_Fragment","_renderList","KanbanColumnHeader","Button","_normalizeClass","Avatar","AvatarImage","AvatarFallback","Icon","Badge","KanbanCard","Icon_default","Badge_default","Button_default","Spinner_default","Input_default","Card_default","Avatar_default","AvatarFallback_default","AvatarImage_default","CardTitle_default","KanbanCard_default","KanbanColumnHeader_default","KanbanFilters_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","KanbanBoard_vue_vue_type_script_setup_true_lang_default","props","__props","runner","useActionRunner","page","usePageActionContext","panel","usePanel","t","useT","direction","useDirection","labelId","useId","instructionsId","controller","KanbanController","toRaw","notifications","showToast","notification","clientErrorNotification","message","router","url","filters","createKanbanFiltersStore","state","useStore","root","ref","cards","focused","search","detach","stopPolling","watch","board","value","onMounted","element","attachKanbanPointer","onBeforeUnmount","schema","computed","lanes","filtered","kanbanActiveFilters","keys","column","card","current","template","setCard","own","key","focus","nextTick","picked","onKeyDown","event","result","onSearch","laneCount","sum","kanbanCardsIn","lane","openBlock","createBlock","unref","withCtx","createElementVNode","createTextVNode","toDisplayString","createElementBlock","createCommentVNode","createVNode","SearchIcon","normalizeStyle","Fragment","renderList","ChevronRightIcon","normalizeClass","cn","kanbanInitials","$event"],"sources":["../../../src/components/kanban/KanbanBoard.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { KanbanEnvironment, KanbanSchema } from '@alfakit/core'\nimport {\n KanbanController,\n attachKanbanPointer,\n clientErrorNotification,\n createKanbanFiltersStore,\n kanbanActiveFilters,\n kanbanCardsIn,\n kanbanInitials,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/vue3'\nimport { ChevronRightIcon, SearchIcon } from '@lucide/vue'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, toRaw, useId, watch } from 'vue'\nimport { useStore } from '../../composables/use-store'\nimport { useActionRunner, useDirection, usePanel, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { usePageActionContext } from '../actions/action-context'\nimport { showToast } from '../notifications/flash-toasts'\nimport Avatar from '../ui/Avatar.vue'\nimport AvatarFallback from '../ui/AvatarFallback.vue'\nimport AvatarImage from '../ui/AvatarImage.vue'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\nimport Card from '../ui/Card.vue'\nimport CardTitle from '../ui/CardTitle.vue'\nimport Input from '../ui/Input.vue'\nimport Spinner from '../ui/Spinner.vue'\nimport KanbanCard from './KanbanCard.vue'\nimport KanbanColumnHeader from './KanbanColumnHeader.vue'\nimport KanbanFilters from './KanbanFilters.vue'\n\n/**\n * Cards move by dragging (mouse, pen, touch) or with the keyboard, and every move is\n * saved in one request.\n */\nconst props = defineProps<{ board: KanbanSchema }>()\n\nconst runner = useActionRunner()\nconst page = usePageActionContext()\nconst panel = usePanel()\nconst t = useT()\nconst direction = useDirection()\nconst labelId = useId()\nconst instructionsId = useId()\n\nconst environment = (): KanbanEnvironment => ({\n runner,\n token: page.token,\n t,\n notify: (notifications) => notifications.forEach((notification) => showToast(notification)),\n error: (message) => showToast(clientErrorNotification('kanban', message)),\n visit: (url) => router.visit(url),\n})\n\nconst controller = new KanbanController(toRaw(props.board), environment())\nconst filters = createKanbanFiltersStore(\n toRaw(props.board),\n page.token,\n panel.value.endpoints.schemaOptions,\n)\nconst state = useStore(controller.store)\nconst root = ref<{ $el: HTMLElement } | null>(null)\nconst cards = new Map<string, HTMLElement>()\nconst focused = ref<string | null>(null)\nconst search = ref(state.value.search)\nlet detach: (() => void) | null = null\nlet stopPolling: (() => void) | null = null\n\nwatch(\n () => props.board,\n (board) => controller.setBoard(toRaw(board)),\n)\nwatch(\n () => state.value.search,\n (value) => {\n if (value !== search.value) search.value = value\n },\n)\n\nonMounted(() => {\n const element = root.value?.$el\n\n if (element instanceof HTMLElement) detach = attachKanbanPointer(element, controller)\n\n stopPolling = controller.startPolling()\n})\n\nonBeforeUnmount(() => {\n detach?.()\n stopPolling?.()\n controller.destroy()\n filters?.destroy()\n})\n\nconst schema = computed(() => {\n // Re-read when the state changes (the controller swaps its schema with the board).\n void state.value.columns\n\n return controller.schema\n})\nconst lanes = computed(() => {\n void state.value.columns\n\n return controller.lanes()\n})\nconst filtered = computed(\n () => state.value.search !== '' || kanbanActiveFilters(state.value.filters) > 0,\n)\nconst keys = computed(() =>\n state.value.columns.flatMap((column) => column.cards.map((card) => card.key)),\n)\nconst current = computed(() =>\n focused.value !== null && keys.value.includes(focused.value)\n ? focused.value\n : (keys.value[0] ?? null),\n)\nconst template = computed(() =>\n state.value.columns\n .map((column) => (state.value.collapsed.has(column.key) ? '3.25rem' : 'minmax(16rem, 20rem)'))\n .join(' '),\n)\n\n// A card moved to another column is mounted there before its old element is unmounted, so\n// an unmount only forgets the element it registered itself (else the moved card would lose\n// its entry and the keyboard focus).\nconst setCard = (key: string) => {\n let own: HTMLElement | null = null\n\n return (element: unknown) => {\n if (element instanceof HTMLElement) {\n own = element\n cards.set(key, element)\n } else if (own !== null) {\n if (cards.get(key) === own) cards.delete(key)\n own = null\n }\n }\n}\n\nconst focus = (key: string | undefined) => {\n if (!key) return\n focused.value = key\n void nextTick(() => cards.get(key)?.focus())\n}\n\n// A card picked up with the keyboard moves to another list: keep the focus on it.\nwatch(\n () => state.value.picked,\n (picked) => {\n if (picked?.via !== 'keyboard') return\n\n void nextTick(() => {\n const element = cards.get(picked.key)\n\n if (element && document.activeElement !== element) element.focus()\n })\n },\n)\n\nconst onKeyDown = (key: string, event: KeyboardEvent) => {\n if (event.target !== event.currentTarget) return\n\n const result = controller.handleKey(key, event, direction.value)\n\n if (!result.handled) return\n\n event.preventDefault()\n\n if (result.open) controller.open(key)\n else focus(result.focus)\n}\n\nconst onSearch = (value: string) => {\n search.value = value\n controller.setSearch(value)\n}\n\nconst laneCount = (lane: string) =>\n state.value.columns.reduce((sum, column) => sum + kanbanCardsIn(column, lane).length, 0)\n</script>\n\n<template>\n <Card ref=\"root\" role=\"region\" :aria-labelledby=\"labelId\" class=\"gap-3 py-4\" data-slot=\"kanban\">\n <div class=\"flex flex-wrap items-center gap-2 px-4\" data-slot=\"kanban-toolbar\">\n <CardTitle v-if=\"schema.heading\" :id=\"labelId\" class=\"text-base\">{{\n schema.heading\n }}</CardTitle>\n <span v-else :id=\"labelId\" class=\"sr-only\">{{ t('kanban.label', {}, 'Kanban board') }}</span>\n <div class=\"ms-auto flex w-full flex-wrap items-center gap-2 sm:w-auto\">\n <Spinner v-if=\"state.loading\" class=\"size-4\" />\n <div v-if=\"schema.searchable\" class=\"relative w-full sm:w-64\">\n <SearchIcon\n class=\"text-muted-foreground pointer-events-none absolute start-2.5 top-1/2 size-4 -translate-y-1/2\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n :model-value=\"search\"\n class=\"h-8 ps-8\"\n :placeholder=\"t('kanban.search_placeholder', {}, 'Search…')\"\n :aria-label=\"t('kanban.search', {}, 'Search cards')\"\n @update:model-value=\"onSearch\"\n />\n </div>\n <KanbanFilters v-if=\"filters\" :controller=\"controller\" :store=\"filters\" />\n </div>\n </div>\n <p :id=\"instructionsId\" class=\"sr-only\">\n {{\n t(\n 'kanban.instructions',\n {},\n 'Press Space to pick up a card. While it is picked up, use the arrow keys to move it, Space to drop it and Escape to cancel.',\n )\n }}\n </p>\n <div\n class=\"relative overflow-x-auto overscroll-x-contain px-4 pb-2\"\n data-slot=\"kanban-scroller\"\n >\n <div class=\"grid w-max min-w-full snap-x gap-3\" :style=\"{ gridTemplateColumns: template }\">\n <KanbanColumnHeader\n v-for=\"column in state.columns\"\n :id=\"`${labelId}-column-${column.key}`\"\n :key=\"column.key\"\n :column=\"column\"\n :collapsed=\"state.collapsed.has(column.key)\"\n :creatable=\"Boolean(column.creatable && schema.createAction)\"\n :filtered=\"filtered\"\n @toggle=\"controller.toggleColumn(column.key)\"\n @create=\"controller.create(column.key)\"\n />\n <template v-for=\"lane in lanes\" :key=\"lane?.key ?? '__board'\">\n <div\n v-if=\"lane\"\n class=\"flex items-center gap-2 pt-2\"\n style=\"grid-column: 1 / -1\"\n data-slot=\"kanban-lane\"\n :data-lane=\"lane.key\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n :aria-expanded=\"!state.collapsedLanes.has(lane.key)\"\n :aria-label=\"\n state.collapsedLanes.has(lane.key)\n ? t('kanban.expand_lane', { lane: lane.label }, 'Expand row :lane')\n : t('kanban.collapse_lane', { lane: lane.label }, 'Collapse row :lane')\n \"\n @click=\"controller.toggleLane(lane.key)\"\n >\n <ChevronRightIcon\n :class=\"\n cn(\n 'transition-transform rtl:rotate-180',\n !state.collapsedLanes.has(lane.key) && 'rotate-90 rtl:rotate-90',\n )\n \"\n aria-hidden=\"true\"\n />\n </Button>\n <Avatar v-if=\"lane.avatar\" class=\"size-6\">\n <AvatarImage :src=\"lane.avatar\" alt=\"\" />\n <AvatarFallback>{{ kanbanInitials(lane.label) }}</AvatarFallback>\n </Avatar>\n <Icon v-else-if=\"lane.icon\" :name=\"lane.icon\" class=\"text-muted-foreground size-4\" />\n <span :id=\"`${labelId}-lane-${lane.key}`\" class=\"text-sm font-semibold\">{{\n lane.label\n }}</span>\n <Badge variant=\"secondary\" class=\"h-5 px-1.5 tabular-nums\">{{\n laneCount(lane.key)\n }}</Badge>\n </div>\n <template v-if=\"!lane || !state.collapsedLanes.has(lane.key)\">\n <ul\n v-for=\"column in state.columns\"\n :key=\"column.key\"\n role=\"list\"\n :aria-labelledby=\"\n [\n `${labelId}-column-${column.key}`,\n lane ? `${labelId}-lane-${lane.key}` : undefined,\n ]\n .filter(Boolean)\n .join(' ')\n \"\n data-slot=\"kanban-dropzone\"\n :data-column=\"column.key\"\n :data-lane=\"lane?.key\"\n :data-refused=\"state.picked && state.refused?.column === column.key ? '' : undefined\"\n :class=\"\n cn(\n 'bg-muted/40 flex min-h-24 flex-col gap-2 rounded-lg p-2',\n lane === null && 'max-h-[70vh] overflow-y-auto',\n )\n \"\n >\n <template v-if=\"!state.collapsed.has(column.key)\">\n <KanbanCard\n v-for=\"card in kanbanCardsIn(column, lane?.key ?? null)\"\n :key=\"card.key\"\n :card=\"card\"\n :board=\"schema\"\n :token=\"page.token\"\n :current=\"current === card.key\"\n :picked=\"state.picked?.key === card.key ? state.picked.via : undefined\"\n :saving=\"state.saving.has(card.key)\"\n :described-by=\"instructionsId\"\n :set-ref=\"setCard(card.key)\"\n @focus=\"focused = card.key\"\n @keydown=\"onKeyDown(card.key, $event)\"\n @open=\"controller.open(card.key)\"\n />\n <li\n v-if=\"kanbanCardsIn(column, lane?.key ?? null).length === 0\"\n class=\"text-muted-foreground rounded-md border border-dashed px-2 py-6 text-center text-xs\"\n data-slot=\"kanban-empty\"\n >\n {{\n filtered\n ? t('kanban.no_results', {}, 'No cards match')\n : (column.emptyState ?? t('kanban.empty', {}, 'No cards'))\n }}\n </li>\n <li\n v-if=\"lane === null && column.total > column.cards.length\"\n class=\"text-muted-foreground px-2 text-center text-xs\"\n >\n {{\n t(\n 'kanban.more_cards',\n { count: column.total - column.cards.length },\n '+:count more',\n )\n }}\n </li>\n </template>\n </ul>\n </template>\n </template>\n </div>\n </div>\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\">{{ state.announcement }}</div>\n </Card>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KanbanColumnHeader.js","names":["_sfc_main","KanbanColumnHeader_vue_vue_type_script_setup_true_lang_default","KanbanColumnHeader_default"],"sources":["../../../src/components/kanban/KanbanColumnHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { KanbanColumnSchema } from '@alfakit/core'\nimport { kanbanWipState } from '@alfakit/core'\nimport { ChevronsLeftRightIcon, ChevronsRightLeftIcon, PlusIcon } from '@lucide/vue'\nimport { computed } from 'vue'\nimport { useT } from '../../context'\nimport { cssColor } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\n\nconst props = defineProps<{\n column: KanbanColumnSchema\n id: string\n collapsed: boolean\n creatable: boolean\n filtered: boolean\n}>()\nconst emit = defineEmits<{ toggle: []; create: [] }>()\nconst t = useT()\n\nconst wip = computed(() => kanbanWipState(props.column))\nconst shown = computed(() =>\n props.column.wipLimit !== undefined\n ? props.column.count\n : props.filtered\n ? props.column.total\n : props.column.count,\n)\nconst countLabel = computed(() => {\n const column = props.column\n\n if (column.wipLimit !== undefined) {\n return t('kanban.wip', { count: column.count, limit: column.wipLimit }, ':count of :limit')\n }\n\n return props.filtered && column.total !== column.count\n ? t(\n 'kanban.count_filtered',\n { shown: column.total, count: column.count },\n ':shown of :count cards',\n )\n :
|
|
1
|
+
{"version":3,"file":"KanbanColumnHeader.js","names":["_sfc_main","KanbanColumnHeader_vue_vue_type_script_setup_true_lang_default","KanbanColumnHeader_default"],"sources":["../../../src/components/kanban/KanbanColumnHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { KanbanColumnSchema } from '@alfakit/core'\nimport { kanbanWipState } from '@alfakit/core'\nimport { ChevronsLeftRightIcon, ChevronsRightLeftIcon, PlusIcon } from '@lucide/vue'\nimport { computed } from 'vue'\nimport { useChoice, useT } from '../../context'\nimport { cssColor } from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport Badge from '../ui/Badge.vue'\nimport Button from '../ui/Button.vue'\n\nconst props = defineProps<{\n column: KanbanColumnSchema\n id: string\n collapsed: boolean\n creatable: boolean\n filtered: boolean\n}>()\nconst emit = defineEmits<{ toggle: []; create: [] }>()\nconst t = useT()\nconst choice = useChoice()\n\nconst wip = computed(() => kanbanWipState(props.column))\nconst shown = computed(() =>\n props.column.wipLimit !== undefined\n ? props.column.count\n : props.filtered\n ? props.column.total\n : props.column.count,\n)\nconst countLabel = computed(() => {\n const column = props.column\n\n if (column.wipLimit !== undefined) {\n return t('kanban.wip', { count: column.count, limit: column.wipLimit }, ':count of :limit')\n }\n\n return props.filtered && column.total !== column.count\n ? t(\n 'kanban.count_filtered',\n { shown: column.total, count: column.count },\n ':shown of :count cards',\n )\n : choice('kanban.count', column.count, {}, '{1} :count card|[0,*] :count cards')\n})\nconst style = computed(() =>\n props.column.color ? { borderTopColor: cssColor(props.column.color) } : undefined,\n)\nconst toggleLabel = computed(() =>\n props.collapsed\n ? t('kanban.expand', { column: props.column.label }, 'Expand :column')\n : t('kanban.collapse', { column: props.column.label }, 'Collapse :column'),\n)\nconst addLabel = computed(() =>\n t('kanban.add_card', { column: props.column.label }, 'Add a card to :column'),\n)\n</script>\n\n<template>\n <div\n v-if=\"props.collapsed\"\n class=\"bg-muted/60 flex snap-start flex-col items-center gap-2 rounded-lg border border-t-4 px-1 py-2\"\n :style=\"style\"\n data-slot=\"kanban-column-header\"\n :data-column=\"props.column.key\"\n data-collapsed=\"\"\n :data-wip=\"wip ?? undefined\"\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"toggleLabel\"\n :aria-expanded=\"false\"\n @click=\"emit('toggle')\"\n >\n <ChevronsLeftRightIcon aria-hidden=\"true\" />\n </Button>\n <span class=\"text-muted-foreground text-xs tabular-nums\" :title=\"countLabel\">{{ shown }}</span>\n <h3 :id=\"props.id\" class=\"text-sm font-medium [writing-mode:vertical-rl]\">\n {{ props.column.label }}\n </h3>\n </div>\n <div\n v-else\n class=\"bg-muted/60 flex snap-start flex-col gap-1 rounded-lg border border-t-4 px-3 py-2\"\n :style=\"style\"\n data-slot=\"kanban-column-header\"\n :data-column=\"props.column.key\"\n :data-wip=\"wip ?? undefined\"\n >\n <div class=\"flex items-center gap-2\">\n <Icon\n v-if=\"props.column.icon\"\n :name=\"props.column.icon\"\n class=\"text-muted-foreground size-4\"\n />\n <h3 :id=\"props.id\" class=\"min-w-0 truncate text-sm font-semibold\">\n {{ props.column.label }}\n </h3>\n <Badge\n variant=\"secondary\"\n :class=\"\n cn(\n 'h-5 px-1.5 tabular-nums',\n wip === 'over' && 'bg-destructive/15 text-destructive',\n wip === 'full' && 'bg-warning/15 text-warning',\n )\n \"\n :title=\"countLabel\"\n >\n <span aria-hidden=\"true\">{{\n props.column.wipLimit !== undefined\n ? `${props.column.count}/${props.column.wipLimit}`\n : shown\n }}</span>\n <span class=\"sr-only\">{{ countLabel }}</span>\n </Badge>\n <div class=\"ms-auto flex items-center\">\n <Button\n v-if=\"props.creatable\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"addLabel\"\n :title=\"addLabel\"\n @click=\"emit('create')\"\n >\n <PlusIcon aria-hidden=\"true\" />\n </Button>\n <Button\n v-if=\"props.column.collapsible\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"toggleLabel\"\n :title=\"toggleLabel\"\n :aria-expanded=\"true\"\n @click=\"emit('toggle')\"\n >\n <ChevronsRightLeftIcon aria-hidden=\"true\" />\n </Button>\n </div>\n </div>\n <p v-if=\"props.column.description\" class=\"text-muted-foreground line-clamp-2 text-xs\">\n {{ props.column.description }}\n </p>\n <p v-if=\"wip === 'over'\" class=\"text-destructive text-xs\">\n {{\n choice(\n 'kanban.wip_over',\n props.column.wipLimit ?? 0,\n { limit: props.column.wipLimit ?? 0 },\n '{1} Over the limit of :limit card|[0,*] Over the limit of :limit cards',\n )\n }}\n </p>\n <p v-if=\"wip === 'full' && props.column.wipStrict\" class=\"text-muted-foreground text-xs\">\n {{ t('kanban.wip_full', {}, 'This column is full') }}\n </p>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KanbanColumnHeader.vue.d.ts","sourceRoot":"","sources":["../../../src/components/kanban/KanbanColumnHeader.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"KanbanColumnHeader.vue.d.ts","sourceRoot":"","sources":["../../../src/components/kanban/KanbanColumnHeader.vue"],"names":[],"mappings":"AAqKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAWvD,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,kBAAkB,CAAA;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAC;;;;;;;;AAiXF,wBAOG"}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cn as
|
|
3
|
-
import { cssColor as
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import { kanbanWipState as
|
|
8
|
-
import { computed as
|
|
9
|
-
import { ChevronsLeftRightIcon as
|
|
1
|
+
import { useChoice as e, useT as t } from "../../context.js";
|
|
2
|
+
import { cn as n } from "../../lib/utils.js";
|
|
3
|
+
import { cssColor as r } from "../../lib/colors.js";
|
|
4
|
+
import i from "../../lib/Icon.js";
|
|
5
|
+
import a from "../ui/Badge2.js";
|
|
6
|
+
import o from "../ui/Button2.js";
|
|
7
|
+
import { kanbanWipState as s } from "@alfakit/core";
|
|
8
|
+
import { computed as c, createBlock as l, createCommentVNode as u, createElementBlock as d, createElementVNode as f, createVNode as p, defineComponent as m, normalizeClass as h, normalizeStyle as g, openBlock as _, toDisplayString as v, unref as y, withCtx as b } from "vue";
|
|
9
|
+
import { ChevronsLeftRightIcon as x, ChevronsRightLeftIcon as S, PlusIcon as C } from "@lucide/vue";
|
|
10
10
|
//#region src/components/kanban/KanbanColumnHeader.vue?vue&type=script&setup=true&lang.ts
|
|
11
|
-
var
|
|
11
|
+
var w = ["data-column", "data-wip"], T = ["title"], E = ["id"], D = ["data-column", "data-wip"], O = { class: "flex items-center gap-2" }, k = ["id"], A = { "aria-hidden": "true" }, j = { class: "sr-only" }, M = { class: "ms-auto flex items-center" }, N = {
|
|
12
12
|
key: 0,
|
|
13
13
|
class: "text-muted-foreground line-clamp-2 text-xs"
|
|
14
|
-
},
|
|
14
|
+
}, P = {
|
|
15
15
|
key: 1,
|
|
16
16
|
class: "text-destructive text-xs"
|
|
17
|
-
},
|
|
17
|
+
}, F = {
|
|
18
18
|
key: 2,
|
|
19
19
|
class: "text-muted-foreground text-xs"
|
|
20
|
-
},
|
|
20
|
+
}, I = /*@__PURE__*/ m({
|
|
21
21
|
__name: "KanbanColumnHeader",
|
|
22
22
|
props: {
|
|
23
23
|
column: {},
|
|
@@ -27,103 +27,103 @@ var C = ["data-column", "data-wip"], w = ["title"], T = ["id"], E = ["data-colum
|
|
|
27
27
|
filtered: { type: Boolean }
|
|
28
28
|
},
|
|
29
29
|
emits: ["toggle", "create"],
|
|
30
|
-
setup(
|
|
31
|
-
let
|
|
32
|
-
let e =
|
|
33
|
-
return e.wipLimit === void 0 ?
|
|
30
|
+
setup(m, { emit: I }) {
|
|
31
|
+
let L = m, R = I, z = t(), B = e(), V = c(() => s(L.column)), H = c(() => L.column.wipLimit === void 0 && L.filtered ? L.column.total : L.column.count), U = c(() => {
|
|
32
|
+
let e = L.column;
|
|
33
|
+
return e.wipLimit === void 0 ? L.filtered && e.total !== e.count ? z("kanban.count_filtered", {
|
|
34
34
|
shown: e.total,
|
|
35
35
|
count: e.count
|
|
36
|
-
}, ":shown of :count cards") :
|
|
36
|
+
}, ":shown of :count cards") : B("kanban.count", e.count, {}, "{1} :count card|[0,*] :count cards") : z("kanban.wip", {
|
|
37
37
|
count: e.count,
|
|
38
38
|
limit: e.wipLimit
|
|
39
39
|
}, ":count of :limit");
|
|
40
|
-
}),
|
|
41
|
-
return (e,
|
|
40
|
+
}), W = c(() => L.column.color ? { borderTopColor: r(L.column.color) } : void 0), G = c(() => L.collapsed ? z("kanban.expand", { column: L.column.label }, "Expand :column") : z("kanban.collapse", { column: L.column.label }, "Collapse :column")), K = c(() => z("kanban.add_card", { column: L.column.label }, "Add a card to :column"));
|
|
41
|
+
return (e, t) => L.collapsed ? (_(), d("div", {
|
|
42
42
|
key: 0,
|
|
43
43
|
class: "bg-muted/60 flex snap-start flex-col items-center gap-2 rounded-lg border border-t-4 px-1 py-2",
|
|
44
|
-
style:
|
|
44
|
+
style: g(W.value),
|
|
45
45
|
"data-slot": "kanban-column-header",
|
|
46
|
-
"data-column":
|
|
46
|
+
"data-column": L.column.key,
|
|
47
47
|
"data-collapsed": "",
|
|
48
|
-
"data-wip":
|
|
48
|
+
"data-wip": V.value ?? void 0
|
|
49
49
|
}, [
|
|
50
|
-
|
|
50
|
+
p(o, {
|
|
51
51
|
type: "button",
|
|
52
52
|
variant: "ghost",
|
|
53
53
|
size: "icon-xs",
|
|
54
|
-
"aria-label":
|
|
54
|
+
"aria-label": G.value,
|
|
55
55
|
"aria-expanded": !1,
|
|
56
|
-
onClick:
|
|
56
|
+
onClick: t[0] ||= (e) => R("toggle")
|
|
57
57
|
}, {
|
|
58
|
-
default:
|
|
58
|
+
default: b(() => [p(y(x), { "aria-hidden": "true" })]),
|
|
59
59
|
_: 1
|
|
60
60
|
}, 8, ["aria-label"]),
|
|
61
|
-
|
|
61
|
+
f("span", {
|
|
62
62
|
class: "text-muted-foreground text-xs tabular-nums",
|
|
63
|
-
title:
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
id:
|
|
63
|
+
title: U.value
|
|
64
|
+
}, v(H.value), 9, T),
|
|
65
|
+
f("h3", {
|
|
66
|
+
id: L.id,
|
|
67
67
|
class: "text-sm font-medium [writing-mode:vertical-rl]"
|
|
68
|
-
},
|
|
69
|
-
], 12,
|
|
68
|
+
}, v(L.column.label), 9, E)
|
|
69
|
+
], 12, w)) : (_(), d("div", {
|
|
70
70
|
key: 1,
|
|
71
71
|
class: "bg-muted/60 flex snap-start flex-col gap-1 rounded-lg border border-t-4 px-3 py-2",
|
|
72
|
-
style:
|
|
72
|
+
style: g(W.value),
|
|
73
73
|
"data-slot": "kanban-column-header",
|
|
74
|
-
"data-column":
|
|
75
|
-
"data-wip":
|
|
74
|
+
"data-column": L.column.key,
|
|
75
|
+
"data-wip": V.value ?? void 0
|
|
76
76
|
}, [
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
f("div", O, [
|
|
78
|
+
L.column.icon ? (_(), l(y(i), {
|
|
79
79
|
key: 0,
|
|
80
|
-
name:
|
|
80
|
+
name: L.column.icon,
|
|
81
81
|
class: "text-muted-foreground size-4"
|
|
82
|
-
}, null, 8, ["name"])) :
|
|
83
|
-
|
|
84
|
-
id:
|
|
82
|
+
}, null, 8, ["name"])) : u("", !0),
|
|
83
|
+
f("h3", {
|
|
84
|
+
id: L.id,
|
|
85
85
|
class: "min-w-0 truncate text-sm font-semibold"
|
|
86
|
-
},
|
|
87
|
-
|
|
86
|
+
}, v(L.column.label), 9, k),
|
|
87
|
+
p(a, {
|
|
88
88
|
variant: "secondary",
|
|
89
|
-
class:
|
|
90
|
-
title:
|
|
89
|
+
class: h(y(n)("h-5 px-1.5 tabular-nums", V.value === "over" && "bg-destructive/15 text-destructive", V.value === "full" && "bg-warning/15 text-warning")),
|
|
90
|
+
title: U.value
|
|
91
91
|
}, {
|
|
92
|
-
default:
|
|
92
|
+
default: b(() => [f("span", A, v(L.column.wipLimit === void 0 ? H.value : `${L.column.count}/${L.column.wipLimit}`), 1), f("span", j, v(U.value), 1)]),
|
|
93
93
|
_: 1
|
|
94
94
|
}, 8, ["class", "title"]),
|
|
95
|
-
|
|
95
|
+
f("div", M, [L.creatable ? (_(), l(o, {
|
|
96
96
|
key: 0,
|
|
97
97
|
type: "button",
|
|
98
98
|
variant: "ghost",
|
|
99
99
|
size: "icon-xs",
|
|
100
|
-
"aria-label":
|
|
101
|
-
title:
|
|
102
|
-
onClick:
|
|
100
|
+
"aria-label": K.value,
|
|
101
|
+
title: K.value,
|
|
102
|
+
onClick: t[1] ||= (e) => R("create")
|
|
103
103
|
}, {
|
|
104
|
-
default:
|
|
104
|
+
default: b(() => [p(y(C), { "aria-hidden": "true" })]),
|
|
105
105
|
_: 1
|
|
106
|
-
}, 8, ["aria-label", "title"])) :
|
|
106
|
+
}, 8, ["aria-label", "title"])) : u("", !0), L.column.collapsible ? (_(), l(o, {
|
|
107
107
|
key: 1,
|
|
108
108
|
type: "button",
|
|
109
109
|
variant: "ghost",
|
|
110
110
|
size: "icon-xs",
|
|
111
|
-
"aria-label":
|
|
112
|
-
title:
|
|
111
|
+
"aria-label": G.value,
|
|
112
|
+
title: G.value,
|
|
113
113
|
"aria-expanded": !0,
|
|
114
|
-
onClick:
|
|
114
|
+
onClick: t[2] ||= (e) => R("toggle")
|
|
115
115
|
}, {
|
|
116
|
-
default:
|
|
116
|
+
default: b(() => [p(y(S), { "aria-hidden": "true" })]),
|
|
117
117
|
_: 1
|
|
118
|
-
}, 8, ["aria-label", "title"])) :
|
|
118
|
+
}, 8, ["aria-label", "title"])) : u("", !0)])
|
|
119
119
|
]),
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
], 12,
|
|
120
|
+
L.column.description ? (_(), d("p", N, v(L.column.description), 1)) : u("", !0),
|
|
121
|
+
V.value === "over" ? (_(), d("p", P, v(y(B)("kanban.wip_over", L.column.wipLimit ?? 0, { limit: L.column.wipLimit ?? 0 }, "{1} Over the limit of :limit card|[0,*] Over the limit of :limit cards")), 1)) : u("", !0),
|
|
122
|
+
V.value === "full" && L.column.wipStrict ? (_(), d("p", F, v(y(z)("kanban.wip_full", {}, "This column is full")), 1)) : u("", !0)
|
|
123
|
+
], 12, D));
|
|
124
124
|
}
|
|
125
125
|
});
|
|
126
126
|
//#endregion
|
|
127
|
-
export {
|
|
127
|
+
export { I as default };
|
|
128
128
|
|
|
129
129
|
//# sourceMappingURL=KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js.map
|