design-system-next 2.19.0 → 2.19.4

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.
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div
3
- ref="reusableCalendarRef"
4
- :class="reusableCalendarClasses"
3
+ ref="dateCalendarPickerRef"
4
+ :class="dateCalendarPickerClasses"
5
5
  >
6
6
  <div
7
7
  :class="[
@@ -132,13 +132,13 @@ import DatePickerCalendarTab from '../tabs/DatePickerCalendarTab.vue';
132
132
  import DatePickerMonthTab from '../tabs/DatePickerMonthTab.vue';
133
133
  import DatePickerYearTab from '../tabs/DatePickerYearTab.vue';
134
134
 
135
- import { useReusableCalendar } from './use-reusable-calendar';
136
- import { reusableCalendarEmitTypes, reusableCalendarPropTypes } from './reusable-calendar';
135
+ import { useDateCalendarPicker } from './use-date-calendar-picker';
136
+ import { dateCalendarPickerEmitTypes, dateCalendarPickerPropTypes } from './date-calendar-picker';
137
137
 
138
- const props = defineProps(reusableCalendarPropTypes);
139
- const emit = defineEmits(reusableCalendarEmitTypes);
138
+ const props = defineProps(dateCalendarPickerPropTypes);
139
+ const emit = defineEmits(dateCalendarPickerEmitTypes);
140
140
 
141
- const reusableCalendarRef = ref<HTMLElement | null>(null);
141
+ const dateCalendarPickerRef = ref<HTMLElement | null>(null);
142
142
 
143
143
  // Use the composable for all logic
144
144
  const {
@@ -176,12 +176,12 @@ const {
176
176
  handleMonthTabMonthUpdateWrapper,
177
177
  handleYearTabYearUpdateWrapper,
178
178
  handleYearTabCurrentPageUpdateWrapper,
179
- } = useReusableCalendar(props, emit);
179
+ } = useDateCalendarPicker(props, emit);
180
180
 
181
181
  // Compute CSS classes using classNames utility
