quasar-ui-danx 0.4.27 → 0.4.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. package/dist/danx.es.js +24536 -24082
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +109 -109
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +1 -1
  7. package/src/components/ActionTable/ActionTable.vue +29 -7
  8. package/src/components/ActionTable/Filters/FilterableField.vue +14 -2
  9. package/src/components/ActionTable/Form/ActionForm.vue +17 -12
  10. package/src/components/ActionTable/Form/Fields/DateField.vue +24 -20
  11. package/src/components/ActionTable/Form/Fields/DateRangeField.vue +57 -53
  12. package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +9 -2
  13. package/src/components/ActionTable/Form/Fields/EditableDiv.vue +12 -12
  14. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +1 -1
  15. package/src/components/ActionTable/Form/Fields/SelectField.vue +27 -6
  16. package/src/components/ActionTable/Form/Fields/SelectOrCreateField.vue +56 -0
  17. package/src/components/ActionTable/Form/Fields/index.ts +1 -0
  18. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +20 -23
  19. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +44 -36
  20. package/src/components/ActionTable/listControls.ts +3 -3
  21. package/src/components/DragAndDrop/ListItemDraggable.vue +38 -28
  22. package/src/components/DragAndDrop/dragAndDrop.ts +220 -220
  23. package/src/components/DragAndDrop/listDragAndDrop.ts +256 -227
  24. package/src/components/PanelsDrawer/PanelsDrawer.vue +7 -7
  25. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +3 -3
  26. package/src/components/Utility/Buttons/ShowHideButton.vue +86 -0
  27. package/src/components/Utility/Buttons/index.ts +1 -0
  28. package/src/components/Utility/Dialogs/ActionFormDialog.vue +30 -0
  29. package/src/components/Utility/Dialogs/CreateNewWithNameDialog.vue +26 -0
  30. package/src/components/Utility/Dialogs/RenderedFormDialog.vue +50 -0
  31. package/src/components/Utility/Dialogs/index.ts +3 -0
  32. package/src/helpers/actions.ts +84 -20
  33. package/src/helpers/formats.ts +23 -20
  34. package/src/helpers/objectStore.ts +24 -12
  35. package/src/types/actions.d.ts +12 -6
  36. package/src/types/controls.d.ts +23 -6
  37. package/types/vue-shims.d.ts +3 -2
@@ -7,231 +7,260 @@ import { DragAndDrop } from "./dragAndDrop";
7
7
  * @class
8
8
  */
