quasar-ui-danx 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/danx.es.js +7127 -6615
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +11 -5
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +3 -1
  7. package/src/components/ActionTable/ActionTable.vue +28 -41
  8. package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
  9. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +6 -6
  10. package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
  11. package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
  12. package/src/components/ActionTable/Filters/index.ts +2 -2
  13. package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
  14. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
  15. package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
  16. package/src/components/ActionTable/Form/Fields/SelectField.vue +24 -38
  17. package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
  18. package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
  19. package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
  20. package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
  21. package/src/components/ActionTable/Form/Fields/index.ts +2 -0
  22. package/src/components/ActionTable/Form/RenderedForm.vue +50 -9
  23. package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
  24. package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
  25. package/src/components/ActionTable/Form/index.ts +1 -0
  26. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +16 -15
  27. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +6 -6
  28. package/src/components/ActionTable/listControls.ts +104 -166
  29. package/src/components/ActionTable/listHelpers.ts +2 -3
  30. package/src/components/ActionTable/tableColumns.ts +3 -27
  31. package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
  32. package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
  33. package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
  34. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
  35. package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
  36. package/src/components/Utility/Dialogs/ConfirmDialog.vue +10 -24
  37. package/src/components/Utility/Dialogs/DialogLayout.vue +10 -28
  38. package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
  39. package/src/components/Utility/Dialogs/index.ts +1 -0
  40. package/src/components/Utility/Files/FilePreview.vue +76 -73
  41. package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
  42. package/src/components/Utility/Tools/ActionVnode.vue +3 -3
  43. package/src/components/Utility/Tools/RenderVnode.vue +1 -1
  44. package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
  45. package/src/components/Utility/Transitions/index.ts +1 -0
  46. package/src/config/index.ts +36 -31
  47. package/src/helpers/FileUpload.ts +295 -297
  48. package/src/helpers/FlashMessages.ts +80 -71
  49. package/src/helpers/actions.ts +102 -82
  50. package/src/helpers/download.ts +189 -189
  51. package/src/helpers/downloadPdf.ts +55 -52
  52. package/src/helpers/formats.ts +151 -109
  53. package/src/helpers/index.ts +2 -0
  54. package/src/helpers/multiFileUpload.ts +72 -58
  55. package/src/helpers/objectStore.ts +52 -0
  56. package/src/helpers/request.ts +70 -51
  57. package/src/helpers/routes.ts +29 -0
  58. package/src/helpers/storage.ts +7 -3
  59. package/src/helpers/utils.ts +47 -29
  60. package/src/styles/quasar-reset.scss +16 -1
  61. package/src/styles/themes/danx/dialogs.scss +4 -0
  62. package/src/types/actions.d.ts +43 -0
  63. package/src/types/config.d.ts +15 -0
  64. package/src/types/controls.d.ts +99 -0
  65. package/src/types/dialogs.d.ts +32 -0
  66. package/src/types/fields.d.ts +20 -0
  67. package/src/types/files.d.ts +54 -0
  68. package/src/types/formats.d.ts +4 -0
  69. package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
  70. package/src/types/index.d.ts +12 -0
  71. package/src/types/requests.d.ts +13 -0
  72. package/src/types/shared.d.ts +15 -0
  73. package/src/types/tables.d.ts +27 -0
  74. package/types/index.d.ts +1 -1
  75. /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
@@ -28,37 +28,37 @@
28
28
  </template>
29
29
  </QTabs>
30
30
  </template>
31
- <script setup>
31
+ <script setup lang="ts">
32
32
  import { QTab } from "quasar";
33
+ import { ActionPanel } from "../../types";
33
34
  import { RenderVnode } from "../Utility";
34
35
 
35
36
  defineEmits(["update:model-value"]);
