quasar-ui-danx 0.0.43 → 0.0.45

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. package/package.json +1 -1
  2. package/src/components/ActionTable/ActionTable.vue +17 -51
  3. package/src/components/ActionTable/ActionTableColumn.vue +72 -0
  4. package/src/components/ActionTable/index.ts +1 -0
  5. package/src/components/AuditHistory/AuditHistoryItem.vue +54 -0
  6. package/src/components/AuditHistory/AuditHistoryItemValue.vue +60 -0
  7. package/src/components/AuditHistory/index.ts +2 -0
  8. package/src/components/PanelsDrawer/PanelsDrawer.vue +64 -0
  9. package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +25 -0
  10. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +65 -0
  11. package/src/components/PanelsDrawer/index.ts +3 -0
  12. package/src/components/Utility/Controls/PreviousNextControls.vue +28 -0
  13. package/src/components/Utility/Controls/index.ts +1 -0
  14. package/src/components/Utility/Formats/IconWithTextFormat.vue +7 -3
  15. package/src/components/Utility/Tabs/BadgeTab.vue +32 -0
  16. package/src/components/Utility/Tabs/IndicatorTab.vue +40 -0
  17. package/src/components/Utility/Tabs/index.ts +2 -0
  18. package/src/components/Utility/Tools/ActionVnode.vue +23 -0
  19. package/src/components/Utility/Tools/RenderVnode.vue +5 -0
  20. package/src/components/Utility/Tools/index.ts +2 -2
  21. package/src/components/Utility/index.ts +2 -0
  22. package/src/components/index.ts +3 -1
  23. package/src/helpers/actions.ts +12 -12
  24. package/src/svg/SkipNextIcon.svg +5 -0
  25. package/src/svg/SkipPreviousIcon.svg +5 -0
  26. package/src/svg/WarningIcon.svg +5 -0
  27. package/src/svg/index.ts +3 -0
  28. package/src/components/Utility/Tools/ActionInputComponent.vue +0 -23
  29. package/src/components/Utility/Tools/RenderVNode.vue +0 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -48,46 +48,17 @@
48
48
  </q-th>
49
49
  </template>
50
50
  <template #body-cell="rowProps">
51
- <q-td :key="rowProps.key" :props="rowProps">
52
- <component
53
- :is="rowProps.col.onClick ? 'a' : 'div'"
54
- class="flex items-center flex-nowrap"
55
- :class="{'justify-end': rowProps.col.align === 'right', 'justify-center': rowProps.col.align === 'center', 'justify-start': rowProps.col.align === 'left'}"
56
- :style="getColumnStyle(rowProps.col)"
57
- @click="() => rowProps.col.onClick && rowProps.col.onClick(rowProps.row)"
58
- >
59
- <RenderVNode
60
- v-if="rowProps.col.vnode"
61
- :vnode="rowProps.col.vnode(rowProps.row)"
62
- />
63
- <RenderComponent
64
- v-else-if="rowProps.col.component"
65
- :params="[rowProps.row]"
66
- :component="rowProps.col.component"
67
- />
68
- <div v-else-if="rowProps.col.fieldList">
69
- <div v-for="field in rowProps.col.fieldList" :key="field">
70
- {{ rowProps.row[field] }}
71
- </div>
72
- </div>
73
- <div v-else>
74
- <slot v-bind="{name: rowProps.col.name, row: rowProps.row, value: rowProps.value}">
75
- {{ rowProps.value }}
76
- </slot>
77
- </div>
78
- <div v-if="rowProps.col.actions" class="flex-grow flex justify-end pl-2">
79
- <ActionMenu
80
- :actions="rowProps.col.actions"
81
- :target="rowProps.row"
82
- :loading="isSavingRow(rowProps.row)"
83
- @action="(action) => $emit('action', action, rowProps.row)"
84
- />
85
- </div>
86
- </component>
87
- </q-td>
51
+ <ActionTableColumn
52
+ :row-props="rowProps"
53
+ :settings="columnSettings[rowProps.col.name]"
54
+ :is-saving="isSavingRow(rowProps.row)"
55
+ @action="$emit('action', $event, rowProps.row)"
56
+ >
57
+ <slot />
58
+ </ActionTableColumn>
88
59
  </template>
89
60
  <template #bottom>
90
- <ActionInputComponent />
61
+ <ActionVnode />
91
62
  </template>
92
63
  </q-table>
93
64
  </template>
