quasar-ui-danx 0.3.22 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. package/.eslintrc.cjs +32 -30
  2. package/danx-local.sh +1 -1
  3. package/dist/danx.es.js +7413 -7461
  4. package/dist/danx.es.js.map +1 -1
  5. package/dist/danx.umd.js +5 -5
  6. package/dist/danx.umd.js.map +1 -1
  7. package/dist/style.css +1 -1
  8. package/package.json +1 -1
  9. package/src/components/ActionTable/ActionMenu.vue +1 -1
  10. package/src/components/ActionTable/ActionTable.vue +67 -47
  11. package/src/components/ActionTable/{ActionTableColumn.vue → Columns/ActionTableColumn.vue} +4 -3
  12. package/src/components/ActionTable/{ActionTableHeaderColumn.vue → Columns/ActionTableHeaderColumn.vue} +2 -2
  13. package/src/components/ActionTable/Columns/index.ts +2 -0
  14. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +23 -21
  15. package/src/components/ActionTable/Form/Fields/DateRangeField.vue +3 -5
  16. package/src/components/ActionTable/Form/Fields/NumberField.vue +60 -59
  17. package/src/components/ActionTable/Form/Fields/SelectField.vue +135 -135
  18. package/src/components/ActionTable/Form/Fields/TextField.vue +36 -36
  19. package/src/components/ActionTable/Form/RenderedForm.vue +133 -112
  20. package/src/components/ActionTable/Form/form.d.ts +31 -0
  21. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +93 -4
  22. package/src/components/ActionTable/TableSummaryRow.vue +4 -4
  23. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +46 -0
  24. package/src/components/ActionTable/Toolbars/index.ts +1 -0
  25. package/src/components/ActionTable/index.ts +1 -2
  26. package/src/components/ActionTable/listControls.ts +512 -385
  27. package/src/components/ActionTable/listHelpers.ts +46 -44
  28. package/src/components/ActionTable/tableColumns.ts +66 -66
  29. package/src/components/PanelsDrawer/PanelsDrawer.vue +37 -26
  30. package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +1 -1
  31. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +1 -6
  32. package/src/components/Utility/Buttons/ExportButton.vue +1 -1
  33. package/src/components/Utility/Buttons/RefreshButton.vue +5 -5
  34. package/src/components/Utility/Controls/PreviousNextControls.vue +4 -4
  35. package/src/components/Utility/Dialogs/ConfirmDialog.vue +69 -115
  36. package/src/components/Utility/Dialogs/DialogLayout.vue +95 -0
  37. package/src/components/Utility/Dialogs/InfoDialog.vue +40 -80
  38. package/src/components/Utility/Layouts/CollapsableSidebar.vue +2 -8
  39. package/src/components/Utility/Popovers/PopoverMenu.vue +3 -3
  40. package/src/components/Utility/Tools/RenderVnode.vue +21 -12
  41. package/src/helpers/actions.ts +198 -188
  42. package/src/styles/general.scss +12 -11
  43. package/src/styles/quasar-reset.scss +81 -22
  44. package/src/styles/themes/danx/action-table.scss +19 -0
  45. package/src/styles/themes/danx/buttons.scss +13 -0
  46. package/src/styles/themes/danx/dialogs.scss +43 -0
  47. package/src/styles/themes/danx/forms.scss +23 -0
  48. package/src/styles/themes/danx/index.scss +7 -0
  49. package/src/styles/themes/danx/panels.scss +19 -0
  50. package/src/styles/themes/danx/sidebar.scss +3 -0
  51. package/src/styles/themes/danx/toolbar.scss +3 -0
  52. package/types/index.d.ts +1 -0
  53. package/src/styles/actions.scss +0 -10
@@ -1,42 +1,44 @@
1
- import { onMounted } from "vue";
2
- import { getUrlParam } from "../../helpers";
1
+ import { ListControlsPagination } from "src/components/ActionTable/listControls";
2
+ import { TableColumn } from "src/components/ActionTable/tableColumns";
3
+ import { onMounted, Ref } from "vue";
4
+ import { AnyObject, getUrlParam } from "../../helpers";
3
5
 