36
- defineProps({
37
- modelValue: {
38
- type: String,
39
- default: "general"
40
- },
41
- panels: {
42
- type: Array,
43
- required: true
44
- }
37
+
38
+ interface Props {
39
+ modelValue?: string | number;
40
+ panels: ActionPanel[];
41
+ }
42
+
43
+ withDefaults(defineProps<Props>(), {
44
+ modelValue: "general"
45
45
  });
46
46
  </script>
47
47
 
48
48
  <style lang="scss" module="cls">
49
49
  .panel-tabs {
50
- @apply p-4 h-auto;
50
+ @apply p-4 h-auto;
51
51
 
52
- :global(.q-tab) {
53
- justify-content: start !important;
52
+ :global(.q-tab) {
53
+ justify-content: start !important;
54
54
 
55
- :global(.q-focus-helper), :global(.q-tab__indicator) {
56
- display: none;
57
- }
55
+ :global(.q-focus-helper), :global(.q-tab__indicator) {
56
+ display: none;
57
+ }
58
58
 
59
- :global(.q-tab__content) {
60
- @apply p-0;
61
- }
62
- }
59
+ :global(.q-tab__content) {
60
+ @apply p-0;
61
+ }
62
+ }
63
63
  }
64
64
  </style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <ConfirmDialog
3
+ class="dx-confirm-action-dialog"
4
+ v-bind="props"
5
+ :confirm-text="confirmText || computedConfirmText"
6
+ :title="title || computedTitle"
7
+ :content="content || computedContentText"
8
+ @confirm="$emit('confirm')"
9
+ @close="$emit('close')"
10
+ >
11
+ <template
12
+ v-for="slotName in childSlots"
13
+ #[slotName]
14
+ >
15
+ <slot :name="slotName" />
16
+ </template>
17
+ <slot />
18
+ </ConfirmDialog>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { computed } from "vue";
23
+ import { fNameOrCount } from "../../../helpers";
24
+ import { ConfirmActionDialogProps } from "../../../types";
25
+ import { default as ConfirmDialog } from "./ConfirmDialog";
26
+
27
+ defineEmits(["confirm", "close"]);
28
+
29
+ const props = withDefaults(defineProps<ConfirmActionDialogProps>(), {
30
+ message: "Are you sure you want to"
31
+ });
32
+
33
+ const nameLabel = computed(() => fNameOrCount(props.target, props.label || props.action));
34
+ const computedTitle = computed(() => `Confirm ${props.action}`);
35
+ const computedConfirmText = computed(() => `${props.action}`);
36
+ const computedContentText = computed(() => `${props.message} ${props.action.toLowerCase()}${nameLabel.value ? " " + nameLabel.value : ""}?`);
37
+
38
+ const childSlots = computed(() => ["title", "subtitle", "default", "toolbar", "actions"]);
39
+ </script>
@@ -10,6 +10,7 @@
10
10
  >
11
11
  <slot :name="slotName" />
12
12
  </template>
13
+ <slot />
13
14
 
14
15
  <template #actions>
15
16
  <div class="dx-dialog-button-cancel">
@@ -42,37 +43,22 @@
42
43
  </DialogLayout>
43
44
  </template>
44
45
 
45
- <script setup>
46
+ <script setup lang="ts">
46
47
  import { computed } from "vue";
48
+ import { ConfirmDialogProps } from "../../../types";
47
49
  import DialogLayout from "./DialogLayout";
48
50
 
49
51
  const emit = defineEmits(["update:model-value", "confirm", "close"]);
50
- const props = defineProps({
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
- }
52
+
53
+ const props = withDefaults(defineProps<ConfirmDialogProps>(), {
54
+ confirmText: "Confirm",
55
+ cancelText: "Cancel",
56
+ confirmClass: "",
57
+ contentClass: ""
72
58
  });
73
59
 
74
60
  const layoutProps = computed(() => ({ ...props, disabled: undefined }));
75
- const childSlots = computed(() => ["title", "subtitle", "default", "toolbar"]);
61
+ const childSlots = computed(() => ["title", "subtitle", "toolbar"]);
76
62
 
77
63
  function onConfirm() {
78
64
  emit("confirm");
@@ -3,7 +3,7 @@
3
3
  class="dx-dialog"
4
4
  :full-height="fullHeight"
5
5
  :full-width="fullWidth"
6
- :model-value="!!modelValue"
6
+ :model-value="true"
7
7
  :no-backdrop-dismiss="!backdropDismiss"
8
8
  :maximized="maximized"
9
9
  @update:model-value="onClose"
@@ -57,36 +57,18 @@
57
57
  </QDialog>
58
58
  </template>
59
59
 
60
- <script setup>
60
+ <script setup lang="ts">
61
61
  import { XIcon as CloseIcon } from "@heroicons/vue/outline";
62
+ import { DialogLayoutProps } from "../../../types";
62
63
 
63
64
  const emit = defineEmits(["close"]);
64
- defineProps({
65
- modelValue: { type: [String, Boolean, Object], default: true },
66
- title: {
67
- type: String,
68
- default: ""
69
- },
70
- titleClass: {
71
- type: String,
72
- default: ""
73
- },
74
- subtitle: {
75
- type: String,
76
- default: ""
77
- },
78
- content: {
79
- type: String,
80
- default: ""
81
- },
82
- backdropDismiss: Boolean,
83
- maximized: Boolean,
84
- fullWidth: Boolean,
85
- fullHeight: Boolean,
86
- contentClass: {
87
- type: String,
88
- default: ""
89
- }
65
+
66
+ withDefaults(defineProps<DialogLayoutProps>(), {
67
+ title: "",
68
+ titleClass: "",
69
+ subtitle: "",
70
+ content: "",
71
+ contentClass: ""
90
72
  });
91
73
 
92
74
  function onClose() {
@@ -22,6 +22,7 @@
22
22
  :key="'file-' + file.id"
23
23
  :name="file.id"
24
24
  :img-src="getThumbUrl(file)"
25
+ class="bg-black"
25
26
  >
26
27
  <div :class="cls['slide-image']">
27
28
  <template v-if="isVideo(file)">
@@ -30,7 +31,7 @@
30
31
  controls
31
32
  >
32
33
  <source
33
- :src="file.url + '#t=0.1'"
34
+ :src="getPreviewUrl(file) + '#t=0.1'"
34
35
  :type="file.mime"
35
36
  >
36
37
  </video>
@@ -38,7 +39,7 @@
38
39
  <img
39
40
  v-else
40
41
  :alt="file.filename"
41
- :src="file.url"
42
+ :src="getPreviewUrl(file)"
42
43
  >
43
44
  </div>
44
45
  </QCarouselSlide>
@@ -56,54 +57,59 @@ import { XIcon as CloseIcon } from "../../../svg";
56
57
 
57
58
  defineEmits(["close"]);
58
59
  const props = defineProps({
59
- files: {
60
- type: Array,
61
- default: () => []
62
- },
63
- defaultSlide: {
64
- type: String,
65
- default: ""
66
- }
60
+ files: {
61
+ type: Array,
62
+ default: () => []
63
+ },
64
+ defaultSlide: {
65
+ type: String,
66
+ default: ""
67
+ }
67
68
  });
68
69
 
69
70
  const carousel = ref(null);
70
71
  const currentSlide = ref(props.defaultSlide);
71
72
  function isVideo(file) {
72
- return file.mime?.startsWith("video");
73
+ return file.mime?.startsWith("video");
73
74
  }
75
+
76
+ function getPreviewUrl(file) {
77
+ return file.transcodes?.compress?.url || file.blobUrl || file.url;
78
+ }
79
+
74
80
  function getThumbUrl(file) {
75
- if (file.thumb) {
76
- return file.thumb.url;
77
- } else if (isVideo(file)) {
78
- // Base64 encode a PlayIcon for the placeholder image
79
- return `data:image/svg+xml;base64,${btoa(
80
- `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M0 0h24v24H0z" fill="none"/><path d="M8 5v14l11-7z"/></svg>`
81
- )}`;
82
- } else {
83
- return file.url;
84
- }
81
+ if (file.thumb) {
82
+ return file.thumb.url;
83
+ } else if (isVideo(file)) {
84
+ // Base64 encode a PlayIcon for the placeholder image
85
+ return `data:image/svg+xml;base64,${btoa(
86
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M0 0h24v24H0z" fill="none"/><path d="M8 5v14l11-7z"/></svg>`
87
+ )}`;
88
+ } else {
89
+ return getPreviewUrl(file);
90
+ }
85
91
  }
86
92
  </script>
87
93
  <style module="cls" lang="scss">
88
94
  .slide-image {
89
- width: 100%;
90
- height: 100%;
91
- background: black;
92
- display: flex;
93
- justify-content: center;
94
- align-items: center;
95
+ width: 100%;
96
+ height: 100%;
97
+ background: black;
98
+ display: flex;
99
+ justify-content: center;
100
+ align-items: center;
95
101
 
96
- img {
97
- max-height: 100%;
98
- max-width: 100%;
99
- object-fit: contain;
100
- }
102
+ img {
103
+ max-height: 100%;
104
+ max-width: 100%;
105
+ object-fit: contain;
106
+ }
101
107
  }
102
108
 
103
109
  .carousel {
104
- :deep(.q-carousel__navigation--bottom) {
105
- position: relative;
106
- bottom: 8em;
107
- }
110
+ :deep(.q-carousel__navigation--bottom) {
111
+ position: relative;
112
+ bottom: 8em;
113
+ }
108
114
  }
109
115
  </style>
@@ -1,3 +1,4 @@
1
+ export { default as ConfirmActionDialog } from "./ConfirmActionDialog.vue";
1
2
  export { default as ConfirmDialog } from "./ConfirmDialog.vue";
2
3
  export { default as FullScreenCarouselDialog } from "./FullscreenCarouselDialog.vue";
3
4
  export { default as FullScreenDialog } from "./FullScreenDialog.vue";
@@ -27,7 +27,7 @@
27
27
  </div>
28
28
  <QImg
29
29
  v-if="thumbUrl || isPreviewable"
30
- fit="scale-down"
30
+ :fit="imageFit"
31
31
  class="non-selectable max-h-full max-w-full h-full"
32
32
  :src="(thumbUrl || previewUrl) + '#t=0.1'"
33
33
  preload="auto"
@@ -54,11 +54,11 @@
54
54
  <slot name="action-button" />
55
55
  </div>
56
56
  <div
57
- v-if="image && image.progress !== undefined"
57
+ v-if="file && file.progress !== undefined"
58
58
  class="absolute-bottom w-full"
59
59
  >
60
60
  <QLinearProgress
61
- :value="image.progress"
61
+ :value="file.progress"
62
62
  size="15px"
63
63
  color="green-600"
64
64
  stripe
@@ -78,7 +78,7 @@
78
78
  <QBtn
79
79
  v-if="downloadable && computedImage?.url"
80
80
  size="sm"
81
- class="!p-1 opacity-70 hover:opacity-100"
81
+ class="dx-file-preview-download py-1 px-2 opacity-70 hover:opacity-100"
82
82
  :class="downloadButtonClass"
83
83
  @click.stop="download(computedImage.url)"
84
84
  >
@@ -88,7 +88,7 @@
88
88
  <QBtn
89
89
  v-if="removable"
90
90
  size="sm"
91
- class="bg-red-900 text-white !p-1 opacity-50 hover:opacity-100"
91
+ class="dx-file-preview-remove bg-red-900 text-white opacity-50 hover:opacity-100 py-1 px-2"
92
92
  @click.stop="onRemove"
93
93
  >
94
94
  <div
@@ -107,106 +107,109 @@
107
107
  <FullScreenCarouselDialog
108
108
  v-if="showPreview && !disabled"
109
109
  :files="relatedFiles || [computedImage]"
110
- :default-slide="computedImage.id"
110
+ :default-slide="computedImage?.id || ''"
111
111
  @close="showPreview = false"
112
112
  />
113
113
  </div>
114
114
  </template>
115
115
 
116
- <script setup>
116
+ <script setup lang="ts">
117
117
  import { DocumentTextIcon as TextFileIcon, DownloadIcon, PlayIcon } from "@heroicons/vue/outline";
118
- import { computed, ref } from "vue";
118
+ import { UploadedFile } from "src/types";
119
+ import { computed, ComputedRef, ref } from "vue";
119
120
  import { download } from "../../../helpers";
120
121
  import { ImageIcon, PdfIcon, TrashIcon as RemoveIcon } from "../../../svg";
121
122
  import { FullScreenCarouselDialog } from "../Dialogs";
122
123
 
124
+ export interface FilePreviewProps {
125
+ src?: string;
126
+ file?: UploadedFile;
127
+ relatedFiles?: UploadedFile[];
128
+ missingIcon?: any;
129
+ downloadButtonClass?: string;
130
+ imageFit?: "cover" | "contain" | "fill" | "none" | "scale-down";
131
+ downloadable?: boolean;
132
+ removable?: boolean;
133
+ disabled?: boolean;
134
+ square?: boolean;
135
+ }
136
+
123
137
  const emit = defineEmits(["remove"]);
124
- const props = defineProps({
125
- src: {
126
- type: String,
127
- default: ""
128
- },
129
- image: {
130
- type: Object,
131
- default: null
132
- },
133
- relatedFiles: {
134
- type: Array,
135
- default: null
136
- },
137
- missingIcon: {
138
- type: [Function, Object],
139
- default: ImageIcon
140
- },
141
- downloadButtonClass: {
142
- type: String,
143
- default: "bg-blue-600 text-white"
144
- },
145
- downloadable: Boolean,
146
- removable: Boolean,
147
- disabled: Boolean,
148
- square: Boolean
138
+
139
+ const props = withDefaults(defineProps<FilePreviewProps>(), {
140
+ src: "",
141
+ file: null,
142
+ relatedFiles: null,
143
+ missingIcon: ImageIcon,
144
+ downloadButtonClass: "bg-blue-600 text-white",
145
+ imageFit: "cover",
146
+ downloadable: false,
147
+ removable: false,
148
+ disabled: false,
149
+ square: false
149
150
  });
150
151
 
151
152
  const showPreview = ref(false);
152
- const computedImage = computed(() => {
153
- if (props.image) {
154
- return props.image;
155
- } else if (props.src) {
156
- return {
157
- id: props.src,
158
- url: props.src,
159
- type: "image/" + props.src.split(".").pop().toLowerCase()
160
- };
161
- }
162
- return null;
153
+ const computedImage: ComputedRef<UploadedFile | null> = computed(() => {
154
+ if (props.file) {
155
+ return props.file;
156
+ } else if (props.src) {
157
+ return {
158
+ id: props.src,
159
+ url: props.src,
160
+ type: "image/" + props.src.split(".").pop()?.toLowerCase(),
161
+ name: "",
162
+ size: 0
163
+ };
164
+ }
165
+ return null;
163
166
  });
164
167
  const mimeType = computed(
165
- () => computedImage.value.type || computedImage.value.mime
168
+ () => computedImage.value?.type || computedImage.value?.mime || ""
166
169
  );
167
- const isImage = computed(() => mimeType.value.match(/^image\//));
168
- const isVideo = computed(() => mimeType.value.match(/^video\//));
169
- const isPdf = computed(() => mimeType.value.match(/^application\/pdf/));
170
+ const isImage = computed(() => !!mimeType.value.match(/^image\//));
171
+ const isVideo = computed(() => !!mimeType.value.match(/^video\//));
172
+ const isPdf = computed(() => !!mimeType.value.match(/^application\/pdf/));
170
173
  const previewUrl = computed(
171
- () => computedImage.value.transcodes?.compress?.url || computedImage.value.blobUrl || computedImage.value.url
174
+ () => computedImage.value?.transcodes?.compress?.url || computedImage.value?.blobUrl || computedImage.value?.url
172
175
  );
173
176
  const thumbUrl = computed(() => {
174
- return computedImage.value.transcodes?.thumb?.url;
177
+ return computedImage.value?.transcodes?.thumb?.url;
175
178
  });
176
179
  const isPreviewable = computed(() => {
177
- return !!thumbUrl.value || isVideo.value || isImage.value;
180
+ return !!thumbUrl.value || isVideo.value || isImage.value;
178
181
  });
179
182
  const isConfirmingRemove = ref(false);
180
183
  function onRemove() {
181
- if (!isConfirmingRemove.value) {
182
- isConfirmingRemove.value = true;
183
- setTimeout(() => {
184
- isConfirmingRemove.value = false;
185
- }, 2000);
186
- } else {
187
- emit("remove");
188
- }
184
+ if (!isConfirmingRemove.value) {
185
+ isConfirmingRemove.value = true;
186
+ setTimeout(() => {
187
+ isConfirmingRemove.value = false;
188
+ }, 2000);
189
+ } else {
190
+ emit("remove");
191
+ }
189
192
  }
190
193
  </script>
191
194
 
192
195
  <style module="cls" lang="scss">
193
196
  .action-button {
194
- position: absolute;
195
- bottom: 1.5em;
196
- right: 1em;
197
- z-index: 1;
197
+ position: absolute;
198
+ bottom: 1.5em;
199
+ right: 1em;
200
+ z-index: 1;
198
201
  }
199
202
 
200
203
  .play-button {
201
- position: absolute;
202
- top: 0;
203
- left: 0;
204
- display: flex;
205
- justify-content: center;
206
- align-items: center;
207
- width: 100%;
208
- height: 100%;
209
- pointer-events: none;
210
- @apply text-blue-200;
204
+ position: absolute;
205
+ top: 0;
206
+ left: 0;
207
+ display: flex;
208
+ justify-content: center;
209
+ align-items: center;
210
+ width: 100%;
211
+ height: 100%;
212
+ pointer-events: none;
213
+ @apply text-blue-200;
211
214
  }
212
215
  </style>
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <QDialog
3
- v-model="isShowing"
3
+ :model-value="show"
4
4
  maximized
5
5
  :position="position"
6
6
  :seamless="seamless"
7
7
  :class="{'hide-backdrop': !overlay}"
8
+ @hide="$emit('update:show', false)"
8
9
  >
9
10
  <div>
10
11
  <div
@@ -21,45 +22,37 @@
21
22
  </QDialog>
22
23
  </template>
23
24
 
24
- <script setup>
25
- import { computed } from "vue";
25
+ <script setup lang="ts">
26
+ import { QDialogProps } from "quasar";
26
27
 
27
- const emit = defineEmits(["update:show"]);
28
-
29
- const props = defineProps({
30
- show: Boolean,
31
- seamless: Boolean,
32
- overlay: Boolean,
33
- position: {
34
- type: String,
35
- default: "bottom"
36
- },
37
- contentClass: {
38
- type: String,
39
- default: "py-8 px-12"
40
- },
41
- title: {
42
- type: String,
43
- default: "Edit"
44
- }
45
- });
28
+ export interface ContentDrawerProps {
29
+ show?: boolean,
30
+ overlay?: boolean,
31
+ position?: QDialogProps["position"],
32
+ seamless?: boolean,
33
+ contentClass?: string,
34
+ title?: string
35
+ }
46
36
 
47
- const isShowing = computed({
48
- get: () => props.show,
49
- set: (value) => emit("update:show", value)
37
+ defineEmits(["update:show"]);
38
+ withDefaults(defineProps<ContentDrawerProps>(), {
39
+ show: false,
40
+ position: "bottom",
41
+ contentClass: "py-8 px-12",
42
+ title: "Edit"
50
43
  });
51
44
  </script>
52
45
 
53
46
  <style lang="scss" module="cls">
54
47
  .dialog-title {
55
- @apply font-medium uppercase text-xs px-6 py-3 border-b rounded-t-md bg-slate-100 text-gray-500 border-gray-200;
56
- font-family: "Roboto", sans-serif;
57
- letter-spacing: 0.05em;
58
- box-shadow: 0px -4px 12px rgba(0, 0, 0, 0.25);
48
+ @apply font-medium uppercase text-xs px-6 py-3 border-b rounded-t-md bg-slate-100 text-gray-500 border-gray-200;
49
+ font-family: "Roboto", sans-serif;
50
+ letter-spacing: 0.05em;
51
+ box-shadow: 0px -4px 12px rgba(0, 0, 0, 0.25);
59
52
  }
60
53
 
61
54
  .dialog-content {
62
- @apply bg-white;
63
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
55
+ @apply bg-white;
56
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
64
57
  }
65
58
  </style>
@@ -16,8 +16,8 @@ import RenderVnode from "./RenderVnode";
16
16
 
17
17
  const isSaving = ref(false);
18
18
  async function onConfirm(input) {
19
- isSaving.value = true;
20
- await activeActionVnode.value.confirm(input);
21
- isSaving.value = false;
19
+ isSaving.value = true;
20
+ await activeActionVnode.value.confirm(input);
21
+ isSaving.value = false;
22
22
  }
23
23
  </script>
@@ -5,7 +5,7 @@ const RenderVnode = (props) => {
5
5
  if (isVNode(props.vnode)) {
6
6
  return props.vnode;
7
7
  }
8
-
8
+
9
9
  if (isRef(props.vnode)) {
10
10
  return props.vnode.value;
11
11
  }