quasar-ui-danx 0.0.10 → 0.0.11

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 (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
@@ -0,0 +1,119 @@
1
+ <template>
2
+ <div
3
+ class="collapsable-sidebar overflow-x-hidden overflow-y-scroll relative"
4
+ :class="{
5
+ 'is-collapsed': isCollapsed,
6
+ 'is-right-side': rightSide,
7
+ [displayClass]: true,
8
+ }"
9
+ :style="style"
10
+ >
11
+ <div class="flex-grow max-w-full">
12
+ <slot :is-collapsed="isCollapsed" />
13
+ </div>
14
+ <template v-if="!disabled && (!hideToggleOnCollapse || !isCollapsed)">
15
+ <div
16
+ v-if="!toggleAtTop"
17
+ class="flex w-full p-4"
18
+ :class="rightSide ? 'justify-start' : 'justify-end'"
19
+ >
20
+ <slot name="toggle">
21
+ <QBtn
22
+ class="btn-white-gray"
23
+ @click="toggleCollapse"
24
+ >
25
+ <ToggleIcon
26
+ class="w-5 transition-all"
27
+ :class="{ 'rotate-180': rightSide ? !isCollapsed : isCollapsed }"
28
+ />
29
+ </QBtn>
30
+ </slot>
31
+ </div>
32
+ <div
33
+ v-else
34
+ class="absolute top-0 right-0 cursor-pointer p-2"
35
+ :class="toggleClass"
36
+ @click="toggleCollapse"
37
+ >
38
+ <ToggleIcon
39
+ class="w-5 transition-all"
40
+ :class="{ 'rotate-180': rightSide ? !isCollapsed : isCollapsed }"
41
+ />
42
+ </div>
43
+ </template>
44
+ </div>
45
+ </template>
46
+ <script setup>
47
+ import { ChevronLeftIcon as ToggleIcon } from "@heroicons/vue/outline";
48
+ import { computed, onMounted, ref, watch } from "vue";
49
+
50
+ const emit = defineEmits(["collapse", "update:collapse"]);
51
+ const props = defineProps({
52
+ rightSide: Boolean,
53
+ displayClass: {
54
+ type: String,
55
+ default: "flex flex-col"
56
+ },
57
+ maxWidth: {
58
+ type: String,
59
+ default: "13.5rem"
60
+ },
61
+ minWidth: {
62
+ type: String,
63
+ default: "5.5rem"
64
+ },
65
+ disabled: Boolean,
66
+ collapse: Boolean,
67
+ name: {
68
+ type: String,
69
+ default: "sidebar"
70
+ },
71
+ toggleAtTop: Boolean,
72
+ toggleClass: {
73
+ type: String,
74
+ default: ""
75
+ },
76
+ hideToggleOnCollapse: Boolean
77
+ });
78
+
79
+ const isCollapsed = ref(props.collapse);
80
+
81
+ const stored = localStorage.getItem(props.name + "-is-collapsed");
82
+
83
+ if (stored !== null) {
84
+ isCollapsed.value = stored === "1";
85
+ }
86
+ function toggleCollapse() {
87
+ setCollapse(!isCollapsed.value);
88
+ emit("collapse", isCollapsed.value);
89
+ emit("update:collapse", isCollapsed.value);
90
+ }
91
+
92
+ function setCollapse(state) {
93
+ isCollapsed.value = state;
94
+ localStorage.setItem(props.name + "-is-collapsed", isCollapsed.value ? "1" : "");
95
+ }
96
+
97
+ onMounted(() => {
98
+ emit("collapse", isCollapsed.value);
99
+ emit("update:collapse", isCollapsed.value);
100
+ });
101
+ const style = computed(() => {
102
+ return {
103
+ width: isCollapsed.value ? props.minWidth : props.maxWidth
104
+ };
105
+ });
106
+
107
+ watch(() => props.collapse, () => {
108
+ setCollapse(props.collapse);
109
+ });
110
+ </script>
111
+
112
+ <style
113
+ scoped
114
+ lang="scss"
115
+ >
116
+ .collapsable-sidebar {
117
+ @apply overflow-y-auto scroll-smooth flex-shrink-0 border-r border-neutral-plus-5 transition-all;
118
+ }
119
+ </style>
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <QDialog
3
+ v-model="isShowing"
4
+ maximized
5
+ :position="position"
6
+ :seamless="seamless"
7
+ :class="{'hide-backdrop': !overlay}"
8
+ >
9
+ <div>
10
+ <div
11
+ v-if="title"
12
+ class="dialog-title"
13
+ @click.stop.prevent
14
+ >
15
+ {{ title }}
16
+ </div>
17
+ <div
18
+ class="dialog-content bg-white"
19
+ :class="{ [contentClass]: true }"
20
+ >
21
+ <slot />
22
+ </div>
23
+ </div>
24
+ </QDialog>
25
+ </template>
26
+
27
+ <script setup>
28
+ import { computed } from "vue";
29
+
30
+ const emit = defineEmits(["update:show"]);
31
+
32
+ const props = defineProps({
33
+ show: Boolean,
34
+ seamless: Boolean,
35
+ overlay: Boolean,
36
+ position: {
37
+ type: String,
38
+ default: "bottom"
39
+ },
40
+ contentClass: {
41
+ type: String,
42
+ default: "py-8 px-12"
43
+ },
44
+ title: {
45
+ type: String,
46
+ default: "Edit"
47
+ }
48
+ });
49
+
50
+ const isShowing = computed({
51
+ get: () => props.show,
52
+ set: (value) => emit("update:show", value)
53
+ });
54
+ </script>
55
+
56
+ <style
57
+ lang="scss"
58
+ scoped
59
+ >
60
+ .dialog-title {
61
+ @apply bg-gray-very-light text-gray-default font-medium uppercase text-xs px-6 py-3 border-b border-neutral-plus-5 rounded-t-md;
62
+ font-family: "Roboto", sans-serif;
63
+ letter-spacing: 0.05em;
64
+ box-shadow: 0px -4px 12px rgba(0, 0, 0, 0.25);
65
+ }
66
+
67
+ .dialog-content {
68
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
69
+ }
70
+ </style>
@@ -0,0 +1,132 @@
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"
9
+ >
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-medium"
14
+ >
15
+ <h3
16
+ class="font-normal flex items-center"
17
+ :class="titleClass"
18
+ >
19
+ <slot name="title">{{ title }}</slot>
20
+ </h3>
21
+ <div
22
+ v-if="subtitle"
23
+ class="mt-1 text-sm"
24
+ >{{ subtitle }}
25
+ </div>
26
+ </QCardSection>
27
+ <QCardSection v-if="$slots.toolbar">
28
+ <slot name="toolbar" />
29
+ </QCardSection>
30
+ <QCardSection
31
+ v-if="content || $slots.default"
32
+ class="px-6 bg-neutral-plus-7 flex-grow max-h-full overflow-y-auto"
33
+ :class="contentClass"
34
+ >
35
+ <slot>{{ content }}</slot>
36
+ </QCardSection>
37
+ <div class="flex px-6 py-4 border-t border-gray-medium">
38
+ <div class="flex-grow">
39
+ <QBtn
40
+ :label="cancelText"
41
+ class="action-btn btn-white-gray"
42
+ @click="onClose"
43
+ >
44
+ <slot name="cancel-text" />
45
+ </QBtn>
46
+ </div>
47
+ <slot name="actions" />
48
+ <div v-if="!hideConfirm">
49
+ <QBtn
50
+ :label="$slots['confirm-text'] ? '' : confirmText"
51
+ class="action-btn ml-4"
52
+ :class="confirmClass"
53
+ :loading="isSaving"
54
+ :disable="disabled"
55
+ data-testid="confirm-button"
56
+ @click="onConfirm"
57
+ >
58
+ <slot name="confirm-text" />
59
+ </QBtn>
60
+ </div>
61
+ </div>
62
+ <a
63
+ class="absolute top-0 right-0 p-4 text-black"
64
+ @click="onClose"
65
+ >
66
+ <CloseIcon class="w-5" />
67
+ </a>
68
+ </QCard>
69
+ </QDialog>
70
+ </template>
71
+
72
+ <script setup>
73
+ import { XIcon as CloseIcon } from "@heroicons/vue/outline";
74
+
75
+ const emit = defineEmits(["update:model-value", "confirm", "close"]);
76
+ const props = defineProps({
77
+ modelValue: { type: [String, Boolean, Object], default: true },
78
+ title: {
79
+ type: String,
80
+ default: ""
81
+ },
82
+ titleClass: {
83
+ type: String,
84
+ default: ""
85
+ },
86
+ subtitle: {
87
+ type: String,
88
+ default: ""
89
+ },
90
+ content: {
91
+ type: String,
92
+ default: ""
93
+ },
94
+ backdropDismiss: Boolean,
95
+ maximized: Boolean,
96
+ fullWidth: Boolean,
97
+ fullHeight: Boolean,
98
+ disabled: Boolean,
99
+ isSaving: Boolean,
100
+ closeOnConfirm: Boolean,
101
+ hideConfirm: Boolean,
102
+ confirmText: {
103
+ type: String,
104
+ default: "Confirm"
105
+ },
106
+ cancelText: {
107
+ type: String,
108
+ default: "Cancel"
109
+ },
110
+ confirmClass: {
111
+ type: String,
112
+ default: "bg-blue-base text-white"
113
+ },
114
+ contentClass: {
115
+ type: String,
116
+ default: ""
117
+ }
118
+ });
119
+
120
+ function onConfirm() {
121
+ emit("confirm");
122
+
123
+ if (props.closeOnConfirm) {
124
+ emit("close");
125
+ }
126
+ }
127
+
128
+ function onClose() {
129
+ emit("update:model-value", false);
130
+ emit("close");
131
+ }
132
+ </script>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <QDialog
3
+ :model-value="modelValue"
4
+ maximized
5
+ transition-show="slide-up"
6
+ transition-hide="slide-down"
7
+ @update:model-value="onClose"
8
+ >
9
+ <div class="flex justify-center min-w-xs" :class="computedClass">
10
+ <div
11
+ v-if="closeable"
12
+ v-close-popup
13
+ class="p-4 m-4 absolute-top-right top right cursor-pointer"
14
+ >
15
+ <XIcon class="w-5 h-5" />
16
+ </div>
17
+ <slot />
18
+ </div>
19
+ </QDialog>
20
+ </template>
21
+
22
+ <script setup>
23
+ import { XIcon } from "src/svg";
24
+ import { computed } from "vue";
25
+
26
+ const emit = defineEmits(["update:model-value", "close"]);
27
+ const props = defineProps({
28
+ modelValue: Boolean,
29
+ center: Boolean,
30
+ blue: Boolean,
31
+ closeable: Boolean
32
+ });
33
+
34
+ let computedClass = computed(() => {
35
+ return {
36
+ "bg-blue-base text-white": props.blue,
37
+ "bg-white text-gray-base": !props.blue,
38
+ "items-center": props.center
39
+ };
40
+ });
41
+
42
+ function onClose() {
43
+ emit("update:model-value", false);
44
+ emit("close");
45
+ }
46
+ </script>
@@ -0,0 +1,92 @@
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"
9
+ >
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-medium"
14
+ >
15
+ <h3
16
+ class="font-normal flex items-center"
17
+ :class="titleClass"
18
+ >
19
+ <slot name="title">{{ title }}</slot>
20
+ </h3>
21
+ <div
22
+ v-if="subtitle"
23
+ class="mt-1 text-sm"
24
+ >{{ subtitle }}
25
+ </div>
26
+ </QCardSection>
27
+ <QCardSection
28
+ v-if="content || $slots.default"
29
+ class="px-6 bg-neutral-plus-7 flex-grow max-h-full overflow-y-auto"
30
+ >
31
+ <slot>{{ content }}</slot>
32
+ </QCardSection>
33
+ <div
34
+ class="flex items-center justify-center px-6 py-4 border-t border-gray-medium"
35
+ >
36
+ <div class="flex-grow text-right">
37
+ <QBtn
38
+ :label="doneText"
39
+ class="action-btn btn-white-gray"
40
+ @click="onClose"
41
+ >
42
+ <slot name="done-text" />
43
+ </QBtn>
44
+ </div>
45
+ </div>
46
+ <a
47
+ class="absolute top-0 right-0 p-4 text-black"
48
+ @click="onClose"
49
+ >
50
+ <CloseIcon class="w-5" />
51
+ </a>
52
+ </QCard>
53
+ </QDialog>
54
+ </template>
55
+
56
+ <script setup>
57
+ import { XIcon as CloseIcon } from "@heroicons/vue/outline";
58
+
59
+ const emit = defineEmits(["update:model-value", "close"]);
60
+ defineProps({
61
+ modelValue: { type: [Boolean, Object], default: true },
62
+ title: {
63
+ type: String,
64
+ default: ""
65
+ },
66
+ titleClass: {
67
+ type: String,
68
+ default: ""
69
+ },
70
+ subtitle: {
71
+ type: String,
72
+ default: ""
73
+ },
74
+ content: {
75
+ type: String,
76
+ default: ""
77
+ },
78
+ backdropDismiss: Boolean,
79
+ maximized: Boolean,
80
+ fullWidth: Boolean,
81
+ fullHeight: Boolean,
82
+ doneText: {
83
+ type: String,
84
+ default: "Done"
85
+ }
86
+ });
87
+
88
+ function onClose() {
89
+ emit("update:model-value", false);
90
+ emit("close");
91
+ }
92
+ </script>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <ConfirmDialog
3
+ v-bind="$props"
4
+ @confirm="$emit('confirm', newInput)"
5
+ @close="$emit('close', $event)"
6
+ >
7
+ <slot>
8
+ <QInput
9
+ v-model="newInput"
10
+ type="number"
11
+ class="w-full"
12
+ @input="$emit('update:input', $event)"
13
+ />
14
+ </slot>
15
+ </ConfirmDialog>
16
+ </template>
17
+ <script setup>
18
+ import ConfirmDialog from "danx/src/components/Utility/Dialogs/ConfirmDialog";
19
+ import { ref } from "vue";
20
+
21
+ defineEmits(["confirm", "close", "update:input"]);
22
+ const props = defineProps({
23
+ ...ConfirmDialog.props,
24
+ title: {
25
+ type: String,
26
+ default: "Enter Value"
27
+ },
28
+ input: {
29
+ type: [Number, String],
30
+ default: ""
31
+ }
32
+ });
33
+
34
+ const newInput = ref(props.input);
35
+ </script>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <TransitionGroup tag="div" :name="name" class="relative">
3
+ <slot />
4
+ </TransitionGroup>
5
+ </template>
6
+
7
+ <script setup>
8
+ defineProps({
9
+ name: {
10
+ type: String,
11
+ default: "fade-list"
12
+ }
13
+ });
14
+ </script>
15
+
16
+ <style lang="scss">
17
+ [class*="list-move"], /* apply transition to moving elements */
18
+ [class*="list-enter-active"],
19
+ [class*=".list-leave-active"] {
20
+ transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1);
21
+ }
22
+
23
+ /* ensure leaving items are taken out of layout flow so that moving
24
+ animations can be calculated correctly. */
25
+ [class*="list-leave-active"] {
26
+ position: absolute !important;
27
+ }
28
+
29
+ /** Default List */
30
+ .list-enter-from,
31
+ .list-leave-to {
32
+ opacity: 0;
33
+ transform: translateX(30px);
34
+ }
35
+
36
+ /** Fade */
37
+ .fade-list-enter-from,
38
+ .fade-list-leave-to {
39
+ opacity: 0;
40
+ transform: scaleY(0.01) translate(30px, 0);
41
+ }
42
+
43
+ /** Fade Down */
44
+ .fade-down-list-enter-from,
45
+ .fade-down-list-leave-to {
46
+ opacity: 0;
47
+ transform-origin: top;
48
+ transform: translateY(30px);
49
+ }
50
+ </style>
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <Transition :name="name">
3
+ <slot />
4
+ </Transition>
5
+ </template>
6
+
7
+ <script setup>
8
+ defineProps({
9
+ name: {
10
+ type: String,
11
+ default: "slide"
12
+ }
13
+ });
14
+ </script>
15
+ <style lang="scss">
16
+ .slide-enter-active,
17
+ .slide-leave-active,
18
+ .slide-right-enter-active,
19
+ .slide-right-leave-active {
20
+ transition: all 0.3s linear;
21
+ width: 100%;
22
+ }
23
+
24
+ .slide-right-enter-active,
25
+ .slide-enter-active {
26
+ position: absolute !important;
27
+ top: 0;
28
+ }
29
+
30
+ /** Slide Left (default) */
31
+ .slide-enter-from {
32
+ right: -120%;
33
+ }
34
+
35
+ .slide-enter-to {
36
+ right: 0;
37
+ }
38
+
39
+ .slide-leave-to {
40
+ left: -120%;
41
+ }
42
+
43
+ .slide-leave-from {
44
+ left: 0;
45
+ }
46
+
47
+ /** Slide Right */
48
+ .slide-right-enter-from {
49
+ left: -120%;
50
+ }
51
+
52
+ .slide-right-enter-to {
53
+ left: 0;
54
+ }
55
+
56
+ .slide-right-leave-to {
57
+ right: -120%;
58
+ }
59
+
60
+ .slide-right-leave-from {
61
+ right: 0;
62
+ }
63
+ </style>
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <TransitionGroup
3
+ ref="list"
4
+ tag="div"
5
+ appear
6
+ :css="false"
7
+ @before-enter="onBeforeEnter"
8
+ @enter="onEnter"
9
+ @leave="onLeave"
10
+ >
11
+ <slot />
12
+ </TransitionGroup>
13
+ </template>
14
+
15
+ <script setup>
16
+ import gsap from "gsap";
17
+ import { isTestMode } from "src/helpers/testing";
18
+ import { computed, ref } from "vue";
19
+
20
+ const props = defineProps({
21
+ height: {
22
+ type: [String, Number],
23
+ default: "auto"
24
+ },
25
+ duration: {
26
+ type: Number,
27
+ default: 0.5
28
+ },
29
+ delayOffset: {
30
+ type: Number,
31
+ default: 0.5
32
+ }
33
+ });
34
+
35
+ const list = ref(null);
36
+ const indexDelay = computed(() => {
37
+ return props.delayOffset / list.value.$el.children.length;
38
+ });
39
+
40
+ function onBeforeEnter(el) {
41
+ if (isTestMode.value) {
42
+ return;
43
+ }
44
+ el.style.opacity = 0;
45
+ el.style.height = 0;
46
+ }
47
+
48
+ function onEnter(el, onComplete) {
49
+ if (isTestMode.value) {
50
+ onComplete();
51
+ return;
52
+ }
53
+
54
+ gsap.to(el, {
55
+ opacity: 1,
56
+ duration: props.duration,
57
+ height: props.height,
58
+ delay: el.dataset.index * indexDelay.value,
59
+ onComplete
60
+ });
61
+ }
62
+
63
+ function onLeave(el, onComplete) {
64
+ if (isTestMode.value) {
65
+ onComplete();
66
+ return;
67
+ }
68
+
69
+ gsap.to(el, {
70
+ opacity: 0,
71
+ height: 0,
72
+ duration: props.duration,
73
+ delay: el.dataset.index * indexDelay.value,
74
+ onComplete
75
+ });
76
+ }
77
+ </script>
78
+
79
+ <style scoped lang="scss">
80
+ .list-move,
81
+ .list-enter-active,
82
+ .list-leave-active {
83
+ transition: all 0.5s ease;
84
+ }
85
+
86
+ .list-enter-from,
87
+ .list-leave-to {
88
+ opacity: 0;
89
+ transform: translateX(2em);
90
+ }
91
+
92
+ /* ensure leaving items are taken out of layout flow so that moving
93
+ animations can be calculated correctly. */
94
+ .list-leave-active {
95
+ position: absolute;
96
+ }
97
+ </style>