4
- export function registerStickyScrolling(tableRef) {
5
- onMounted(() => {
6
- const scrollEl = tableRef.value.$el.getElementsByClassName("q-table__middle")[0];
7
- scrollEl.addEventListener("scroll", onScroll);
6
+ export function registerStickyScrolling(tableRef: Ref) {
7
+ onMounted(() => {
8
+ const scrollEl = tableRef.value.$el.getElementsByClassName("q-table__middle")[0];
9
+ scrollEl.addEventListener("scroll", onScroll);
8
10
 
9
- function onScroll({ target }) {
10
- // Add / remove scroll y class based on whether we're scrolling vertically
11
- if (target.scrollTop > 0) {
12
- scrollEl.classList.add("is-scrolling-y");
13
- } else {
14
- scrollEl.classList.remove("is-scrolling-y");
15
- }
11
+ function onScroll({ target }: { target: HTMLElement }) {
12
+ // Add / remove scroll y class based on whether we're scrolling vertically
13
+ if (target.scrollTop > 0) {
14
+ scrollEl.classList.add("is-scrolling-y");
15
+ } else {
16
+ scrollEl.classList.remove("is-scrolling-y");
17
+ }
16
18
 
17
- // Add / remove scroll x class based on whether we're scrolling horizontally
18
- if (target.scrollLeft > 0) {
19
- scrollEl.classList.add("is-scrolling-x");
20
- } else {
21
- scrollEl.classList.remove("is-scrolling-x");
22
- }
23
- }
24
- });
19
+ // Add / remove scroll x class based on whether we're scrolling horizontally
20
+ if (target.scrollLeft > 0) {
21
+ scrollEl.classList.add("is-scrolling-x");
22
+ } else {
23
+ scrollEl.classList.remove("is-scrolling-x");
24
+ }
25
+ }
26
+ });
25
27
  }
26
28
 
27
- export function mapSortBy(pagination, columns) {
28
- if (!pagination.sortBy) return null;
29
+ export function mapSortBy(pagination: ListControlsPagination, columns: TableColumn[]) {
30
+ if (!pagination.sortBy) return null;
29
31
 
30
- const column = columns.find(c => c.name === pagination.sortBy);
31
- if (!column) return null;
32
+ const column = columns.find(c => c.name === pagination.sortBy);
33
+ if (!column) return null;
32
34
 
33
- return [
34
- {
35
- column: column.sortBy || column.name,
36
- expression: column.sortByExpression || undefined,
37
- order: pagination.descending ? "desc" : "asc"
38
- }
39
- ];
35
+ return [
36
+ {
37
+ column: column.sortBy || column.name,
38
+ expression: column.sortByExpression || undefined,
39
+ order: pagination.descending ? "desc" : "asc"
40
+ }
41
+ ];
40
42
  }
41
43
 
42
44
  /**
@@ -44,16 +46,16 @@ export function mapSortBy(pagination, columns) {
44
46
  * @param url
45
47
  * @param allowedKeys
46
48
  */
47
- export function getFilterFromUrl(url: string, allowedKeys = null) {
48
- const filter = {};
49
- const urlFilter = getUrlParam("filter", url);
50
- if (urlFilter) {
51
- const fields = JSON.parse(urlFilter);
52
- Object.keys(fields).forEach((key) => {
53
- if (!allowedKeys || allowedKeys.includes(key)) {
54
- filter[key] = fields[key];
55
- }
56
- });
57
- }
58
- return filter;
49
+ export function getFilterFromUrl(url: string, allowedKeys: string[] | null = null) {
50
+ const filter: AnyObject = {};
51
+ const urlFilter = getUrlParam("filter", url);
52
+ if (urlFilter) {
53
+ const fields = JSON.parse(urlFilter);
54
+ Object.keys(fields).forEach((key) => {
55
+ if (!allowedKeys || allowedKeys.includes(key)) {
56
+ filter[key] = fields[key];
57
+ }
58
+ });
59
+ }
60
+ return filter;
59
61
  }
@@ -1,82 +1,82 @@
1
- import { computed, ref, watch } from "vue";
2
- import { getItem, setItem } from "../../helpers";
1
+ import { computed, ref, VNode, watch } from "vue";
2
+ import { ActionOptions, getItem, setItem } from "../../helpers";
3
3
 
4
4
  export interface TableColumn {
5
- actionMenu?: object,
6
- align?: string,
7
- category?: string,
8
- class?: string | object,
9
- field: string,
10
- format?: Function,
11
- innerClass?: string | object,
12
- style?: string | object,
13
- headerStyle?: string | object,
14
- isSavingRow?: boolean | Function,
15
- label: string,
16
- maxWidth?: number,
17
- minWidth?: number,
18
- name: string,
19
- onClick?: Function,
20
- required?: boolean,
21
- resizeable?: boolean,
22
- sortable?: boolean,
23
- sortBy?: string,
24
- sortByExpression?: string,
25
- titleColumns?: Function,
26
- vnode?: Function,
5
+ actionMenu?: ActionOptions[],
6
+ align?: string,
7
+ category?: string,
8
+ class?: string | object,
9
+ field: string,
10
+ format?: (value: any, options: any) => any,
11
+ innerClass?: string | object,
12
+ style?: string | object,
13
+ headerStyle?: string | object,
14
+ isSavingRow?: boolean | (() => boolean),
15
+ label: string,
16
+ maxWidth?: number,
17
+ minWidth?: number,
18
+ name: string,
19
+ onClick?: (target: any) => void,
20
+ required?: boolean,
21
+ resizeable?: boolean,
22
+ sortable?: boolean,
23
+ sortBy?: string,
24
+ sortByExpression?: string,
25
+ titleColumns?: () => string[],
26
+ vnode?: () => VNode,
27
27
  }
28
28
 
29
29
  export function useTableColumns(name: string, columns: TableColumn[]) {
30
- const COLUMN_ORDER_KEY = `${name}-column-order`;
31
- const VISIBLE_COLUMNS_KEY = `${name}-visible-columns`;
32
- const TITLE_COLUMNS_KEY = `${name}-title-columns`;
30
+ const COLUMN_ORDER_KEY = `${name}-column-order`;
31
+ const VISIBLE_COLUMNS_KEY = `${name}-visible-columns`;
32
+ const TITLE_COLUMNS_KEY = `${name}-title-columns`;
33
33
 
34
- // The list that defines the order the columns should appear in
35
- const columnOrder = ref(getItem(COLUMN_ORDER_KEY) || []);
34
+ // The list that defines the order the columns should appear in
35
+ const columnOrder = ref(getItem(COLUMN_ORDER_KEY) || []);
36
36
 
37
- // Manages visible columns on the table
38
- const hiddenColumnNames = ref(getItem(VISIBLE_COLUMNS_KEY, []));
37
+ // Manages visible columns on the table
38
+ const hiddenColumnNames = ref(getItem(VISIBLE_COLUMNS_KEY, []));
39
39
 
40
- // Title columns will have their name appear on the first column of the table as part of the records' title
41
- const titleColumnNames = ref(getItem(TITLE_COLUMNS_KEY, []));
40
+ // Title columns will have their name appear on the first column of the table as part of the records' title
41
+ const titleColumnNames = ref(getItem(TITLE_COLUMNS_KEY, []));
42
42
 
43
- // Columns that should be locked to the left side of the table
44
- const lockedColumns = computed(() => orderedColumns.value.slice(0, 1));
43
+ // Columns that should be locked to the left side of the table
44
+ const lockedColumns = computed(() => orderedColumns.value.slice(0, 1));
45
45
 
46
- // The resolved list of columns in the order they should appear in
47
- const orderedColumns = computed(() => [...columns].sort((a, b) => {
48
- const aIndex = columnOrder.value.indexOf(a.name);
49
- const bIndex = columnOrder.value.indexOf(b.name);
50
- return aIndex === -1 ? 1 : bIndex === -1 ? -1 : aIndex - bIndex;
51
- }));
46
+ // The resolved list of columns in the order they should appear in
47
+ const orderedColumns = computed(() => [...columns].sort((a, b) => {
48
+ const aIndex = columnOrder.value.indexOf(a.name);
49
+ const bIndex = columnOrder.value.indexOf(b.name);
50
+ return aIndex === -1 ? 1 : bIndex === -1 ? -1 : aIndex - bIndex;
51
+ }));
52
52
 
53
- // The ordered list of columns. The ordering of this list is editable and will be stored in localStorage
54
- const sortableColumns = computed({
55
- get() {
56
- return orderedColumns.value.slice(1);
57
- },
58
- set(newColumns) {
59
- columnOrder.value = [...lockedColumns.value.map(c => c.name), ...newColumns.map(c => c.name)];
60
- setItem(COLUMN_ORDER_KEY, columnOrder.value);
61
- }
62
- });
53
+ // The ordered list of columns. The ordering of this list is editable and will be stored in localStorage
54
+ const sortableColumns = computed({
55
+ get() {
56
+ return orderedColumns.value.slice(1);
57
+ },
58
+ set(newColumns) {
59
+ columnOrder.value = [...lockedColumns.value.map(c => c.name), ...newColumns.map(c => c.name)];
60
+ setItem(COLUMN_ORDER_KEY, columnOrder.value);
61
+ }
62
+ });
63
63
 
64
- // The list of columns that are visible. To edit the visible columns, edit the hiddenColumnNames list
65
- const visibleColumns = computed(() => orderedColumns.value.filter(c => !hiddenColumnNames.value.includes(c.name)));
64
+ // The list of columns that are visible. To edit the visible columns, edit the hiddenColumnNames list
65
+ const visibleColumns = computed(() => orderedColumns.value.filter(c => !hiddenColumnNames.value.includes(c.name)));
66
66
 
67
- // The list of columns that should be included in the title of a row
68
- const orderedTitleColumns = computed(() => orderedColumns.value.filter(c => titleColumnNames.value.includes(c.name)));
67
+ // The list of columns that should be included in the title of a row
68
+ const orderedTitleColumns = computed(() => orderedColumns.value.filter(c => titleColumnNames.value.includes(c.name)));
69
69
 
70
- // Save changes to the list of hidden columns in localStorage
71
- watch(() => hiddenColumnNames.value, () => setItem(VISIBLE_COLUMNS_KEY, hiddenColumnNames.value));
72
- watch(() => titleColumnNames.value, () => setItem(TITLE_COLUMNS_KEY, titleColumnNames.value));
70
+ // Save changes to the list of hidden columns in localStorage
71
+ watch(() => hiddenColumnNames.value, () => setItem(VISIBLE_COLUMNS_KEY, hiddenColumnNames.value));
72
+ watch(() => titleColumnNames.value, () => setItem(TITLE_COLUMNS_KEY, titleColumnNames.value));
73
73
 
74
- return {
75
- sortableColumns,
76
- lockedColumns,
77
- visibleColumns,
78
- hiddenColumnNames,
79
- titleColumnNames,
80
- orderedTitleColumns
81
- };
74
+ return {
75
+ sortableColumns,
76
+ lockedColumns,
77
+ visibleColumns,
78
+ hiddenColumnNames,
79
+ titleColumnNames,
80
+ orderedTitleColumns
81
+ };
82
82
  }
@@ -4,30 +4,40 @@
4
4
  :show="true"
5
5
  overlay
6
6
  content-class="h-full"
7
+ class="dx-panels-drawer"
7
8
  title=""
8
9
  @update:show="$emit('close')"
9
10
  >
10
11
  <div class="flex flex-col flex-nowrap h-full">
11
- <div class="flex items-center px-6 py-4 border-b">
12
+ <div class="dx-panels-drawer-header flex items-center px-6 py-4">
12
13
  <div class="flex-grow">
13
- <slot name="header" />
14
+ <slot name="header">
15
+ <h2>{{ title }}</h2>
16
+ </slot>
17
+ </div>
18
+ <div
19
+ v-if="$slots.controls"
20
+ class="mr-4"
21
+ >
22
+ <slot name="controls" />
14
23
  </div>
15
-
16
24
  <div>
17
- <QBtn @click="$emit('close')">
25
+ <QBtn
26
+ class="dx-close-button"
27
+ @click="$emit('close')"
28
+ >
18
29
  <CloseIcon class="w-4" />
19
30
  </QBtn>
20
31
  </div>
21
32
  </div>
22
- <div class="flex-grow overflow-hidden h-full">
33
+ <div class="dx-panels-drawer-body flex-grow overflow-hidden h-full">
23
34
  <div class="flex items-stretch flex-nowrap h-full">
24
- <div class="border-r w-[13.5rem] overflow-y-auto">
25
- <PanelsDrawerTabs
26
- v-model="activePanel"
27
- :panels="panels"
28
- @update:model-value="$emit('update:model-value', $event)"
29
- />
30
- </div>
35
+ <PanelsDrawerTabs
36
+ v-model="activePanel"
37
+ :class="tabsClass"
38
+ :panels="panels"
39
+ @update:model-value="$emit('update:model-value', $event)"
40
+ />
31
41
  <PanelsDrawerPanels
32
42
  :panels="panels"
33
43
  :active-panel="activePanel"
@@ -44,27 +54,28 @@
44
54
  </div>
45
55
  </ContentDrawer>
46
56
  </template>
47
- <script setup>
57
+ <script setup lang="ts">
48
58
  import { ref, watch } from "vue";
49
59
  import { XIcon as CloseIcon } from "../../svg";
60
+ import { ActionPanel } from "../ActionTable";
50
61
  import { ContentDrawer } from "../Utility";
51
62
  import PanelsDrawerPanels from "./PanelsDrawerPanels";
52
63
  import PanelsDrawerTabs from "./PanelsDrawerTabs";
53
64
 
65
+ export interface Props {
66
+ title?: string,
67
+ modelValue?: string,
68
+ tabsClass?: string | object,
69
+ panelsClass?: string | object,
70
+ panels: ActionPanel[]
71
+ }
72
+
54
73
  defineEmits(["update:model-value", "close"]);
55
- const props = defineProps({
56
- modelValue: {
57
- type: String,
58
- default: null
59
- },
60
- panelsClass: {
61
- type: [Object, String],
62
- default: "w-[35.5rem]"
63
- },
64
- panels: {
65
- type: Array,
66
- required: true
67
- }
74
+ const props = withDefaults(defineProps<Props>(), {
75
+ title: "",
76
+ modelValue: null,
77
+ tabsClass: "w-[13.5rem]",
78
+ panelsClass: "w-[35.5rem]"
68
79
  });
69
80
 
70
81
  const activePanel = ref(props.modelValue);
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <QTabPanels
3
3
  :model-value="activePanel"
4
- class="overflow-y-auto bg-gray-100 h-full transition-all"
4
+ class="dx-panels-drawer-panels overflow-y-auto h-full transition-all"
5
5
  >
6
6
  <QTabPanel
7
7
  v-for="panel in panels"
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <QTabs
3
+ class="dx-panels-drawer-tabs overflow-y-auto"
3
4
  :model-value="modelValue"
4
5
  vertical
5
6
  align="left"
@@ -50,8 +51,6 @@ defineProps({
50
51
 
51
52
  :global(.q-tab) {
52
53
  justify-content: start !important;
53
- padding: 0;
54
- @apply text-left py-2.5 px-2 rounded-lg hover:bg-slate-200;
55
54
 
56
55
  :global(.q-focus-helper), :global(.q-tab__indicator) {
57
56
  display: none;
@@ -61,9 +60,5 @@ defineProps({
61
60
  @apply p-0;
62
61
  }
63
62
  }
64
-
65
- :global(.q-tab.q-tab--active) {
66
- @apply text-white bg-blue-600;
67
- }
68
63
  }
69
64
  </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <QBtn
3
- class="bg-slate-200"
3
+ class="dx-export-button dx-action-button"
4
4
  :loading="isExporting"
5
5
  @click="onExport"
6
6
  >
@@ -1,16 +1,16 @@
1
1
  <template>
2
2
  <QBtn
3
- class="bg-slate-200"
3
+ class="dx-refresh-button dx-action-button"
4
4
  :loading="loading"
5
5
  >
6
6
  <RefreshIcon class="w-5" />
7
7
  </QBtn>
8
8
  </template>
9
- <script setup>
9
+ <script setup lang="ts">
10
10
  import { RefreshIcon } from "@heroicons/vue/solid";
11
11
 
12
12
  defineEmits(["refresh"]);
13
- defineProps({
14
- loading: Boolean
15
- });
13
+ defineProps<{
14
+ loading?: boolean
15
+ }>();
16
16
  </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <div class="previous-next-controls">
2
+ <div class="dx-previous-next-controls">
3
3
  <QBtn
4
- class="bg-slate-200 border-gray-300 border border-solid !rounded-r-none !p-2 !min-w-0"
4
+ class="dx-control dx-control-previous border border-solid !rounded-r-none !p-2 !min-w-0"
5
5
  :disable="isLoading"
6
6
  :loading="isLoading"
7
7
  @click="$emit('next', -1)"
@@ -9,7 +9,7 @@
9
9
  <SkipPreviousIcon class="w-6" />
10
10
  </QBtn>
11
11
  <QBtn
12
- class="bg-slate-200 border-gray-300 border border-solid border-l-0 !rounded-l-none !p-2 !min-w-0"
12
+ class="dx-control dx-control-next border border-solid border-l-0 !rounded-l-none !p-2 !min-w-0"
13
13
  :disable="isLoading"
14
14
  :loading="isLoading"
15
15
  @click="$emit('next', 1)"
@@ -23,6 +23,6 @@ import { SkipNextIcon, SkipPreviousIcon } from "../../../svg";
23
23
 
24
24
  defineEmits(["next"]);
25
25
  defineProps({
26
- isLoading: Boolean
26
+ isLoading: Boolean
27
27
  });
28
28
  </script>
@@ -1,135 +1,89 @@
1
1
  <template>
2
- <QDialog
3
- :full-height="fullHeight"
4
- :full-width="fullWidth"
5
- :model-value="!!modelValue"
6
- :no-backdrop-dismiss="!backdropDismiss"
7
- :maximized="maximized"
8
- @update:model-value="onClose"
2
+ <DialogLayout
3
+ class="dx-confirm-dialog"
4
+ v-bind="layoutProps"
5
+ @close="onClose"
9
6
  >
10
- <QCard class="flex flex-col flex-nowrap">
11
- <QCardSection
12
- v-if="title || $slots.title"
13
- class="pl-6 pr-10 border-b border-gray-300"
14
- >
15
- <h3
16
- class="font-normal flex items-center"
17
- :class="titleClass"
18
- >
19
- <slot name="title">
20
- {{ title }}
21
- </slot>
22
- </h3>
23
- <div
24
- v-if="subtitle"
25
- class="mt-1 text-sm"
7
+ <template
8
+ v-for="slotName in childSlots"
9
+ #[slotName]
10
+ >
11
+ <slot :name="slotName" />
12
+ </template>
13
+
14
+ <template #actions>
15
+ <div class="dx-dialog-button-cancel">
16
+ <QBtn
17
+ :label="cancelText"
18
+ class="dx-dialog-button"
19
+ @click="onClose"
26
20
  >
27
- {{ subtitle }}
28
- </div>
29
- </QCardSection>
30
- <QCardSection v-if="$slots.toolbar">
31
- <slot name="toolbar" />
32
- </QCardSection>
33
- <QCardSection
34
- v-if="content || $slots.default"
35
- class="px-6 bg-gray-100 flex-grow max-h-full overflow-y-auto"
36
- :class="contentClass"
37
- >
38
- <slot>{{ content }}</slot>
39
- </QCardSection>
40
- <div class="flex px-6 py-4 border-t border-gray-300">
41
- <div class="flex-grow">
42
- <QBtn
43
- :label="cancelText"
44
- class="action-btn btn-white-gray"
45
- @click="onClose"
46
- >
47
- <slot name="cancel-text" />
48
- </QBtn>
49
- </div>
50
- <slot name="actions" />
51
- <div v-if="!hideConfirm">
52
- <QBtn
53
- :label="$slots['confirm-text'] ? '' : confirmText"
54
- class="action-btn ml-4"
55
- :class="confirmClass"
56
- :loading="isSaving"
57
- :disable="disabled"
58
- data-testid="confirm-button"
59
- @click="onConfirm"
60
- >
61
- <slot name="confirm-text" />
62
- </QBtn>
63
- </div>
21
+ <slot name="cancel-text" />
22
+ </QBtn>
64
23
  </div>
65
- <a
66
- class="absolute top-0 right-0 p-4 text-black"
67
- @click="onClose"
24
+ <slot name="actions" />
25
+ <div
26
+ v-if="!hideConfirm"
27
+ class="dx-dialog-button-confirm"
68
28
  >
69
- <CloseIcon class="w-5" />
70
- </a>
71
- </QCard>
72
- </QDialog>
29
+ <QBtn
30
+ :label="$slots['confirm-text'] ? '' : confirmText"
31
+ class="dx-dialog-button"
32
+ :class="confirmClass"
33
+ :loading="isSaving"
34
+ :disable="disabled"
35
+ data-testid="confirm-button"
36
+ @click="onConfirm"
37
+ >
38
+ <slot name="confirm-text" />
39
+ </QBtn>
40
+ </div>
41
+ </template>
42
+ </DialogLayout>
73
43
  </template>
74
44
 
75
45
  <script setup>
76
- import { XIcon as CloseIcon } from "@heroicons/vue/outline";
46
+ import { computed } from "vue";
47
+ import DialogLayout from "./DialogLayout";
77
48
 
78
49
  const emit = defineEmits(["update:model-value", "confirm", "close"]);
79
50
  const props = defineProps({
80
- modelValue: { type: [String, Boolean, Object], default: true },
81
- title: {
82
- type: String,
83
- default: ""
84
- },
85
- titleClass: {
86
- type: String,
87
- default: ""
88
- },
89
- subtitle: {
90
- type: String,
91
- default: ""
92
- },
93
- content: {
94
- type: String,
95
- default: ""
96
- },
97
- backdropDismiss: Boolean,
98
- maximized: Boolean,
99
- fullWidth: Boolean,
100
- fullHeight: Boolean,
101
- disabled: Boolean,
102
- isSaving: Boolean,
103
- closeOnConfirm: Boolean,
104
- hideConfirm: Boolean,
105
- confirmText: {
106
- type: String,
107
- default: "Confirm"
108
- },
109
- cancelText: {
110
- type: String,
111
- default: "Cancel"
112
- },
113
- confirmClass: {
114
- type: String,
115
- default: "bg-blue-600 text-white"
116
- },
117
- contentClass: {
118
- type: String,
119
- default: ""
120
- }
51
+ ...DialogLayout.props,
52
+ disabled: Boolean,
53
+ isSaving: Boolean,
54
+ closeOnConfirm: Boolean,
55
+ hideConfirm: Boolean,
56
+ confirmText: {
57
+ type: String,
58
+ default: "Confirm"
59
+ },
60
+ cancelText: {
61
+ type: String,
62
+ default: "Cancel"
63
+ },
64
+ confirmClass: {
65
+ type: String,
66
+ default: ""
67
+ },
68
+ contentClass: {
69
+ type: String,
70
+ default: ""
71
+ }
121
72
  });
122
73
 
74
+ const layoutProps = computed(() => ({ ...props, disabled: undefined }));
75
+ const childSlots = computed(() => ["title", "subtitle", "default", "toolbar"]);
76
+
123
77
  function onConfirm() {
124
- emit("confirm");
78
+ emit("confirm");
125
79
 
126
- if (props.closeOnConfirm) {
127
- emit("close");
128
- }
80
+ if (props.closeOnConfirm) {
81
+ emit("close");
82
+ }
129
83
  }
130
84
 
131
85
  function onClose() {
132
- emit("update:model-value", false);
133
- emit("close");
86
+ emit("update:model-value", false);
87
+ emit("close");
134
88
  }
135
89
  </script>