182
- const reusableCalendarClasses = computed(() => {
182
+ const dateCalendarPickerClasses = computed(() => {
183
183
  return classNames(
184
- 'reusable-calendar-container spr-bg-white spr-rounded-lg spr-shadow-lg spr-border spr-border-solid spr-border-mushroom-200 min-w-[320px]',
184
+ 'date-calendar-picker-container spr-bg-white spr-rounded-lg spr-shadow-lg spr-border spr-border-solid spr-border-mushroom-200 min-w-[320px]',
185
185
  {
186
186
  'spr-disabled': props.disabled,
187
187
  'spr-readonly': props.readonly,
@@ -3,11 +3,11 @@ import { toRefs } from 'vue';
3
3
  import dayjs from 'dayjs';
4
4
 
5
5
  import type { SetupContext } from 'vue';
6
- import type { ReusableCalendarEmitTypes, ReusableCalendarPropTypes } from './reusable-calendar';
6
+ import type { DateCalendarPickerEmitTypes, DateCalendarPickerPropTypes } from './date-calendar-picker';
7
7
 
8
- export const useReusableCalendar = (
9
- props: ReusableCalendarPropTypes,
10
- emit: SetupContext<ReusableCalendarEmitTypes>['emit']
8
+ export const useDateCalendarPicker = (
9
+ props: DateCalendarPickerPropTypes,
10
+ emit: SetupContext<DateCalendarPickerEmitTypes>['emit']
11
11
  ) => {
12
12
  // Extract reactive props
13
13
  const {
@@ -1,8 +1,6 @@
1
1
  import { onBeforeMount, ref, toRefs, watch } from 'vue';
2
- import { useVModel } from '@vueuse/core';
3
-
2
+ import { useVModel, watchDeep } from '@vueuse/core';
4
3
  import { LadderizedListPropTypes, LadderizedListEmitTypes } from './ladderized-list';
5
-
6
4
  import type { SetupContext } from 'vue';
7
5
  import type { MenuListType } from '../list';
8
6
 
@@ -21,6 +19,8 @@ export const useLadderizedList = (
21
19
  const activeList = ref<MenuListType[]>(menuList.value); // List of items to display in the active level
22
20
  const searchText = ref('');
23
21
 
22
+ const modelValueIsCustom = ref(false);
23
+
24
24
  // Recursive filter function for ladderized options
25
25
  const filterOptionsRecursive = (items: MenuListType[], search: string): MenuListType[] => {
26
26
  if (!search) return items;
@@ -86,6 +86,12 @@ export const useLadderizedList = (
86
86
  const handleSelectedListItem = (item: MenuListType) => {
87
87
  transitionName.value = 'slide-left';
88
88
 
89
+ if (modelValueIsCustom.value) {
90
+ console.log("Custom");
91
+ ladderizedListOutput.value.shift();
92
+ modelValueIsCustom.value = false;
93
+ };
94
+
89
95
  // If searching, reconstruct full path as array of option objects
90
96
  if (searchText.value) {
91
97
  const path = findOptionPath(menuList.value, String(item.value));
@@ -111,7 +117,7 @@ export const useLadderizedList = (
111
117
  replaceItemInOutput(item);
112
118
  }
113
119
 
114
- if (item.sublevel && item.sublevel.length > 0) updateLevel(item);
120
+ if (item.sublevel && item.sublevel.length > 0) updateLevel(item); // FIXME: This causes activeLevel one less than expected. Currently not critical since most forms are 2 levels deep.
115
121
  emit('update:modelValue', ladderizedListOutput.value);
116
122
  };
117
123
 
@@ -224,9 +230,14 @@ export const useLadderizedList = (
224
230
 
225
231
  prevList.value = activeList.value;
226
232
  activeList.value = item.sublevel ?? prevList.value;
227
- activeLevel.value += item.sublevel ? 1 : 0;
233
+ activeLevel.value += item.sublevel ? 1 : 0; // FIXME: This causes activeLevel one less than expected. Currently not critical since most forms are 2 levels deep.
228
234
  } else {
229
- // If no item found, skip the for loop
235
+ // If no item found, rest the values to initial state
236
+ selectedListItem.value = [];
237
+ prevList.value = [];
238
+ activeList.value = menuList.value;
239
+ activeLevel.value = 0;
240
+ modelValueIsCustom.value = true;
230
241
  return;
231
242
  }
232
243
  });
@@ -241,8 +252,8 @@ export const useLadderizedList = (
241
252
  };
242
253
 
243
254
  // Watch for modelValue changes and reset selectedListItem if cleared
244
- watch(
245
- () => props.modelValue,
255
+ watchDeep(
256
+ ladderizedListOutput,
246
257
  (newVal) => {
247
258
  if (!newVal || (Array.isArray(newVal) && newVal.length === 0)) {
248
259
  selectedListItem.value = [];
@@ -36,6 +36,10 @@ export const listPropTypes = {
36
36
  type: String,
37
37
  default: '',
38
38
  },
39
+ supportingDisplayText: {
40
+ type: String,
41
+ default: '',
42
+ },
39
43
  menuList: {
40
44
  type: Array as PropType<MenuListType[]>,
41
45
  required: true,
@@ -99,11 +103,16 @@ export const listPropTypes = {
99
103
  type: String,
100
104
  default: '',
101
105
  },
106
+ disabledUnselectedItems: {
107
+ type: Boolean,
108
+ default: false,
109
+ },
102
110
  };
103
111
 
104
112
  export const listEmitTypes = {
105
113
  'update:modelValue': (value: MenuListType[]) => value,
106
114
  'update:searchValue': (value: string) => typeof value === 'string',
115
+ 'get-single-selected-item': (item: MenuListType) => item,
107
116
  };
108
117
 
109
118
  export type ListPropTypes = ExtractPropTypes<typeof listPropTypes>;
@@ -20,8 +20,14 @@
20
20
  :placeholder="props.searchableMenuPlaceholder"
21
21
  autocomplete="off"
22
22
  />
23
- <span v-if="props.displayListItemSelected" class="spr-label-sm-medium spr-text-color-base spr-block">
24
- {{ selectedItems.length }} Selected
23
+ <span
24
+ v-if="props.supportingDisplayText || props.displayListItemSelected"
25
+ class="spr-label-sm-medium spr-text-color-base spr-block"
26
+ >
27
+ <template v-if="props.supportingDisplayText">
28
+ {{ props.supportingDisplayText }}
29
+ </template>
30
+ <template v-else> {{ selectedItems.length }} Selected</template>
25
31
  </span>
26
32
  </div>
27
33
  </template>
@@ -47,7 +53,11 @@
47
53
  >
48
54
  <template v-if="props.lozenge">
49
55
  <div class="spr-flex spr-items-center spr-gap-1">
50
- <spr-checkbox v-if="props.multiSelect" :disabled="item.disabled" :checked="isItemSelected(item)" />
56
+ <spr-checkbox
57
+ v-if="props.multiSelect"
58
+ :disabled="item.disabled || (props.disabledUnselectedItems && !isItemSelected(item))"
59
+ :checked="isItemSelected(item)"
60
+ />
51
61
  <spr-lozenge
52
62
  v-if="props.lozenge"
53
63
  :label="item.text || (item.lozengeProps?.label as string)"
@@ -61,27 +71,46 @@
61
71
  </template>
62
72
  <template v-else>
63
73
  <div class="spr-flex spr-items-center spr-gap-1">
64
- <spr-checkbox v-if="props.multiSelect" :disabled="item.disabled" :checked="isItemSelected(item)" />
74
+ <spr-checkbox
75
+ v-if="props.multiSelect"
76
+ :disabled="item.disabled || (props.disabledUnselectedItems && !isItemSelected(item))"
77
+ :checked="isItemSelected(item)"
78
+ />
65
79
  <div :class="[item.textColor, 'spr-flex spr-flex-row spr-items-center spr-gap-size-spacing-3xs']">
66
- <span v-if="props.itemIcon || item.icon" :class="[item.iconColor, 'spr-mt-[2px]']">
80
+ <span
81
+ v-if="props.itemIcon || item.icon"
82
+ :class="[
83
+ item.iconColor,
84
+ 'spr-mt-[2px]',
85
+ {
86
+ 'spr-text-color-disabled':
87
+ item.disabled || (props.disabledUnselectedItems && !isItemSelected(item)),
88
+ },
89
+ ]"
90
+ >
67
91
  <icon :icon="(props.itemIcon || item.icon) as string" width="20px" height="20px" />
68
92
  </span>
69
93
  <div
70
94
  :class="[
71
95
  'spr-flex spr-flex-auto spr-flex-col spr-justify-start',
72
- { 'spr-text-color-disabled': item.disabled },
96
+ {
97
+ 'spr-text-color-disabled':
98
+ item.disabled || (props.disabledUnselectedItems && !isItemSelected(item)),
99
+ },
73
100
  ]"
74
101
  >
75
- <span class="spr-text-left spr-text-xs" style="word-break: break-word">
102
+ <span class="spr-break-words spr-text-left spr-text-xs">
76
103
  {{ item.text }}
77
104
  </span>
78
105
  <span
79
106
  v-if="item.subtext"
80
107
  :class="[
81
- 'spr-body-xs-regular spr-text-color-base spr-text-left',
82
- { 'spr-text-color-disabled': item.disabled },
108
+ 'spr-body-xs-regular spr-text-color-base spr-break-words spr-text-left',
109
+ {
110
+ 'spr-text-color-disabled':
111
+ item.disabled || (props.disabledUnselectedItems && !isItemSelected(item)),
112
+ },
83
113
  ]"
84
- style="word-break: break-word"
85
114
  >
86
115
  {{ item.subtext }}
87
116
  </span>
@@ -140,7 +169,11 @@
140
169
  >
141
170
  <template v-if="props.lozenge">
142
171
  <div class="spr-flex spr-items-center spr-gap-1">
143
- <spr-checkbox v-if="props.multiSelect" :disabled="item.disabled" :checked="isItemSelected(item)" />
172
+ <spr-checkbox
173
+ v-if="props.multiSelect"
174
+ :disabled="item.disabled || (props.disabledUnselectedItems && !isItemSelected(item))"
175
+ :checked="isItemSelected(item)"
176
+ />
144
177
  <spr-lozenge
145
178
  v-if="props.lozenge"
146
179
  :label="item.text || (item.lozengeProps?.label as string)"
@@ -154,27 +187,46 @@
154
187
  </template>
155
188
  <template v-else>
156
189
  <div class="spr-flex spr-items-center spr-gap-1">
157
- <spr-checkbox v-if="props.multiSelect" :disabled="item.disabled" :checked="isItemSelected(item)" />
190
+ <spr-checkbox
191
+ v-if="props.multiSelect"
192
+ :disabled="item.disabled || (props.disabledUnselectedItems && !isItemSelected(item))"
193
+ :checked="isItemSelected(item)"
194
+ />
158
195
  <div :class="[item.textColor, 'spr-flex spr-flex-row spr-items-center spr-gap-size-spacing-3xs']">
159
- <span v-if="props.itemIcon || item.icon" :class="[item.iconColor, 'spr-mt-[2px]']">
196
+ <span
197
+ v-if="props.itemIcon || item.icon"
198
+ :class="[
199
+ item.iconColor,
200
+ 'spr-mt-[2px]',
201
+ {
202
+ 'spr-text-color-disabled':
203
+ item.disabled || (props.disabledUnselectedItems && !isItemSelected(item)),
204
+ },
205
+ ]"
206
+ >
160
207
  <icon :icon="(props.itemIcon || item.icon) as string" width="20px" height="20px" />
161
208
  </span>
162
209
  <div
163
210
  :class="[
164
211
  'spr-flex spr-flex-auto spr-flex-col spr-justify-start',
165
- { 'spr-text-color-disabled': item.disabled },
212
+ {
213
+ 'spr-text-color-disabled':
214
+ item.disabled || (props.disabledUnselectedItems && !isItemSelected(item)),
215
+ },
166
216
  ]"
167
217
  >
168
- <span class="spr-text-left spr-text-xs" style="word-break: break-word">
218
+ <span class="spr-break-words spr-text-left spr-text-xs">
169
219
  {{ item.text }}
170
220
  </span>
171
221
  <span
172
222
  v-if="item.subtext"
173
223
  :class="[
174
- 'spr-body-xs-regular spr-text-color-base spr-text-left',
175
- { 'spr-text-color-disabled': item.disabled },
224
+ 'spr-body-xs-regular spr-text-color-base spr-break-words spr-text-left',
225
+ {
226
+ 'spr-text-color-disabled':
227
+ item.disabled || (props.disabledUnselectedItems && !isItemSelected(item)),
228
+ },
176
229
  ]"
177
- style="word-break: break-word"
178
230
  >
179
231
  {{ item.subtext }}
180
232
  </span>
@@ -14,8 +14,16 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
14
14
  const selectedItems = useVModel(props, 'modelValue', emit);
15
15
  const searchString = useVModel(props, 'searchValue', emit);
16
16
 
17
- const { menuList, menuLevel, groupItemsBy, multiSelect, preSelectedItems, disabledLocalSearch, noCheck } =
18
- toRefs(props);
17
+ const {
18
+ menuList,
19
+ menuLevel,
20
+ groupItemsBy,
21
+ multiSelect,
22
+ preSelectedItems,
23
+ disabledLocalSearch,
24
+ noCheck,
25
+ disabledUnselectedItems,
26
+ } = toRefs(props);
19
27
 
20
28
  const listClasses: ComputedRef<ListClasses> = computed(() => {
21
29
  const listItemClasses = classNames(
@@ -161,6 +169,7 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
161
169
 
162
170
  if (previousSelected) {
163
171
  handleSelectedItem(item);
172
+
164
173
  return true;
165
174
  }
166
175
 
@@ -341,10 +350,10 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
341
350
  };
342
351
 
343
352
  const getListItemClasses = (item: MenuListType) => ({
344
- [listClasses.value.listItemClasses]: !item.disabled,
353
+ [listClasses.value.listItemClasses]: !item.disabled && !(disabledUnselectedItems.value && !isItemSelected(item)),
345
354
  'spr-background-color-single-active': isItemSelected(item) && !item.disabled && !noCheck.value,
346
- 'hover:spr-cursor-not-allowed spr-flex spr-cursor-pointer spr-items-center spr-gap-1.5 spr-rounded-lg':
347
- item.disabled,
355
+ 'spr-cursor-not-allowed spr-flex spr-items-center spr-gap-1.5 spr-rounded-lg':
356
+ item.disabled || (disabledUnselectedItems.value && !isItemSelected(item)),
348
357
  'spr-p-size-spacing-3xs': !props.lozenge,
349
358
  'spr-py-size-spacing-3xs spr-px-size-spacing-4xs': props.lozenge,
350
359
  });
@@ -420,6 +429,8 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
420
429
  const handleSelectedItem = (item: MenuListType) => {
421
430
  if (item.disabled) return;
422
431
 
432
+ if (disabledUnselectedItems.value && !isItemSelected(item)) return;
433
+
423
434
  if (multiSelect.value) {
424
435
  // For multi-select, check if item is already selected
425
436
  const index = selectedItems.value.findIndex((selectedItem: MenuListType) => {
@@ -488,8 +499,11 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
488
499
  } else {
489
500
  // For single-select, simply replace the selection
490
501
  selectedItems.value = [item];
502
+
491
503
  if (item.onClickFn) item.onClickFn();
492
504
  }
505
+
506
+ emit('get-single-selected-item', item);
493
507
  };
494
508
  // #endregion - Helper Methods
495
509
 
@@ -567,6 +581,7 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
567
581
 
568
582
  onMounted(() => {
569
583
  searchString.value = searchText.value;
584
+
570
585
  setMenuList();
571
586
  setPreSelectedItems();
572
587
  });
@@ -144,12 +144,16 @@ export const selectLadderizedPropTypes = {
144
144
  type: Boolean,
145
145
  default: false,
146
146
  },
147
+ writableInputText: {
148
+ type: Boolean,
149
+ default: false,
150
+ }
147
151
  };
148
152
 
149
153
  export const selectLadderizedEmitTypes = {
150
154
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
151
155
  'update:modelValue': (_value: unknown) => true,
152
- 'popper-state': Boolean,
156
+ 'popper-state': () => true,
153
157
  };
154
158
 
155
159
  export type SelectLadderizedEmitFn = (event: string, ...args: unknown[]) => void;
@@ -37,10 +37,11 @@
37
37
  :helper-text="props.helperText"
38
38
  :helper-icon="props.helperIcon"
39
39
  :display-helper="props.displayHelper"
40
- readonly
40
+ :readonly="!props.writableInputText"
41
41
  :active="props.active"
42
42
  :disabled="props.disabled"
43
43
  :error="props.error"
44
+ @blur="handleInputChange"
44
45
  >
45
46
  <template #icon>
46
47
  <div
@@ -121,5 +122,6 @@ const {
121
122
  inputText,
122
123
  handleSelectedLadderizedItem,
123
124
  handleClear,
125
+ handleInputChange,
124
126
  } = useSelectLadderized(props, emit as SelectLadderizedEmitFn);
125
127
  </script>
@@ -1,5 +1,5 @@
1
1
  import { ref, toRefs, computed, watch } from 'vue';
2
- import { useVModel, onClickOutside } from '@vueuse/core';
2
+ import { useVModel, onClickOutside, watchDeep } from '@vueuse/core';
3
3
 
4
4
  import type { SelectLadderizedPropTypes } from './select-ladderized';
5
5
 
@@ -17,6 +17,7 @@ export const useSelectLadderized = (
17
17
  supportingLabelClasses: 'spr-body-sm-regular spr-text-color-supporting',
18
18
  }));
19
19
 
20
+ // Wrapper for input field
20
21
  const ladderizedSelectState = ref<HTMLDivElement | null>(null);
21
22
 
22
23
  // Popper Variables
@@ -31,6 +32,7 @@ export const useSelectLadderized = (
31
32
  // Input Variables
32
33
  const inputText = ref<string>('');
33
34
  const wasCleared = ref<boolean>(false);
35
+ const isCustomInput = ref<boolean>(false);
34
36
 
35
37
  const isLeafNode = (item: MenuListType): boolean => {
36
38
  return !item.sublevel || item.sublevel.length === 0;
@@ -57,6 +59,7 @@ export const useSelectLadderized = (
57
59
 
58
60
  const handleSelectedLadderizedItem = (selectedItems: string[], selectedItem?: MenuListType) => {
59
61
  wasCleared.value = false;
62
+ isCustomInput.value = false;
60
63
 
61
64
  // If the selectedItems is a single value (leaf from search), reconstruct the full path
62
65
  let fullPath: string[] | null = null;
@@ -157,15 +160,17 @@ export const useSelectLadderized = (
157
160
  };
158
161
 
159
162
  // Watch for changes in modelValue to update inputText
160
- watch(
161
- () => ladderizedSelectModel.value,
163
+ watchDeep(
164
+ ladderizedSelectModel,
162
165
  (newVal) => {
166
+ if (isCustomInput.value) return;
167
+
163
168
  if (wasCleared.value) {
164
169
  inputText.value = '';
165
170
  wasCleared.value = false;
166
171
 
167
172
  return;
168
- }
173
+ };
169
174
 
170
175
  if (Array.isArray(newVal) && newVal.length > 0) {
171
176
  // Treat the array as a single path for ladderized select
@@ -194,6 +199,13 @@ export const useSelectLadderized = (
194
199
  emit('popper-state', newState);
195
200
  });
196
201
 
202
+ const handleInputChange = () => {
203
+ if (!props.writableInputText) return;
204
+ wasCleared.value = false;
205
+ isCustomInput.value = true;
206
+ ladderizedSelectModel.value = [inputText.value];
207
+ };
208
+
197
209
  // Close only when clicking completely outside both the popper and the trigger wrapper.
198
210
  onClickOutside(ladderizedSelectPopperRef, (event) => {
199
211
  const triggerWrapper = ladderizedSelectState.value;
@@ -216,5 +228,6 @@ export const useSelectLadderized = (
216
228
  inputText,
217
229
  handleSelectedLadderizedItem,
218
230
  handleClear,
231
+ handleInputChange,
219
232
  };
220
233
  };
@@ -123,6 +123,14 @@ export const multiSelectPropTypes = {
123
123
  type: String,
124
124
  default: '',
125
125
  },
126
+ supportingDisplayText: {
127
+ type: String,
128
+ default: '',
129
+ },
130
+ persistentDisplayText: {
131
+ type: Boolean,
132
+ default: false,
133
+ },
126
134
  displaySelectedCountOnly: {
127
135
  type: Boolean,
128
136
  default: false,
@@ -183,14 +191,22 @@ export const multiSelectPropTypes = {
183
191
  type: String,
184
192
  default: '',
185
193
  },
194
+ disabledUnselectedItems: {
195
+ type: Boolean,
196
+ default: false,
197
+ },
186
198
  };
187
199
 
188
200
  export const multiSelectEmitTypes = {
189
201
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
190
202
  'update:modelValue': (_value: unknown) => true,
191
203
  'update:searchValue': (value: string) => typeof value === 'string',
204
+ 'search-string': (value: string) => typeof value === 'string',
192
205
  'infinite-scroll-trigger': Boolean,
193
206
  'popper-state': Boolean,
207
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
208
+ 'get-selected-options': (_value: unknown) => true,
209
+ 'get-single-selected-item': (item: MenuListType) => item,
194
210
  };
195
211
 
196
212
  export type MultiSelectPropTypes = ExtractPropTypes<typeof multiSelectPropTypes>;
@@ -162,10 +162,13 @@
162
162
  :loading="props.loading"
163
163
  :item-icon="props.itemIcon"
164
164
  :lozenge="props.lozenge"
165
+ :supporting-display-text="props.supportingDisplayText"
165
166
  :display-list-item-selected="props.displayListItemSelected"
166
167
  :disabled-local-search="props.disabledLocalSearch"
168
+ :disabled-unselected-items="props.disabledUnselectedItems"
167
169
  multi-select
168
170
  @update:model-value="handleMultiSelectedItem"
171
+ @get-single-selected-item="emit('get-single-selected-item', $event)"
169
172
  />
170
173
  </div>
171
174
  </template>