quasar-ui-danx 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. package/package.json +3 -2
  2. package/src/components/ActionTable/ActionTable.vue +135 -0
  3. package/src/components/ActionTable/BatchActionMenu.vue +60 -0
  4. package/src/components/ActionTable/EmptyTableState.vue +33 -0
  5. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +36 -0
  6. package/src/components/ActionTable/Filters/FilterGroupItem.vue +28 -0
  7. package/src/components/ActionTable/Filters/FilterGroupList.vue +76 -0
  8. package/src/components/ActionTable/Filters/FilterListToggle.vue +50 -0
  9. package/src/components/ActionTable/Filters/FilterableField.vue +141 -0
  10. package/src/components/ActionTable/Form/Fields/BooleanField.vue +37 -0
  11. package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +46 -0
  12. package/src/components/ActionTable/Form/Fields/DateField.vue +59 -0
  13. package/src/components/ActionTable/Form/Fields/DateRangeField.vue +110 -0
  14. package/src/components/ActionTable/Form/Fields/DateTimeField.vue +50 -0
  15. package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +59 -0
  16. package/src/components/ActionTable/Form/Fields/EditableDiv.vue +39 -0
  17. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +32 -0
  18. package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +78 -0
  19. package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +44 -0
  20. package/src/components/ActionTable/Form/Fields/IntegerField.vue +26 -0
  21. package/src/components/ActionTable/Form/Fields/LabeledInput.vue +63 -0
  22. package/src/components/ActionTable/Form/Fields/MultiFileField.vue +91 -0
  23. package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +57 -0
  24. package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +39 -0
  25. package/src/components/ActionTable/Form/Fields/NumberField.vue +94 -0
  26. package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +140 -0
  27. package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +136 -0
  28. package/src/components/ActionTable/Form/Fields/SelectField.vue +318 -0
  29. package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +81 -0
  30. package/src/components/ActionTable/Form/Fields/SingleFileField.vue +78 -0
  31. package/src/components/ActionTable/Form/Fields/TextField.vue +82 -0
  32. package/src/components/ActionTable/Form/Fields/WysiwygField.vue +46 -0
  33. package/src/components/ActionTable/Form/Fields/index.ts +23 -0
  34. package/src/components/ActionTable/Form/RenderedForm.vue +74 -0
  35. package/src/components/ActionTable/RenderComponentColumn.vue +22 -0
  36. package/src/components/ActionTable/TableSummaryRow.vue +95 -0
  37. package/src/components/ActionTable/index.ts +15 -0
  38. package/src/components/ActionTable/listActions.ts +361 -0
  39. package/src/components/ActionTable/tableColumns.ts +72 -0
  40. package/src/components/ActionTable/tableHelpers.ts +83 -0
  41. package/src/components/Utility/CollapsableSidebar.vue +119 -0
  42. package/src/components/Utility/ContentDrawer.vue +70 -0
  43. package/src/components/Utility/Dialogs/ConfirmDialog.vue +132 -0
  44. package/src/components/Utility/Dialogs/FullScreenDialog.vue +46 -0
  45. package/src/components/Utility/Dialogs/InfoDialog.vue +92 -0
  46. package/src/components/Utility/Dialogs/InputDialog.vue +35 -0
  47. package/src/components/Utility/Transitions/ListTransition.vue +50 -0
  48. package/src/components/Utility/Transitions/SlideTransition.vue +63 -0
  49. package/src/components/Utility/Transitions/StaggeredListTransition.vue +97 -0
  50. package/src/components/Utility/index.ts +9 -0
  51. package/src/components/index.ts +3 -0
  52. package/src/helpers/FileUpload.ts +294 -0
  53. package/src/helpers/FlashMessages.ts +79 -0
  54. package/src/helpers/array.ts +37 -0
  55. package/src/helpers/compatibility.ts +64 -0
  56. package/src/helpers/date.ts +5 -0
  57. package/src/helpers/download.ts +192 -0
  58. package/src/helpers/downloadPdf.ts +92 -0
  59. package/src/helpers/files.ts +52 -0
  60. package/src/helpers/formats.ts +183 -0
  61. package/src/helpers/http.ts +62 -0
  62. package/src/helpers/index.ts +10 -1
  63. package/src/helpers/multiFileUpload.ts +68 -0
  64. package/src/helpers/singleFileUpload.ts +54 -0
  65. package/src/helpers/storage.ts +8 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -62,6 +62,7 @@