@@ -97,8 +68,8 @@ import { ref } from 'vue';
97
68
  import { getItem, setItem } from '../../helpers';
98
69
  import { DragHandleIcon as RowResizeIcon } from '../../svg';
99
70
  import { HandleDraggable } from '../DragAndDrop';
100
- import { ActionInputComponent, mapSortBy, RenderComponent, RenderVNode } from '../index';
101
- import { ActionMenu, EmptyTableState, registerStickyScrolling, TableSummaryRow } from './index';
71
+ import { ActionVnode, mapSortBy } from '../index';
72
+ import { ActionTableColumn, EmptyTableState, registerStickyScrolling, TableSummaryRow } from './index';
102
73
 
103
74
  defineEmits(['action', 'update:quasar-pagination', 'update:selected-rows']);
104
75
  const props = defineProps({
@@ -147,19 +118,14 @@ registerStickyScrolling(actionTable);
147
118
  const COLUMN_SETTINGS_KEY = `column-settings-${props.name}`;
148
119
  const columnSettings = ref(getItem(COLUMN_SETTINGS_KEY) || {});
149
120
  function onResizeColumn(column, val) {
150
- columnSettings.value[column.name] = Math.max(Math.min(val.distance + val.startDropZoneSize, column.maxWidth || 500), column.minWidth || 80);
121
+ columnSettings.value = {
122
+ ...columnSettings.value,
123
+ [column.name]: {
124
+ width: Math.max(Math.min(val.distance + val.startDropZoneSize, column.maxWidth || 500), column.minWidth || 80)
125
+ }
126
+ };
151
127
  setItem(COLUMN_SETTINGS_KEY, columnSettings.value);
152
128
  }
153
- function getColumnStyle(column) {
154
- const width = columnSettings.value[column.name] || column.width;
155
-
156
- if (width) {
157
- return {
158
- width: `${width}px`
159
- };
160
- }
161
- return null;
162
- }
163
129
 
164
130
  function isSavingRow(row) {
165
131
  if (!props.isSavingTarget) return false;
@@ -0,0 +1,72 @@
1
+ <template>
2
+ <q-td :key="rowProps.key" :props="rowProps" :style="columnStyle">
3
+ <div
4
+ class="flex items-center flex-nowrap"
5
+ :class="columnClass"
6
+ >
7
+ <a
8
+ v-if="column.onClick"
9
+ class="flex-grow"
10
+ @click="column.onClick(row)"
11
+ >
12
+ <RenderVnode
13
+ v-if="column.vnode"
14
+ :vnode="column.vnode(row)"
15
+ />
16
+ <slot v-else v-bind="{name: column.name, row, value}">
17
+ {{ value }}
18
+ </slot>
19
+ </a>
20
+ <div v-else class="flex-grow">
21
+ <RenderVnode
22
+ v-if="column.vnode"
23
+ :vnode="column.vnode(row)"
24
+ />
25
+ <slot v-else v-bind="{name: column.name, row, value}">
26
+ {{ value }}
27
+ </slot>
28
+ </div>
29
+ <div v-if="column.actions" class="flex flex-shrink-0 pl-2">
30
+ <ActionMenu
31
+ :actions="column.actions"
32
+ :target="row"
33
+ :loading="isSaving"
34
+ @action="$emit('action', $event)"
35
+ />
36
+ </div>
37
+ </div>
38
+ </q-td>
39
+ </template>
40
+ <script setup>
41
+ import { computed } from 'vue';
42
+ import { RenderVnode } from '../Utility';
43
+ import { ActionMenu } from './index';
44
+
45
+ defineEmits(['action']);
46
+ const props = defineProps({
47
+ rowProps: {
48
+ type: Object,
49
+ required: true
50
+ },
51
+ settings: {
52
+ type: Object,
53
+ default: null
54
+ },
55
+ isSaving: Boolean
56
+ });
57
+
58
+ const row = computed(() => props.rowProps.row);
59
+ const column = computed(() => props.rowProps.col);
60
+ const value = computed(() => props.rowProps.value);
61
+
62
+ const columnStyle = computed(() => {
63
+ const width = props.settings?.width || column.value.width;
64
+ return width ? { width: `${width}px` } : null;
65
+ });
66
+
67
+ const columnClass = computed(() => ({
68
+ 'justify-end': column.value.align === 'right',
69
+ 'justify-center': column.value.align === 'center',
70
+ 'justify-start': column.value.align === 'left'
71
+ }));
72
+ </script>
@@ -6,5 +6,6 @@ export * from "./listHelpers";
6
6
  export * from "./tableColumns";
7
7
  export { default as ActionMenu } from "./ActionMenu.vue";
8
8
  export { default as ActionTable } from "./ActionTable.vue";
9
+ export { default as ActionTableColumn } from "./ActionTableColumn.vue";
9
10
  export { default as EmptyTableState } from "./EmptyTableState.vue";
10
11
  export { default as TableSummaryRow } from "./TableSummaryRow.vue";
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <div class="text-gray-shadow flex items-stretch flex-nowrap p-4">
3
+ <div class="flex-grow text-sm w-3/5 overflow-auto">
4
+ <h5>{{ change.label }} ({{ change.name }})</h5>
5
+ <div class="flex flex-nowrap items-center mt-4">
6
+ <div class="bg-red-light line-through p-2">
7
+ <AdHistoryItemValue
8
+ :type="change.type"
9
+ :value="change.oldValue"
10
+ />
11
+ </div>
12
+ <div class="bg-green-plus-4 ml-2.5 p-2">
13
+ <AdHistoryItemValue
14
+ :type="change.type"
15
+ :value="change.newValue"
16
+ />
17
+ </div>
18
+ </div>
19
+ </div>
20
+ <div class="ml-4 text-sm w-2/5">
21
+ <template v-if="item.user">
22
+ <div>{{ item.user.name }}</div>
23
+ <div>{{ item.user.email }}</div>
24
+ </template>
25
+ <div>{{ item.account }}</div>
26
+ <div>
27
+ <a v-if="item.audit_request_id" :href="novaUrl" target="_blank">{{ fLocalizedDateTime(item.timestamp) }}</a>
28
+ <template v-else>{{ fLocalizedDateTime(item.timestamp) }}</template>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </template>
33
+ <script setup>
34
+ import { computed } from 'vue';
35
+ import { fLocalizedDateTime } from '../../helpers';
36
+ import AdHistoryItemValue from './AuditHistoryItemValue';
37
+
38
+ const props = defineProps({
39
+ item: {
40
+ type: Object,
41
+ required: true
42
+ },
43
+ change: {
44
+ type: Object,
45
+ required: true
46
+ },
47
+ novaUrl: {
48
+ type: String,
49
+ default: '/nova'
50
+ }
51
+ });
52
+
53
+ const novaUrl = computed(() => props.novaUrl + `/resources/audit-requests/${props.item.audit_request_id}`);
54
+ </script>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div class="flex space-x-2">
3
+ <template v-if="type === 'SINGLE_FILE'">
4
+ <FilePreview
5
+ :image="value"
6
+ class="w-24"
7
+ />
8
+ </template>
9
+ <template v-else-if="type === 'MULTI_FILE'">
10
+ <FilePreview
11
+ v-for="file in value"
12
+ :key="'file-' + file.id"
13
+ :image="file"
14
+ class="w-24 mb-2"
15
+ />
16
+ </template>
17
+ <template v-else-if="type === 'WYSIWYG'">
18
+ <div v-html="value" />
19
+ </template>
20
+ <template v-else>
21
+ {{ format(value) }}
22
+ </template>
23
+ </div>
24
+ </template>
25
+ <script setup>
26
+ import { fCurrency, fDate, fLocalizedDateTime, fNumber } from '../../helpers';
27
+ import { FilePreview } from '../Utility';
28
+
29
+ const props = defineProps({
30
+ type: {
31
+ type: String,
32
+ required: true
33
+ },
34
+ value: {
35
+ type: [Number, String, Array, Object, Boolean],
36
+ default: null
37
+ }
38
+ });
39
+
40
+ function format(value) {
41
+ if (value === null || value === '' || value === undefined) {
42
+ return '';
43
+ }
44
+
45
+ switch (props.type) {
46
+ case 'NUMBER':
47
+ return fNumber(value);
48
+ case 'CURRENCY':
49
+ return fCurrency(value);
50
+ case 'DATE':
51
+ return fDate(value);
52
+ case 'DATETIME':
53
+ return fLocalizedDateTime(value);
54
+ case 'BOOLEAN':
55
+ return value ? 'Yes' : 'No';
56
+ }
57
+
58
+ return value;
59
+ }
60
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as AuditHistoryItem } from "./AuditHistoryItem.vue";
2
+ export { default as AuditHistoryItemValue } from "./AuditHistoryItemValue.vue";
@@ -0,0 +1,64 @@
1
+ <template>
2
+ <ContentDrawer
3
+ position="right"
4
+ :show="true"
5
+ overlay
6
+ content-class="h-full"
7
+ title=""
8
+ @update:show="$emit('close')"
9
+ >
10
+ <div class="flex flex-col flex-nowrap h-full">
11
+ <div class="flex items-center px-6 py-4 border-b">
12
+ <div class="flex-grow">
13
+ <slot name="header" />
14
+ </div>
15
+
16
+ <div>
17
+ <QBtn @click="$emit('close')">
18
+ <CloseIcon class="w-4" />
19
+ </QBtn>
20
+ </div>
21
+ </div>
22
+ <div class="flex-grow overflow-hidden h-full">
23
+ <div class="flex items-stretch flex-nowrap h-full">
24
+ <div class="border-r w-[13.5em] overflow-y-auto">
25
+ <PanelsDrawerTabs
26
+ v-model="activePanel"
27
+ :panels="panels"
28
+ @update:model-value="$emit('update:model-value', $event)"
29
+ />
30
+ </div>
31
+ <PanelsDrawerPanels :panels="panels" :active-panel="activePanel" :class="panelsClass" />
32
+ <div v-if="$slots['right-sidebar']" class="border-l overflow-y-auto">
33
+ <slot name="right-sidebar" />
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </ContentDrawer>
39
+ </template>
40
+ <script setup>
41
+ import { ref, watch } from 'vue';
42
+ import { XIcon as CloseIcon } from '../../svg';
43
+ import { ContentDrawer } from '../Utility';
44
+ import { PanelsDrawerPanels, PanelsDrawerTabs } from './index';
45
+
46
+ defineEmits(['update:model-value', 'close']);
47
+ const props = defineProps({
48
+ modelValue: {
49
+ type: String,
50
+ default: null
51
+ },
52
+ panelsClass: {
53
+ type: [Object, String],
54
+ default: 'w-[35.5rem]'
55
+ },
56
+ panels: {
57
+ type: Array,
58
+ required: true
59
+ }
60
+ });
61
+
62
+ const activePanel = ref(props.modelValue);
63
+ watch(() => props.modelValue, (value) => activePanel.value = value);
64
+ </script>
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <QTabPanels
3
+ :model-value="activePanel"
4
+ class="overflow-y-auto bg-neutral-plus-7 h-full transition-all"
5
+ >
6
+ <QTabPanel v-for="panel in panels" :key="panel.name" :name="panel.name">
7
+ <RenderVnode v-if="panel.vnode" :vnode="panel.vnode" />
8
+ </QTabPanel>
9
+ </QTabPanels>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { RenderVnode } from "quasar-ui-danx";
14
+
15
+ defineProps({
16
+ activePanel: {
17
+ type: String,
18
+ required: true
19
+ },
20
+ panels: {
21
+ type: Array,
22
+ required: true
23
+ }
24
+ });
25
+ </script>
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <QTabs
3
+ :model-value="modelValue"
4
+ vertical
5
+ align="left"
6
+ class="panel-tabs p-4 h-auto"
7
+ no-caps
8
+ @update:model-value="$emit('update:model-value', $event)"
9
+ >
10
+ <template v-for="panel in panels">
11
+ <template v-if="panel.enabled !== false">
12
+ <RenderVnode
13
+ v-if="panel.tabVnode"
14
+ :key="panel.name"
15
+ :vnode="panel.tabVnode"
16
+ :is-active="modelValue === panel.name"
17
+ :name="panel.name"
18
+ :label="panel.label"
19
+ />
20
+ <QTab v-else :key="panel.name" :name="panel.name" :label="panel.label" />
21
+ </template>
22
+ </template>
23
+ </QTabs>
24
+ </template>
25
+ <script setup>
26
+ import { QTab } from "quasar";
27
+ import { RenderVnode } from "quasar-ui-danx";
28
+
29
+ defineEmits(["update:model-value"]);
30
+ defineProps({
31
+ modelValue: {
32
+ type: String,
33
+ default: "general"
34
+ },
35
+ panels: {
36
+ type: Array,
37
+ required: true
38
+ }
39
+ });
40
+ </script>
41
+
42
+ <style
43
+ lang="scss"
44
+ scoped
45
+ >
46
+ .panel-tabs {
47
+ :deep(.q-tab) {
48
+ justify-content: start !important;
49
+ padding: 0;
50
+ @apply text-left py-2.5 px-2 rounded-lg hover:bg-neutral-plus-6;
51
+
52
+ .q-focus-helper, .q-tab__indicator {
53
+ display: none;
54
+ }
55
+
56
+ .q-tab__content {
57
+ @apply p-0;
58
+ }
59
+ }
60
+
61
+ :deep(.q-tab.q-tab--active) {
62
+ @apply text-white bg-blue-base;
63
+ }
64
+ }
65
+ </style>
@@ -0,0 +1,3 @@
1
+ export { default as PanelsDrawer } from "./PanelsDrawer.vue";
2
+ export { default as PanelsDrawerPanels } from "./PanelsDrawerPanels.vue";
3
+ export { default as PanelsDrawerTabs } from "./PanelsDrawerTabs.vue";
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <div class="previous-next-controls">
3
+ <QBtn
4
+ class="bg-neutral-plus-6 border-neutral-plus-4 border border-solid !rounded-r-none !p-2 !min-w-0"
5
+ :disable="isLoading"
6
+ :loading="isLoading"
7
+ @click="$emit('next', -1)"
8
+ >
9
+ <SkipPreviousIcon class="w-6" />
10
+ </QBtn>
11
+ <QBtn
12
+ class="bg-neutral-plus-6 border-neutral-plus-4 border border-solid border-l-0 !rounded-l-none !p-2 !min-w-0"
13
+ :disable="isLoading"
14
+ :loading="isLoading"
15
+ @click="$emit('next', 1)"
16
+ >
17
+ <SkipNextIcon class="w-6" />
18
+ </QBtn>
19
+ </div>
20
+ </template>
21
+ <script setup>
22
+ import { SkipNextIcon, SkipPreviousIcon } from '../../../svg';
23
+
24
+ defineEmits(['next']);
25
+ defineProps({
26
+ isLoading: Boolean
27
+ });
28
+ </script>
@@ -0,0 +1 @@
1
+ export { default as PreviousNextControls } from "./PreviousNextControls.vue";
@@ -2,7 +2,7 @@
2
2
  <div class="flex items-center">
3
3
  <component :is="icon" :class="iconClass" />
4
4
  <div :class="textClass">
5
- <slot />
5
+ <slot>{{ text }}</slot>
6
6
  </div>
7
7
  </div>
8
8
  </template>
@@ -14,11 +14,15 @@ defineProps({
14
14
  },
15
15
  iconClass: {
16
16
  type: String,
17
- default: "w-6"
17
+ default: 'w-6'
18
+ },
19
+ text: {
20
+ type: String,
21
+ default: null
18
22
  },
19
23
  textClass: {
20
24
  type: String,
21
- default: "ml-2"
25
+ default: 'ml-2'
22
26
  }
23
27
  });
24
28
  </script>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <q-tab
3
+ :name="name"
4
+ class="w-full"
5
+ content-class="w-full"
6
+ >
7
+ <div class="flex items-center w-full">
8
+ <div class="flex-grow text-sm">{{ label }}</div>
9
+ <q-badge
10
+ color="gray-base"
11
+ :label="count"
12
+ rounded
13
+ />
14
+ </div>
15
+ </q-tab>
16
+ </template>
17
+ <script setup>
18
+ defineProps({
19
+ name: {
20
+ type: String,
21
+ required: true
22
+ },
23
+ label: {
24
+ type: String,
25
+ required: true
26
+ },
27
+ count: {
28
+ type: [String, Number],
29
+ default: ''
30
+ }
31
+ });
32
+ </script>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <q-tab
3
+ :name="name"
4
+ class="w-full"
5
+ content-class="w-full"
6
+ >
7
+ <div class="flex items-center w-full">
8
+ <div class="flex-grow text-sm">{{ label }}</div>
9
+ <div>
10
+ <OverdueIcon
11
+ v-if="overdue"
12
+ class="w-5 ml-2"
13
+ :class="isActive ? 'text-white' : 'text-red-danger'"
14
+ />
15
+ <WarningIcon
16
+ v-else-if="warning"
17
+ class="text-yellow-warning w-5"
18
+ />
19
+ </div>
20
+ </div>
21
+ </q-tab>
22
+ </template>
23
+ <script setup>
24
+ import { ExclamationCircleIcon as OverdueIcon } from '@heroicons/vue/solid';
25
+ import { WarningIcon } from '../../../svg';
26
+
27
+ defineProps({
28
+ name: {
29
+ type: String,
30
+ required: true
31
+ },
32
+ label: {
33
+ type: String,
34
+ required: true
35
+ },
36
+ overdue: Boolean,
37
+ warning: Boolean,
38
+ isActive: Boolean
39
+ });
40
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as BadgeTab } from "./BadgeTab.vue";
2
+ export { default as IndicatorTab } from "./IndicatorTab.vue";
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div>
3
+ <RenderVnode
4
+ v-if="activeActionVnode"
5
+ :vnode="activeActionVnode.vnode"
6
+ :is-saving="isSaving"
7
+ @confirm="onConfirm"
8
+ @close="activeActionVnode.cancel"
9
+ />
10
+ </div>
11
+ </template>
12
+ <script setup>
13
+ import { ref } from 'vue';
14
+ import { activeActionVnode } from '../../../helpers';
15
+ import { RenderVnode } from './index';
16
+
17
+ const isSaving = ref(false);
18
+ async function onConfirm(input) {
19
+ isSaving.value = true;
20
+ await activeActionVnode.value.confirm(input);
21
+ isSaving.value = false;
22
+ }
23
+ </script>
@@ -0,0 +1,5 @@
1
+ <script>
2
+ const RenderVnode = (props) => props.vnode;
3
+ RenderVnode.props = { vnode: { type: Object, required: true } };
4
+ export default RenderVnode;
5
+ </script>
@@ -1,3 +1,3 @@
1
- export { default as ActionInputComponent } from "./ActionInputComponent.vue";
1
+ export { default as ActionVnode } from "./ActionVnode.vue";
2
2
  export { default as RenderComponent } from "./RenderComponent.vue";