9
9
  export class ListDragAndDrop extends DragAndDrop {
10
- listPosition = 0;
11
- cursorPosition = 0;
12
- initialPosition = 0;
13
- onPositionChangeCb = null;
14
- onDragPositionChangeCb = null;
15
- placeholder = null;
16
-
17
- constructor(options = {}) {
18
- super({
19
- showPlaceholder: true,
20
- ...options
21
- });
22
- }
23
-
24
- /**
25
- * Callback that fires after dragging has ended and the list position has changed from the original
26
- * @param cb
27
- * @returns {ListDragAndDrop}
28
- */
29
- onPositionChange(cb) {
30
- this.onPositionChangeCb = cb;
31
- return this;
32
- }
33
-
34
- /**
35
- * Callback that fires while dragging the element when the cursor's position has changed in the list
36
- * @param cb
37
- * @returns {ListDragAndDrop}
38
- */
39
- onDragPositionChange(cb) {
40
- this.onDragPositionChangeCb = cb;
41
- return this;
42
- }
43
-
44
- /**
45
- * Start listening for drag events and prepare an element for drag/drop
46
- * @param e
47
- * @param data
48
- */
49
- dragStart(e, data) {
50
- super.dragStart(e, data);
51
-
52
- if (this.currentDropZone) {
53
- this.listPosition = this.getListPosition(e.target);
54
- this.initialPosition = this.listPosition;
55
- this.updateScrollPosition();
56
- }
57
- }
58
-
59
- /**
60
- * When dragging has ended, check for list position changes and fire the onPositionChange callback if it has
61
- */
62
- dragEnd(e) {
63
- const draggableData = this.draggableData;
64
- this.placeholder?.remove();
65
- super.dragEnd(e);
66
-
67
- // If our list position has changed, trigger the drop callback
68
- if (this.listPosition !== this.initialPosition) {
69
- this.onPositionChangeCb &&
70
- this.onPositionChangeCb(this.listPosition, this.initialPosition, draggableData);
71
- }
72
- }
73
-
74
- /**
75
- * The dragging element is moving
76
- * @param e
77
- */
78
- dragOver(e) {
79
- super.dragOver(e);
80
- this.updateListPosition(e);
81
- }
82
-
83
- /**
84
- * Notify if the targeted position of the cursor is different from the current position
85
- * @param e
86
- */
87
- updateListPosition(e) {
88
- const prevPosition = this.listPosition;
89
- const newPosition = this.getListPositionOfPoint({
90
- x: e.clientX,
91
- y: e.clientY
92
- });
93
-
94
- // If the cursor position has changed, we should update the rendering and see if our actual list position has
95
- // changed
96
- if (this.cursorPosition !== newPosition) {
97
- this.cursorPosition = newPosition;
98
- this.listPosition =
99
- this.initialPosition < this.cursorPosition
100
- ? this.cursorPosition - 1
101
- : this.cursorPosition;
102
- if (this.options.showPlaceholder) {
103
- this.renderPlaceholder();
104
- }
105
-
106
- // The position has changed, trigger the callback
107
- if (this.listPosition !== prevPosition) {
108
- this.onDragPositionChangeCb &&
109
- this.onDragPositionChangeCb(this.listPosition, this.draggableData);
110
- }
111
- }
112
- }
113
-
114
- /**
115
- * Find the numeric position of the element in the children of the list
116
- * @returns {Number|null}
117
- * @param item
118
- */
119
- getListPosition(item) {
120
- let index = 0;
121
- for (const child of this.getChildren()) {
122
- if (child === item) {
123
- return index;
124
- }
125
- index++;
126
- }
127
-
128
- return null;
129
- }
130
-
131
- /**
132
- * Get all the children of the current drop zone, excluding the placeholder
133
- * @returns {*}
134
- */
135
- getChildren() {
136
- return [...this.currentDropZone.children].filter(
137
- (c) => c.className.match(/drag-placeholder/) === null
138
- );
139
- }
140
-
141
- /**
142
- * Find the element at the current cursor position in the given drop zone
143
- * @param point
144
- * @returns {null}
145
- */
146
- getListPositionOfPoint(point) {
147
- let index = 0;
148
- const children = this.getChildren();
149
-
150
- while (index < children.length) {
151
- const rect = children[index].getBoundingClientRect();
152
- if (this.isVertical()) {
153
- if (point.y < rect.top + rect.height / 2) {
154
- break;
155
- }
156
- } else {
157
- if (point.x < rect.left + rect.width / 2) {
158
- break;
159
- }
160
- }
161
- index++;
162
- }
163
-
164
- return index;
165
- }
166
-
167
- /**
168
- * Updates the scroll position while dragging an element so a user can navigate a longer list while dragging
169
- */
170
- updateScrollPosition() {
171
- if (this.currentDropZone) {
172
- const rect = this.currentDropZone.getBoundingClientRect();
173
- const threshold = 100;
174
- let velocity = 0;
175
- const velocityFn = (x) => x * 5;
176
- const cursorPos = this.isVertical() ? this.cursorY : this.cursorX;
177
- const rectStart = this.isVertical() ? rect.top : rect.left;
178
- const rectEnd = this.isVertical() ? rect.bottom : rect.right;
179
- const beforeDiff = rectStart + threshold - cursorPos;
180
- const afterDiff = cursorPos - (rectEnd - threshold);
181
-
182
- if (beforeDiff > 0) {
183
- velocity = -velocityFn(beforeDiff);
184
- } else if (afterDiff > 0) {
185
- velocity = velocityFn(afterDiff);
186
- }
187
-
188
- if (velocity) {
189
- if (this.isVertical()) {
190
- this.currentDropZone.scrollTo({
191
- top: this.currentDropZone.scrollTop + velocity,
192
- behavior: "smooth"
193
- });
194
- } else {
195
- this.currentDropZone.scrollTo({
196
- left: this.currentDropZone.scrollLeft + velocity,
197
- behavior: "smooth"
198
- });
199
- }
200
- }
201
-
202
- setTimeout(() => this.updateScrollPosition(), 500);
203
- }
204
- }
205
-
206
- /**
207
- * Render a placeholder element at the given position (in between the elements)
208
- */
209
- renderPlaceholder() {
210
- if (!this.placeholder) {
211
- this.placeholder = document.createElement("div");
212
- this.placeholder.classList.add("drag-placeholder");
213
- }
214
-
215
- // Make sure the placeholder is oriented correctly
216
- if (this.isVertical()) {
217
- this.placeholder.classList.add("direction-vertical");
218
- this.placeholder.classList.remove("direction-horizontal");
219
- this.placeholder.style.height = undefined;
220
- } else {
221
- this.placeholder.classList.add("direction-horizontal");
222
- this.placeholder.classList.remove("direction-vertical");
223
- this.placeholder.style.height =
224
- this.currentDropZone.getBoundingClientRect().height + "px";
225
- }
226
-
227
- const children = this.getChildren();
228
- if (this.cursorPosition < children.length) {
229
- this.currentDropZone.insertBefore(
230
- this.placeholder,
231
- children[this.cursorPosition]
232
- );
233
- } else {
234
- this.currentDropZone.appendChild(this.placeholder);
235
- }
236
- }
10
+ listPosition = 0;
11
+ cursorPosition = 0;
12
+ initialPosition = 0;
13
+ initialDropZone: HTMLElement | null = null;
14
+ onPositionChangeCb = null;
15
+ onDragPositionChangeCb = null;
16
+ onDropZoneChangeCb = null;
17
+ placeholder = null;
18
+
19
+ constructor(options = {}) {
20
+ super({
21
+ showPlaceholder: true,
22
+ ...options
23
+ });
24
+ }
25
+
26
+ /**
27
+ * Callback that fires after dragging has ended and the list position has changed from the original
28
+ */
29
+ onPositionChange(cb): ListDragAndDrop {
30
+ this.onPositionChangeCb = cb;
31
+ return this;
32
+ }
33
+
34
+ /**
35
+ * Callback that fires when the drop zone has changed
36
+ */
37
+ onDropZoneChange(cb): ListDragAndDrop {
38
+ this.onDropZoneChangeCb = cb;
39
+ return this;
40
+ }
41
+
42
+ /**
43
+ * Callback that fires while dragging the element when the cursor's position has changed in the list
44
+ * @param cb
45
+ * @returns {ListDragAndDrop}
46
+ */
47
+ onDragPositionChange(cb) {
48
+ this.onDragPositionChangeCb = cb;
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * Start listening for drag events and prepare an element for drag/drop
54
+ * @param e
55
+ * @param data
56
+ */
57
+ dragStart(e, data) {
58
+ super.dragStart(e, data);
59
+
60
+ if (this.currentDropZone) {
61
+ this.listPosition = this.getListPosition(e.target);
62
+ this.initialPosition = this.listPosition;
63
+ this.initialDropZone = this.currentDropZone;
64
+ this.updateScrollPosition();
65
+ }
66
+ }
67
+
68
+ /**
69
+ * When dragging has ended, check for list position changes and fire the onPositionChange callback if it has
70
+ */
71
+ dragEnd(e) {
72
+ const draggableData = this.draggableData;
73
+ this.placeholder?.remove();
74
+ const newDropZone = this.currentDropZone;
75
+ super.dragEnd(e);
76
+
77
+ // If the list drop zone has changed, trigger the callback for drop zone change
78
+ if (newDropZone && newDropZone !== this.initialDropZone) {
79
+ this.onDropZoneChangeCb && this.onDropZoneChangeCb(e, newDropZone, this.listPosition, this.initialPosition, draggableData);
80
+ } else if (this.listPosition !== this.initialPosition) {
81
+ // If our list position has changed, trigger the position change callback
82
+ this.onPositionChangeCb &&
83
+ this.onPositionChangeCb(this.listPosition, this.initialPosition, draggableData);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * The dragging element is moving
89
+ * @param e
90
+ */
91
+ dragOver(e) {
92
+ super.dragOver(e);
93
+ this.updateListPosition(e);
94
+ }
95
+
96
+ /**
97
+ * Notify if the targeted position of the cursor is different from the current position
98
+ * @param e
99
+ */
100
+ updateListPosition(e: MouseEvent) {
101
+ const point = {
102
+ x: e.clientX,
103
+ y: e.clientY
104
+ };
105
+ const newDropZone = this.getDropZoneForTarget(e.target as HTMLElement);
106
+ if (newDropZone !== this.currentDropZone) {
107
+ this.currentDropZone = newDropZone;
108
+ this.cursorPosition = 0;
109
+ this.listPosition = 0;
110
+ this.placeholder?.remove();
111
+ }
112
+
113
+ const prevPosition = this.listPosition;
114
+ const newPosition = this.getListPositionOfPoint(point);
115
+
116
+ // If the cursor position has changed, we should update the rendering and see if our actual list position has
117
+ // changed
118
+ if (this.cursorPosition !== newPosition) {
119
+ this.cursorPosition = newPosition;
120
+ this.listPosition =
121
+ this.initialPosition < this.cursorPosition
122
+ ? this.cursorPosition - 1
123
+ : this.cursorPosition;
124
+ if (this.options.showPlaceholder) {
125
+ this.renderPlaceholder();
126
+ }
127
+
128
+ // The position has changed, trigger the callback
129
+ if (this.listPosition !== prevPosition) {
130
+ this.onDragPositionChangeCb &&
131
+ this.onDragPositionChangeCb(this.listPosition, this.draggableData);
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Find the numeric position of the element in the children of the list
138
+ * @returns {Number|null}
139
+ * @param item
140
+ */
141
+ getListPosition(item) {
142
+ let index = 0;
143
+ for (const child of this.getChildren()) {
144
+ if (child === item) {
145
+ return index;
146
+ }
147
+ index++;
148
+ }
149
+
150
+ return null;
151
+ }
152
+
153
+ /**
154
+ * Get all the children of the current drop zone, excluding the placeholder
155
+ * @returns {*}
156
+ */
157
+ getChildren() {
158
+ return [...(this.currentDropZone?.children || [])].filter(
159
+ (c) => c.className.match(/drag-placeholder/) === null
160
+ );
161
+ }
162
+
163
+ /**
164
+ * Get the list element that is the parent of the target element
165
+ */
166
+ getDropZoneForTarget(target: HTMLElement): HTMLElement | null {
167
+ return target.closest(`[data-drop-zone]`);
168
+ }
169
+
170
+ /**
171
+ * Find the element at the current cursor position in the given drop zone
172
+ * @param point
173
+ * @returns {null}
174
+ */
175
+ getListPositionOfPoint(point) {
176
+ let index = 0;
177
+ const children = this.getChildren();
178
+
179
+ while (index < children.length) {
180
+ const rect = children[index].getBoundingClientRect();
181
+ if (this.isVertical()) {
182
+ if (point.y < rect.top + rect.height / 2) {
183
+ break;
184
+ }
185
+ } else {
186
+ if (point.x < rect.left + rect.width / 2) {
187
+ break;
188
+ }
189
+ }
190
+ index++;
191
+ }
192
+
193
+ return index;
194
+ }
195
+
196
+ /**
197
+ * Updates the scroll position while dragging an element so a user can navigate a longer list while dragging
198
+ */
199
+ updateScrollPosition() {
200
+ if (this.currentDropZone) {
201
+ const rect = this.currentDropZone.getBoundingClientRect();
202
+ const threshold = 100;
203
+ let velocity = 0;
204
+ const velocityFn = (x) => x * 5;
205
+ const cursorPos = this.isVertical() ? this.cursorY : this.cursorX;
206
+ const rectStart = this.isVertical() ? rect.top : rect.left;
207
+ const rectEnd = this.isVertical() ? rect.bottom : rect.right;
208
+ const beforeDiff = rectStart + threshold - cursorPos;
209
+ const afterDiff = cursorPos - (rectEnd - threshold);
210
+
211
+ if (beforeDiff > 0) {
212
+ velocity = -velocityFn(beforeDiff);
213
+ } else if (afterDiff > 0) {
214
+ velocity = velocityFn(afterDiff);
215
+ }
216
+
217
+ if (velocity) {
218
+ if (this.isVertical()) {
219
+ this.currentDropZone.scrollTo({
220
+ top: this.currentDropZone.scrollTop + velocity,
221
+ behavior: "smooth"
222
+ });
223
+ } else {
224
+ this.currentDropZone.scrollTo({
225
+ left: this.currentDropZone.scrollLeft + velocity,
226
+ behavior: "smooth"
227
+ });
228
+ }
229
+ }
230
+
231
+ setTimeout(() => this.updateScrollPosition(), 500);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Render a placeholder element at the given position (in between the elements)
237
+ */
238
+ renderPlaceholder() {
239
+ if (!this.placeholder) {
240
+ this.placeholder = document.createElement("div");
241
+ this.placeholder.classList.add("drag-placeholder");
242
+ }
243
+
244
+ // Make sure the placeholder is oriented correctly
245
+ if (this.isVertical()) {
246
+ this.placeholder.classList.add("direction-vertical");
247
+ this.placeholder.classList.remove("direction-horizontal");
248
+ this.placeholder.style.height = undefined;
249
+ } else {
250
+ this.placeholder.classList.add("direction-horizontal");
251
+ this.placeholder.classList.remove("direction-vertical");
252
+ this.placeholder.style.height =
253
+ this.currentDropZone.getBoundingClientRect().height + "px";
254
+ }
255
+
256
+ const children = this.getChildren();
257
+ if (this.cursorPosition < children.length) {
258
+ this.currentDropZone.insertBefore(
259
+ this.placeholder,
260
+ children[this.cursorPosition]
261
+ );
262
+ } else {
263
+ this.currentDropZone.appendChild(this.placeholder);
264
+ }
265
+ }
237
266
  }
@@ -16,7 +16,7 @@
16
16
  <h2 v-if="title">
17
17
  {{ title }}
18
18
  </h2>
19
- <div v-if="!activeItem">
19
+ <div v-if="!target">
20
20
  Loading
21
21
  <QSpinnerHourglass />
22
22
  </div>
@@ -39,22 +39,22 @@
39
39
  </div>
40
40
  <div class="dx-panels-drawer-body flex-grow overflow-hidden h-full">
41
41
  <div
42
- v-if="activeItem.__timestamp > 0"
42
+ v-if="target.__timestamp > 0"
43
43
  class="flex items-stretch flex-nowrap h-full"
44
44
  >
45
45
  <PanelsDrawerTabs
46
- :key="'pd-tabs:' + activeItem.id"
46
+ :key="'pd-tabs:' + target.id"
47
47
  v-model="activePanel"
48
- :active-item="activeItem"
48
+ :target="target"
49
49
  :class="tabsClass"
50
50
  :panels="panels"
51
51
  @update:model-value="$emit('update:model-value', $event)"
52
52
  />
53
53
  <PanelsDrawerPanels
54
- :key="'pd-panels:' + activeItem.id"
54
+ :key="'pd-panels:' + target.id"
55
55
  :panels="panels"
56
56
  :active-panel="activePanel"
57
- :active-item="activeItem"
57
+ :active-item="target"
58
58
  :class="activePanelOptions?.class || panelsClass"
59
59
  />
60
60
  <div
@@ -79,7 +79,7 @@ import PanelsDrawerTabs from "./PanelsDrawerTabs";
79
79
  export interface Props {
80
80
  title?: string,
81
81
  modelValue?: string | number,
82
- activeItem: ActionTargetItem;
82
+ target: ActionTargetItem;
83
83
  tabsClass?: string | object,
84
84
  panelsClass?: string | object,
85
85
  position?: "standard" | "right" | "left";
@@ -13,7 +13,7 @@
13
13
  <RenderVnode
14
14
  v-if="panel.tabVnode"
15
15
  :key="panel.name"
16
- :vnode="panel.tabVnode(activeItem, modelValue)"
16
+ :vnode="panel.tabVnode(target, modelValue)"
17
17
  :is-active="modelValue === panel.name"
18
18
  :name="panel.name"
19
19
  :label="panel.label"
@@ -37,7 +37,7 @@ defineEmits(["update:model-value"]);
37
37
 
38
38
  interface Props {
39
39
  modelValue?: string | number;
40
- activeItem: ActionTargetItem;
40
+ target: ActionTargetItem;
41
41
  panels: ActionPanel[];
42
42
  }
43
43
 
@@ -51,7 +51,7 @@ function isEnabled(panel) {
51
51
  if (!panel.enabled) return false;
52
52
 
53
53
  if (typeof panel.enabled === "function") {
54
- return panel.enabled(props.activeItem);
54
+ return panel.enabled(props.target);
55
55
  }
56
56
 
57
57
  return true;
@@ -0,0 +1,86 @@
1
+ <template>
2
+ <QBtn
3
+ class="py-1 px-2"
4
+ :disable="disable"
5
+ @click="onToggle"
6
+ >
7
+ <div class="flex items-center flex-nowrap whitespace-nowrap">
8
+ <slot :is-showing="isShowing">
9
+ <component
10
+ :is="isShowing ? (hideIcon || DefaultHideIcon) : (showIcon || DefaultShowIcon)"
11
+ :class="iconClass"
12
+ />
13
+ <div
14
+ v-if="label"
15
+ :class="labelClass"
16
+ >
17
+ {{ (isShowing ? hideLabel : showLabel) || label }}
18
+ </div>
19
+ </slot>
20
+ </div>
21
+ <QTooltip v-if="tooltip">
22
+ {{ tooltip }}
23
+ </QTooltip>
24
+ </QBtn>
25
+ </template>
26
+ <script lang="ts" setup>
27
+ import { FaSolidEye as DefaultShowIcon, FaSolidEyeSlash as DefaultHideIcon } from "danx-icon";
28
+ import { nextTick } from "vue";
29
+ import { getItem, setItem } from "../../../helpers";
30
+
31
+ export interface Props {
32
+ name?: string;
33
+ showLabel?: string;
34
+ hideLabel?: string;
35
+ showIcon?: object | string;
36
+ hideIcon?: object | string;
37
+ iconClass?: string;
38
+ labelClass?: string;
39
+ label?: string;
40
+ tooltip?: string;
41
+ disable?: boolean;
42
+ }
43
+
44
+ const emit = defineEmits(["show", "hide"]);
45
+ const isShowing = defineModel<boolean>();
46
+ const props = withDefaults(defineProps<Props>(), {
47
+ name: "",
48
+ showLabel: "",
49
+ hideLabel: "",
50
+ showIcon: null,
51
+ hideIcon: null,
52
+ iconClass: "w-4 h-6",
53
+ labelClass: "ml-2",
54
+ label: "",
55
+ tooltip: ""
56
+ });
57
+
58
+ const SETTINGS_KEY = "show-hide-button";
59
+ const settings = getItem(SETTINGS_KEY, {});
60
+
61
+ if (props.name) {
62
+ if (settings[props.name] !== undefined) {
63
+ isShowing.value = settings[props.name];
64
+ }
65
+ }
66
+
67
+ function onToggle() {
68
+ isShowing.value = !isShowing.value;
69
+
70
+
71
+ // NOTE: use nextTick to ensure the value is updated before saving (if the parent does not pass a value for modelValue, this can cause a desync)
72
+ nextTick(() => {
73
+ if (isShowing.value) {
74
+ emit("show");
75
+ } else {
76
+ emit("hide");
77
+ }
78
+
79
+ if (props.name) {
80
+ settings[props.name] = isShowing.value;
81
+ setItem(SETTINGS_KEY, { ...getItem(SETTINGS_KEY, {}), [props.name]: isShowing.value });
82
+ }
83
+ });
84
+ }
85
+
86
+ </script>
@@ -1,2 +1,3 @@
1
1
  export { default as ExportButton } from "./ExportButton.vue";
2
2
  export { default as RefreshButton } from "./RefreshButton.vue";
3
+ export { default as ShowHideButton } from "./ShowHideButton.vue";