62
62
  "last 4 iOS versions"
63
63
  ],
64
64
  "dependencies": {
65
- "@vueuse/core": "^10.7.2"
65
+ "@vueuse/core": "^10.7.2",
66
+ "tailwindcss": "^3.4.1"
66
67
  }
67
68
  }
@@ -0,0 +1,135 @@
1
+ <!--suppress VueUnrecognizedSlot -->
2
+ <template>
3
+ <QTable
4
+ ref="actionTable"
5
+ :selected="selectedRows"
6
+ :pagination="quasarPagination"
7
+ :columns="columns"
8
+ :loading="isLoadingList"
9
+ :rows="pagedItems?.data || []"
10
+ selection="multiple"
11
+ :rows-per-page-options="[25,50,100]"
12
+ class="sticky-column sticky-header w-full !border-0"
13
+ color="blue-base"
14
+ @update:selected="$emit('update:selected-rows', $event)"
15
+ @update:pagination="() => {}"
16
+ @request="$emit('update:quasar-pagination', $event.pagination)"
17
+ >
18
+ <template #no-data>
19
+ <slot name="empty">
20
+ <EmptyTableState :text="`There are no ${label.toLowerCase()} matching the applied filter`" />
21
+ </slot>
22
+ </template>
23
+ <template #top-row>
24
+ <TableSummaryRow
25
+ :label="label"
26
+ :item-count="summary?.count || 0"
27
+ :selected-count="selectedRows.length"
28
+ :loading="isLoadingSummary"
29
+ :summary="summary"
30
+ :columns="columns"
31
+ @clear="$emit('update:selected-rows', [])"
32
+ />
33
+ </template>
34
+ <template #header-cell="rowProps">
35
+ <QTh
36
+ :key="rowProps.key"
37
+ :props="rowProps"
38
+ :data-drop-zone="`resize-column-` + rowProps.col.name"
39
+ >
40
+ {{ rowProps.col.label }}
41
+ <HandleDraggable
42
+ v-if="rowProps.col.resizeable"
43
+ :drop-zone="`resize-column-` + rowProps.col.name"
44
+ class="resize-handle"
45
+ @resize="rowProps.col.onResize"
46
+ >
47
+ <RowResizeIcon class="w-4 text-neutral-base" />
48
+ </HandleDraggable>
49
+ </QTh>
50
+ </template>
51
+ <template #body-cell="rowProps">
52
+ <QTd :key="rowProps.key" :props="rowProps">
53
+ <template v-if="rowProps.col.component">
54
+ <RenderComponentColumn
55
+ :row-props="rowProps"
56
+ @action="$emit('action', $event)"
57
+ />
58
+ </template>
59
+ <template v-else-if="rowProps.col.fieldList">
60
+ <div v-for="field in rowProps.col.fieldList" :key="field">
61
+ {{ rowProps.row[field] }}
62
+ </div>
63
+ </template>
64
+ <template v-else-if="rowProps.col.filterOnClick">
65
+ <a @click="$emit('filter', rowProps.col.filterOnClick(rowProps.row))">
66
+ {{ rowProps.value }}
67
+ </a>
68
+ </template>
69
+ <template v-else>
70
+ <slot v-bind="{name: rowProps.col.name, row: rowProps.row, value: rowProps.value}">
71
+ {{ rowProps.value }}
72
+ </slot>
73
+ </template>
74
+ </QTd>
75
+ </template>
76
+ </QTable>
77
+ </template>
78
+
79
+ <script setup>
80
+ import { DragHandleIcon as RowResizeIcon } from "@/svg";
81
+ import { EmptyTableState, registerStickyScrolling, RenderComponentColumn, TableSummaryRow } from "danx/src/components";
82
+ import { HandleDraggable } from "quasar-ui-danx/src";
83
+ import { ref } from "vue";
84
+
85
+ defineEmits(["action", "filter", "update:quasar-pagination", "update:selected-rows"]);
86
+ defineProps({
87
+ label: {
88
+ type: String,
89
+ required: true
90
+ },
91
+ selectedRows: {
92
+ type: Array,
93
+ required: true
94
+ },
95
+ quasarPagination: {
96
+ type: Object,
97
+ required: true
98
+ },
99
+ isLoadingList: Boolean,
100
+ pagedItems: {
101
+ type: Object,
102
+ default: null
103
+ },
104
+ isLoadingSummary: Boolean,
105
+ summary: {
106
+ type: Object,
107
+ default: null
108
+ },
109
+ columns: {
110
+ type: Array,
111
+ required: true
112
+ }
113
+ });
114
+ const actionTable = ref(null);
115
+ registerStickyScrolling(actionTable);
116
+ </script>
117
+
118
+ <style lang="scss" scoped>
119
+ [data-drop-zone] {
120
+ .resize-handle {
121
+ position: absolute;
122
+ top: 0;
123
+ right: -.45em;
124
+ width: .9em;
125
+ opacity: 0;
126
+ transition: all .3s;
127
+ }
128
+
129
+ &:hover {
130
+ .resize-handle {
131
+ opacity: 1;
132
+ }
133
+ }
134
+ }
135
+ </style>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div>
3
+ <PopoverMenu
4
+ class="bg-neutral-plus-6 px-4 h-full flex"
5
+ :items="items"
6
+ :disabled="selectedRows.length === 0"
7
+ @action="onAction"
8
+ />
9
+ <QTooltip v-if="selectedRows.length === 0">
10
+ Batch actions require a selection
11
+ </QTooltip>
12
+ <slot>
13
+ <Component
14
+ :is="activeComponent.is"
15
+ v-if="activeComponent"
16
+ v-bind="activeComponent.props"
17
+ :is-saving="isSaving"
18
+ @close="activeAction = false"
19
+ @confirm="onConfirmAction"
20
+ />
21
+ </slot>
22
+ </div>
23
+ </template>
24
+ <script setup>
25
+ import PopoverMenu from "components/Common/Menu/PopoverMenu";
26
+ import { computed, ref } from "vue";
27
+
28
+ const emit = defineEmits(["action"]);
29
+ const props = defineProps({
30
+ items: {
31
+ type: Array,
32
+ required: true
33
+ },
34
+ selectedRows: {
35
+ type: Array,
36
+ required: true
37
+ },
38
+ applyBatchAction: {
39
+ type: Function,
40
+ required: true
41
+ },
42
+ isSaving: Boolean
43
+ });
44
+
45
+
46
+ const activeAction = ref(null);
47
+ const activeComponent = computed(() => (props.items.find(i => i.action === activeAction.value)?.component || (() => null))(props.selectedRows));
48
+
49
+ function onAction(action) {
50
+ activeAction.value = action;
51
+ emit("action", action);
52
+ }
53
+ async function onConfirmAction(input) {
54
+ const result = await props.applyBatchAction(input || activeComponent.value.input());
55
+
56
+ if (result?.success) {
57
+ activeAction.value = null;
58
+ }
59
+ }
60
+ </script>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <div class="flex items-center justify-center text-sm py-14 w-full">
3
+ <div v-if="loading">
4
+ <slot name="loading">{{ loadingText }}
5
+ <QSpinnerBall class="w-4 ml-2" />
6
+ </slot>
7
+ </div>
8
+ <div v-if="saving">
9
+ <slot name="saving">{{ savingText }}
10
+ <QSpinnerBall class="w-4 ml-2" />
11
+ </slot>
12
+ </div>
13
+ <slot>{{ text }}</slot>
14
+ </div>
15
+ </template>
16
+ <script setup>
17
+ defineProps({
18
+ loading: Boolean,
19
+ saving: Boolean,
20
+ text: {
21
+ type: String,
22
+ default: "No records found"
23
+ },
24
+ loadingText: {
25
+ type: String,
26
+ default: "Loading..."
27
+ },
28
+ savingText: {
29
+ type: String,
30
+ default: "Saving..."
31
+ }
32
+ });
33
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <CollapsableSidebar
3
+ :collapse="!showFilters"
4
+ disabled
5
+ min-width="0"
6
+ max-width="18rem"
7
+ name="admin-ads"
8
+ @update:collapse="$emit('update:show-filters', !$event)"
9
+ >
10
+ <FilterGroupList
11
+ :filter="filter"
12
+ :filter-groups="filterGroups"
13
+ @update:filter="$emit('update:filter', $event)"
14
+ />
15
+ </CollapsableSidebar>
16
+ </template>
17
+ <script setup>
18
+ import { CollapsableSidebar, FilterGroupList } from "danx/src/components";
19
+
20
+ defineEmits(["update:filter", "update:show-filters"]);
21
+ defineProps({
22
+ name: {
23
+ type: String,
24
+ required: true
25
+ },
26
+ showFilters: Boolean,
27
+ filter: {
28
+ type: Object,
29
+ default: null
30
+ },
31
+ filterGroups: {
32
+ type: Array,
33
+ default: () => []
34
+ }
35
+ });
36
+ </script>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <QExpansionItem>
3
+ <template #header>
4
+ <div class="flex items-center flex-nowrap flex-grow">
5
+ <div class="whitespace-nowrap flex-grow text-left text-sm font-bold">{{ name }}</div>
6
+ <QBadge
7
+ :label="count"
8
+ rounded
9
+ class="ml-2 transition-all"
10
+ :class="{'bg-gray-base': !count, 'bg-blue-base': count}"
11
+ />
12
+ </div>
13
+ </template>
14
+ <slot />
15
+ </QExpansionItem>
16
+ </template>
17
+ <script setup>
18
+ defineProps({
19
+ name: {
20
+ type: String,
21
+ required: true
22
+ },
23
+ count: {
24
+ type: Number,
25
+ required: true
26
+ }
27
+ });
28
+ </script>
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <QList>
3
+ <div class="px-4 py-2 max-w-full">
4
+ <template
5
+ v-for="(group, index) in filterGroups"
6
+ :key="'group-' + group.name"
7
+ >
8
+ <template v-if="group.flat">
9
+ <FilterableField
10
+ v-for="field in group.fields"
11
+ :key="'field-' + field.name"
12
+ :model-value="field.calcValue ? field.calcValue(filter) : filter[field.name]"
13
+ :field="field"
14
+ :loading="loading"
15
+ class="mb-4"
16
+ @update:model-value="updateFilter(field, $event)"
17
+ />
18
+ </template>
19
+
20
+ <FilterGroupItem
21
+ v-else
22
+ :name="group.name"
23
+ :count="activeCountByGroup[group.name]"
24
+ >
25
+ <FilterableField
26
+ v-for="field in group.fields"
27
+ :key="'field-' + field.name"
28
+ :model-value="field.calcValue ? field.calcValue(filter) : filter[field.name]"
29
+ :field="field"
30
+ :loading="loading"
31
+ class="mb-4"
32
+ @update:model-value="updateFilter(field, $event)"
33
+ />
34
+ </FilterGroupItem>
35
+
36
+ <QSeparator
37
+ v-if="index < (filterGroups.length - 1)"
38
+ class="my-2"
39
+ />
40
+ </template>
41
+ </div>
42
+ </QList>
43
+ </template>
44
+ <script setup>
45
+ import FilterableField from "danx/src/components/ActionTable/Filters/FilterableField";
46
+ import FilterGroupItem from "danx/src/components/ActionTable/Filters/FilterGroupItem";
47
+ import { computed } from "vue";
48
+
49
+ const emit = defineEmits(["update:filter"]);
50
+ const props = defineProps({
51
+ filterGroups: {
52
+ type: Array,
53
+ required: true
54
+ },
55
+ filter: {
56
+ type: Object,
57
+ required: true
58
+ },
59
+ loading: Boolean
60
+ });
61
+
62
+ const activeCountByGroup = computed(() => {
63
+ const activeCountByGroup = {};
64
+ for (const group of props.filterGroups) {
65
+ activeCountByGroup[group.name] = group.fields.filter(field => props.filter[field.name] !== undefined).length;
66
+ }
67
+ return activeCountByGroup;
68
+ });
69
+ function updateFilter(field, value) {
70
+ let fieldFilter = { [field.name]: value };
71
+ if (field.filterBy) {
72
+ fieldFilter = field.filterBy(value);
73
+ }
74
+ emit("update:filter", { ...props.filter, ...fieldFilter });
75
+ }
76
+ </script>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <div class="flex items-center" :class="{'w-72': showFilters}">
3
+ <div class="flex-grow">
4
+ <QBtn
5
+ class="btn-blue-highlight"
6
+ :class="{'highlighted': showFilters}"
7
+ @click="$emit('update:show-filters', !showFilters)"
8
+ >
9
+ <FilterIcon class="w-5 mr-2" />
10
+ <QBadge
11
+ :label="'' + activeCount"
12
+ rounded
13
+ :color="activeCount > 0 ? 'blue-base' : 'gray-base'"
14
+ />
15
+ </QBtn>
16
+ </div>
17
+ <a
18
+ v-if="activeCount > 0"
19
+ class="text-blue-base hover:text-blue-plus-1 text-sm ml-4"
20
+ @click="$emit('update:filter', {})"
21
+ >Clear All</a>
22
+ </div>
23
+ </template>
24
+ <script setup>
25
+ import { FilterIcon } from "@/svg";
26
+ import { computed } from "vue";
27
+
28
+ defineEmits(["update:show-filters", "update:filter"]);
29
+ const props = defineProps({
30
+ filter: {
31
+ type: Object,
32
+ required: true
33
+ },
34
+ filterGroups: {
35
+ type: Array,
36
+ required: true
37
+ },
38
+ showFilters: Boolean
39
+ });
40
+
41
+ const filterNameDictionary = computed(() => {
42
+ return props.filterGroups.reduce((acc, fg) => {
43
+ fg.fields.forEach(f => {
44
+ acc[f.name] = true;
45
+ });
46
+ return acc;
47
+ }, {});
48
+ });
49
+ const activeCount = computed(() => Object.keys(props.filter).filter(key => props.filter[key] !== undefined && filterNameDictionary.value[key]).length);
50
+ </script>
@@ -0,0 +1,141 @@
1
+ <template>
2
+ <div>
3
+ <template v-if="field.type === 'multi-select'">
4
+ <SelectField
5
+ v-if="field.options?.length > 0 || loading"
6
+ :model-value="modelValue"
7
+ :options="field.options"
8
+ multiple
9
+ :loading="loading"
10
+ :chip-limit="1"
11
+ filterable
12
+ :placeholder="field.placeholder"
13
+ :label="field.label"
14
+ @update:model-value="onUpdate"
15
+ />
16
+ <div
17
+ v-else
18
+ class="mt-2"
19
+ >
20
+ <div class="text-xs font-bold">{{ field.label }}</div>
21
+ <div class="text-sm ml-3 py-2">No Available Options</div>
22
+ </div>
23
+ </template>
24
+
25
+ <SelectField
26
+ v-else-if="field.type === 'single-select'"
27
+ :model-value="modelValue"
28
+ :options="field.options"
29
+ :placeholder="field.placeholder"
30
+ :loading="loading"
31
+ :label="field.label"
32
+ @update:model-value="onUpdate"
33
+ />
34
+ <DateField
35
+ v-else-if="field.type === 'date'"
36
+ :model-value="modelValue"
37
+ :label="field.label"
38
+ class="mt-2"
39
+ @update:model-value="onUpdate"
40
+ />
41
+ <DateRangeField
42
+ v-else-if="field.type === 'date-range'"
43
+ :model-value="modelValue"
44
+ :label="field.label"
45
+ :inline="field.inline"
46
+ with-time
47
+ class="mt-2 reactive"
48
+ @update:model-value="onUpdate"
49
+ />
50
+ <NumberRangeField
51
+ v-else-if="field.type === 'number-range'"
52
+ :model-value="modelValue"
53
+ :label="field.label"
54
+ class="mt-2"
55
+ :debounce="1000"
56
+ @update:model-value="onUpdate"
57
+ />
58
+ <NumberRangeField
59
+ v-else-if="field.type === 'currency-range'"
60
+ :model-value="modelValue"
61
+ :label="field.label"
62
+ class="mt-2"
63
+ :debounce="1000"
64
+ currency
65
+ @update:model-value="onUpdate"
66
+ />
67
+ <NumberRangeField
68
+ v-else-if="field.type === 'percent-range'"
69
+ :model-value="modelValue"
70
+ :label="field.label"
71
+ class="mt-2"
72
+ :debounce="1000"
73
+ percent
74
+ @update:model-value="onUpdate"
75
+ />
76
+ <BooleanField
77
+ v-else-if="field.type === 'boolean'"
78
+ :field="field"
79
+ :model-value="modelValue"
80
+ class="mt-2"
81
+ label-class="text-xs font-bold"
82
+ @update:model-value="onUpdate"
83
+ />
84
+ <MultiKeywordField
85
+ v-else-if="field.type === 'multi-keywords'"
86
+ :model-value="modelValue"
87
+ :field="field"
88
+ @update:model-value="onUpdate"
89
+ />
90
+ <SelectWithChildrenField
91
+ v-else-if="field.type === 'select-with-children'"
92
+ :model-value="modelValue"
93
+ :options="field.options"
94
+ :loading="loading"
95
+ :label="field.label"
96
+ :placeholder="field.placeholder"
97
+ @update:model-value="onUpdate"
98
+ />
99
+ <template v-else>
100
+ Field &quot;{{ field.name }}&quot;: Unknown filter type {{ field.type }}
101
+ </template>
102
+ </div>
103
+ </template>
104
+ <script setup>
105
+ import BooleanField from "danx/src/components/ActionTable/Form/Fields/BooleanField";
106
+ import DateField from "danx/src/components/ActionTable/Form/Fields/DateField";
107
+ import DateRangeField from "danx/src/components/ActionTable/Form/Fields/DateRangeField";
108
+ import MultiKeywordField from "danx/src/components/ActionTable/Form/Fields/MultiKeywordField";
109
+ import NumberRangeField from "danx/src/components/ActionTable/Form/Fields/NumberRangeField";
110
+ import SelectField from "danx/src/components/ActionTable/Form/Fields/SelectField";
111
+ import SelectWithChildrenField from "danx/src/components/ActionTable/Form/Fields/SelectWithChildrenField";
112
+
113
+ const emit = defineEmits(["update:model-value"]);
114
+ const props = defineProps({
115
+ field: {
116
+ type: Object,
117
+ required: true
118
+ },
119
+ modelValue: {
120
+ type: [String, Array, Number, Object, Boolean],
121
+ default: undefined
122
+ },
123
+ loading: Boolean
124
+ });
125
+
126
+ function onUpdate(val) {
127
+ let newVal = val || undefined;
128
+
129
+ switch (props.field.type) {
130
+ case "multi-select":
131
+ newVal = val.length > 0 ? val : undefined;
132
+ break;
133
+ case "single-select":
134
+ case "boolean":
135
+ newVal = val === null ? undefined : val;
136
+ break;
137
+ }
138
+
139
+ emit("update:model-value", newVal);
140
+ }
141
+ </script>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <QToggle
3
+ :data-testid="'boolean-field-' + field.id"
4
+ :model-value="modelValue"
5
+ :toggle-indeterminate="toggleIndeterminate"
6
+ :indeterminate-value="undefined"
7
+ @update:model-value="$emit('update:model-value', $event)"
8
+ >
9
+ <FieldLabel
10
+ :field="field"
11
+ :show-name="showName"
12
+ :class="labelClass"
13
+ />
14
+ </QToggle>
15
+ </template>
16
+
17
+ <script setup>
18
+ import FieldLabel from "./FieldLabel";
19
+
20
+ defineEmits(["update:model-value"]);
21
+ defineProps({
22
+ modelValue: {
23
+ type: [Boolean],
24
+ default: undefined
25
+ },
26
+ field: {
27
+ type: Object,
28
+ required: true
29
+ },
30
+ labelClass: {
31
+ type: String,
32
+ default: "text-sm"
33
+ },
34
+ showName: Boolean,
35
+ toggleIndeterminate: Boolean
36
+ });
37
+ </script>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <LabeledInput
3
+ type="password"
4
+ v-bind="props"
5
+ :rules="rules"
6
+ @update:model-value="$emit('update:model-value', $event)"
7
+ />
8
+ </template>
9
+
10
+ <script setup>
11
+ import LabeledInput from "danx/src/components/ActionTable/Form/Fields/LabeledInput";
12
+
13
+ defineEmits(["update:model-value"]);
14
+ const props = defineProps({
15
+ name: {
16
+ type: String,
17
+ default: "password_confirmation"
18
+ },
19
+ label: {
20
+ type: String,
21
+ default: "Confirm Password"
22
+ },
23
+ placeholder: {
24
+ type: String,
25
+ default: "Confirm Password"
26
+ },
27
+ modelValue: {
28
+ type: [String, Number],
29
+ required: true
30
+ },
31
+ error: {
32
+ type: String,
33
+ default: null
34
+ },
35
+ password: {
36
+ type: String,
37
+ default: ""
38
+ },
39
+ disabled: Boolean
40
+ });
41
+
42
+ const rules = [
43
+ (val) =>
44
+ val === props.password || "The password and confirmation do not match"
45
+ ];
46
+ </script>