3
- export { default as RenderVNode } from "./RenderVNode.vue";
3
+ export { default as RenderVnode } from "./RenderVnode.vue";
@@ -1,8 +1,10 @@
1
1
  export * from "./Buttons";
2
+ export * from "./Controls";
2
3
  export * from "./Dialogs";
3
4
  export * from "./Files";
4
5
  export * from "./Formats";
5
6
  export * from "./Layouts";
6
7
  export * from "./Popovers";
8
+ export * from "./Tabs";
7
9
  export * from "./Tools";
8
10
  export * from "./Transitions";
@@ -1,3 +1,5 @@
1
1
  export * from "./ActionTable";
2
- export * from "./Utility";
2
+ export * from "./AuditHistory";
3
3
  export * from "./DragAndDrop";
4
+ export * from "./PanelsDrawer";
5
+ export * from "./Utility";
@@ -1,4 +1,4 @@
1
- import { shallowRef } from "vue";
1
+ import { shallowRef, VNode } from "vue";
2
2
  import { FlashMessages } from "./index";
3
3
 
4
4
  interface ActionOptions {
@@ -8,7 +8,7 @@ interface ActionOptions {
8
8
  batch?: boolean;
9
9
  category?: string;
10
10
  class?: string;
11
- inputComponent?: (target: object[] | object) => any;
11
+ vnode?: (target: object[] | object) => VNode;
12
12
  enabled?: (target: object) => boolean;
13
13
  batchEnabled?: (targets: object[]) => boolean;
14
14
  onAction?: (action: string | null, target: object, input: any) => Promise<any>;
@@ -18,7 +18,7 @@ interface ActionOptions {
18
18
  onFinish?: (action: string | null, targets: object, input: any) => any;
19
19
  }
20
20
 
21
- export const activeActionInput = shallowRef(null);
21
+ export const activeActionVnode = shallowRef(null);
22
22
 
23
23
  /**
24
24
  * Hook to perform an action on a set of targets
@@ -98,25 +98,25 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
98
98
  */
99
99
  async performAction(name: string | object, target: object[] | object, input: any = null) {
100
100
  const action = resolveAction(name);
101
- const component = action.inputComponent && action.inputComponent(target);
101
+ const vnode = action.vnode && action.vnode(target);
102
102
  let result = null;
103
103
 
104
104
  isSavingTarget.value = target;
105
105
 
106
- // If no component input is required, we can directly perform the action
107
- if (component) {
108
- // If the action requires an input, we set the activeActionInput to the input component.
109
- // This will tell the ActionInputComponent to render the input component, and confirm or cancel the
106
+ // If additional input is required, first render the vnode and wait for the confirm or cancel action
107
+ if (vnode) {
108
+ // If the action requires an input, we set the activeActionVnode to the input component.
109
+ // This will tell the ActionVnode to render the input component, and confirm or cancel the
110
110
  // action The confirm function has the input from the component passed and will resolve the promise
111
111
  // with the result of the action
112
112
  result = await new Promise((resolve, reject) => {
113
- activeActionInput.value = {
114
- component,
113
+ activeActionVnode.value = {
114
+ vnode,
115
115
  confirm: async input => {
116
116
  const result = await onConfirmAction(action, target, input);
117
117
 
118
118
  // Only resolve when we have a non-error response, so we can show the error message w/o
119
- // hiding the dialog / inputComponent
119
+ // hiding the dialog / vnode
120
120
  if (result === undefined || result === true || result?.success) {
121
121
  resolve(result);
122
122
  }
@@ -125,7 +125,7 @@ export function useActions(actions: ActionOptions[], globalOptions: ActionOption
125
125
  };
126
126
  });
127
127
 
128
- activeActionInput.value = null;
128
+ activeActionVnode.value = null;
129
129
  } else {
130
130
  result = await onConfirmAction(action, target, input);
131
131
  }
@@ -0,0 +1,5 @@
1
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g>
3
+ <path d="M16.5 18V6H18.5V18H16.5ZM5.5 18V6L14.5 12L5.5 18Z" fill="currentColor"/>
4
+ </g>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g>
3
+ <path d="M5.5 18V6H7.5V18H5.5ZM18.5 18L9.5 12L18.5 6V18Z" fill="currentColor"/>
4
+ </g>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path
3
+ d="M0 18.2727L10 1L20 18.2727H0ZM3.13636 16.4545H16.8636L10 4.63636L3.13636 16.4545ZM10 15.5455C10.2576 15.5455 10.4736 15.4582 10.6482 15.2836C10.8221 15.1097 10.9091 14.8939 10.9091 14.6364C10.9091 14.3788 10.8221 14.163 10.6482 13.9891C10.4736 13.8145 10.2576 13.7273 10 13.7273C9.74242 13.7273 9.52667 13.8145 9.35273 13.9891C9.17818 14.163 9.09091 14.3788 9.09091 14.6364C9.09091 14.8939 9.17818 15.1097 9.35273 15.2836C9.52667 15.4582 9.74242 15.5455 10 15.5455ZM9.09091 12.8182H10.9091V8.27273H9.09091V12.8182Z"
4
+ fill="currentColor"/>
5
+ </svg>
package/src/svg/index.ts CHANGED
@@ -4,5 +4,8 @@ export { default as FilterIcon } from "./FilterIcon.svg";
4
4
  export { default as ImageIcon } from "./ImageIcon.svg";
5
5
  export { default as PdfIcon } from "./PdfIcon.svg";
6
6
  export { default as PercentIcon } from "./PercentIcon.svg";
7
+ export { default as SkipNextIcon } from "./SkipNextIcon.svg";
8
+ export { default as SkipPreviousIcon } from "./SkipPreviousIcon.svg";
7
9
  export { default as TrashIcon } from "./TrashIcon.svg";
10
+ export { default as WarningIcon } from "./WarningIcon.svg";
8
11
  export { default as XIcon } from "./XIcon.svg";
@@ -1,23 +0,0 @@
1
- <template>
2
- <div>
3
- <RenderComponent
4
- v-if="activeActionInput"
5
- :component="activeActionInput.component"
6
- :is-saving="isSaving"
7
- @confirm="onConfirm"
8
- @close="activeActionInput.cancel"
9
- />
10
- </div>
11
- </template>
12
- <script setup>
13
- import { ref } from 'vue';
14
- import { activeActionInput } from '../../../helpers';
15
- import RenderComponent from './RenderComponent';
16
-
17
- const isSaving = ref(false);
18
- async function onConfirm(input) {
19
- isSaving.value = true;
20
- await activeActionInput.value.confirm(input);
21
- isSaving.value = false;
22
- }
23
- </script>
@@ -1,6 +0,0 @@
1
- <script>
2
- const RenderVNode = (props) => props.vnode;
3
- RenderVNode.props = { vnode: { type: Object, required: true } };
4
- RenderVNode.emits = ['action'];
5
- export default RenderVNode;
6
- </script>