design-system-next 1.8.2 → 1.9.2

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.
@@ -66,7 +66,7 @@ export const useCalendarCell = (props: CalendarCellPropTypes) => {
66
66
 
67
67
  const getCalendarCellClassess = computed(() => {
68
68
  const calendarCellWrapper =
69
- 'spr-flex spr-items-center spr-gap-size-spacing-3xs spr-relative spr-w-[217px] spr-rounded-md spr-border-2 spr-p-3 spr-transition-all hover:spr-shadow-md';
69
+ 'spr-flex spr-items-center spr-gap-size-spacing-3xs spr-relative spr-max-w-[217px] spr-rounded-md spr-border-2 spr-p-3 spr-transition-all hover:spr-shadow-md';
70
70
 
71
71
  const statusCellClasses = classNames({
72
72
  'spr-border-dashed': props.status === 'pending',
@@ -5,7 +5,7 @@ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<
5
5
  export const checkboxPropTypes = {
6
6
  modelValue: {
7
7
  type: Boolean,
8
- required: true,
8
+ default: false,
9
9
  },
10
10
  label: {
11
11
  type: String,
@@ -19,6 +19,10 @@ export const checkboxPropTypes = {
19
19
  type: Boolean,
20
20
  default: false,
21
21
  },
22
+ checked: {
23
+ type: Boolean,
24
+ default: true,
25
+ },
22
26
  };
23
27
 
24
28
  export const checkboxEmitTypes = {};
@@ -3,9 +3,9 @@
3
3
  <div class="spr-relative spr-flex spr-items-center">
4
4
  <input
5
5
  type="checkbox"
6
- :checked="props.modelValue"
7
6
  :class="checkboxClasses.inputCheckboxClasses"
8
7
  :disabled="props.disabled"
8
+ :checked="props.modelValue || props.checked"
9
9
  @change="handleCheckbox"
10
10
  />
11
11
  <span :class="checkboxClasses.inputCheckboxCheckIconClasses">
@@ -13,12 +13,8 @@ interface CheckboxClasses {
13
13
  descriptionClasses: string;
14
14
  }
15
15
 
16
- interface CheckboxEvent extends Event {
17
- target: HTMLInputElement;
18
- }
19
-
20
16
  export const useCheckbox = (props: CheckboxPropTypes, emit: SetupContext<CheckboxEmitTypes>['emit']) => {
21
- const { modelValue, disabled } = toRefs(props);
17
+ const { modelValue, disabled, checked } = toRefs(props);
22
18
 
23
19
  const checkboxClasses: ComputedRef<CheckboxClasses> = computed(() => {
24
20
  const baseClasses = classNames(
@@ -33,8 +29,8 @@ export const useCheckbox = (props: CheckboxPropTypes, emit: SetupContext<Checkbo
33
29
  'spr-h-5 spr-w-5 spr-appearance-none spr-rounded-[2.5px] spr-border-color-supporting spr-border-[1.25px] spr-border-solid',
34
30
  'spr-transition spr-duration-150 spr-ease-in-out',
35
31
  {
36
- 'spr-background-color-brand-base spr-border-color-brand-base': modelValue.value,
37
- 'spr-border-color-disabled spr-background-color-base spr-cursor-not-allowed': disabled.value,
32
+ 'spr-background-color-brand-base spr-border-color-brand-base': modelValue.value || checked.value,
33
+ 'spr-border-color-disabled spr-background-color-base spr-cursor-not-allowed': disabled.value || checked.value,
38
34
  'spr-cursor-pointer': !disabled.value,
39
35
  },
40
36
  );
@@ -42,7 +38,7 @@ export const useCheckbox = (props: CheckboxPropTypes, emit: SetupContext<Checkbo
42
38
  const inputCheckboxCheckIconClasses = classNames(
43
39
  'spr-flex spr-items-center spr-justify-center spr-pointer-events-none spr-absolute spr-left-1/2 spr-top-1/2 -spr-translate-x-1/2 -spr-translate-y-1/2 spr-transform spr-font-bold spr-opacity-0',
44
40
  {
45
- 'spr-opacity-100': modelValue.value,
41
+ 'spr-opacity-100': modelValue.value || checked.value,
46
42
  'spr-text-color-inverted-strong': !disabled.value,
47
43
  'spr-text-color-on-fill-disabled': disabled.value,
48
44
  },
@@ -65,8 +61,10 @@ export const useCheckbox = (props: CheckboxPropTypes, emit: SetupContext<Checkbo
65
61
  };
66
62
  });
67
63
 
68
- const handleCheckbox = (e: CheckboxEvent): void => {
69
- emit('update:modelValue', e.target.checked);
64
+ const handleCheckbox = (event: Event): void => {
65
+ if (event.target instanceof HTMLInputElement) {
66
+ emit('update:modelValue', event.target.checked);
67
+ }
70
68
  };
71
69
 
72
70
  return {
@@ -4,10 +4,12 @@ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<
4
4
 
5
5
  export const REST_DAYS_TYPES = ['su', 'mo', 'tu', 'we', 'th', 'fr', 'sa'] as const;
6
6
 
7
+ const POPPER_STRATEGY_TYPES = ['fixed', 'absolute'] as const;
8
+
7
9
  export const datePickerPropTypes = {
8
10
  id: {
9
11
  type: String,
10
- default: '',
12
+ required: true,
11
13
  },
12
14
  modelValue: {
13
15
  type: String,
@@ -70,6 +72,11 @@ export const datePickerPropTypes = {
70
72
  type: String,
71
73
  default: '100%',
72
74
  },
75
+ popperStrategy: {
76
+ type: String,
77
+ validator: (value: 'fixed' | 'absolute') => POPPER_STRATEGY_TYPES.includes(value),
78
+ default: 'absolute',
79
+ },
73
80
  };
74
81
 
75
82
  export type RestDayType = (typeof REST_DAYS_TYPES)[number];
@@ -9,11 +9,16 @@
9
9
  :popper-hide-triggers="[]"
10
10
  :auto-hide="false"
11
11
  :disabled="isDatePickerPopperDisabled"
12
+ :container="`#${props.id}`"
13
+ :strategy="
14
+ props.popperStrategy === 'fixed' || props.popperStrategy === 'absolute' ? props.popperStrategy : 'absolute'
15
+ "
16
+ :delay="0"
12
17
  :style="{
13
18
  width: props.width,
14
19
  }"
15
20
  >
16
- <div class="spr-grid spr-gap-2">
21
+ <div :id="props.id" class="spr-grid spr-gap-2">
17
22
  <label v-if="props.label" :for="props.id" :class="datePickerClasses.labelClasses">
18
23
  {{ props.label }}
19
24
  </label>
@@ -2,8 +2,9 @@ import type { PropType, ExtractPropTypes } from 'vue';
2
2
 
3
3
  export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<T>;
4
4
 
5
- const DROPDOWN_TYPES = ['single-select', 'multi-select'] as const;
6
- const PLACEMENTS = [
5
+ const GROUPED_ITEMS_BY_TYPES = ['A-Z', 'Z-A'] as const;
6
+
7
+ const PLACEMENTS_TYPES = [
7
8
  'auto',
8
9
  'auto-start',
9
10
  'auto-end',
@@ -21,41 +22,68 @@ const PLACEMENTS = [
21
22
  'left-end',
22
23
  ] as const;
23
24
 
25
+ const POPPER_STRATEGY_TYPES = ['fixed', 'absolute'] as const;
26
+
24
27
  export type DropdownMenuType = {
25
28
  text: string;
26
29
  value: string;
27
30
  };
28
31
 
29
32
  export const dropdownPropTypes = {
30
- menu: {
31
- type: Array as PropType<DropdownMenuType[]>,
33
+ id: {
34
+ type: String,
32
35
  required: true,
33
- default: [],
34
36
  },
35
- preSelectedItems: {
36
- type: Array,
37
- default: [],
37
+ modelValue: {
38
+ type: Array as PropType<string[]>,
39
+ default: () => [],
38
40
  },
39
- dropdownType: {
40
- type: String,
41
- validator: (value: (typeof DROPDOWN_TYPES)[number]) => DROPDOWN_TYPES.includes(value),
41
+ menuList: {
42
+ type: Array as PropType<{ text: string; value: string }[]>,
42
43
  required: true,
43
- default: 'single-select',
44
+ default: [],
44
45
  },
45
- placement: {
46
+ searchString: {
46
47
  type: String,
47
- validator: (value: (typeof PLACEMENTS)[number]) => PLACEMENTS.includes(value),
48
- default: 'bottom',
48
+ default: '',
49
49
  },
50
- menuOpened: {
50
+ multiSelect: {
51
51
  type: Boolean,
52
52
  default: false,
53
53
  },
54
+ placement: {
55
+ type: String as PropType<(typeof PLACEMENTS_TYPES)[number]>,
56
+ validator: (value: (typeof PLACEMENTS_TYPES)[number]) => PLACEMENTS_TYPES.includes(value),
57
+ default: 'bottom',
58
+ },
59
+ groupItemsBy: {
60
+ type: String as PropType<(typeof GROUPED_ITEMS_BY_TYPES)[number]>,
61
+ validator: (value: (typeof GROUPED_ITEMS_BY_TYPES)[number] | undefined) => {
62
+ return value === undefined || GROUPED_ITEMS_BY_TYPES.includes(value);
63
+ },
64
+ },
65
+ wrapperPosition: {
66
+ type: String,
67
+ default: 'relative',
68
+ },
69
+ width: {
70
+ type: String,
71
+ default: '100%',
72
+ },
73
+ popperWidth: {
74
+ type: String,
75
+ default: '100%',
76
+ },
77
+ popperStrategy: {
78
+ type: String,
79
+ validator: (value: 'fixed' | 'absolute') => POPPER_STRATEGY_TYPES.includes(value),
80
+ default: 'absolute',
81
+ },
54
82
  };
55
83
 
56
84
  export const dropdownEmitTypes = {
57
85
  'get-selected-item': Object,
58
- 'get-popper-state': Boolean,
86
+ 'infinite-scroll-trigger': Boolean,
59
87
  };
60
88
 
61
89
  export type DropdownPropTypes = ExtractPropTypes<typeof dropdownPropTypes>;
@@ -1,40 +1,49 @@
1
1
  <template>
2
2
  <Menu
3
- v-model:shown="menuOpenedState"
4
- class="spr-w-fit"
3
+ v-model:shown="dropdownPopperState"
5
4
  aria-id="dropdown-wrapper"
6
5
  distance="4"
7
6
  :placement="props.placement"
8
7
  :triggers="[]"
9
8
  :popper-hide-triggers="[]"
9
+ :auto-hide="false"
10
+ :container="`#${props.id}`"
11
+ :strategy="
12
+ props.popperStrategy === 'fixed' || props.popperStrategy === 'absolute' ? props.popperStrategy : 'absolute'
13
+ "
14
+ :delay="0"
15
+ :style="{
16
+ position: props.wrapperPosition,
17
+ width: props.width,
18
+ }"
10
19
  >
11
- <div @click="menuOpenedState = !menuOpenedState">
20
+ <div @click="dropdownPopperState = true">
12
21
  <slot />
13
22
  </div>
14
23
 
24
+ <div
25
+ :id="props.id"
26
+ :style="{
27
+ width: props.popperWidth,
28
+ }"
29
+ ></div>
30
+
15
31
  <template #popper>
16
- <div class="spr-grid spr-gap-0.5">
17
- <div
18
- v-for="(item, index) in props.menu"
19
- :key="index"
20
- :class="[
21
- dropdownItemBaseClasses,
22
- {
23
- 'spr-background-color-single-active': isItemSelected(item),
24
- },
25
- ]"
26
- @click="handleSelectedItem(item)"
27
- >
28
- <spr-checkbox v-if="props.dropdownType === 'multi-select'" v-model="checkboxModels[item.text]" />
29
- <div class="spr-flex spr-w-full spr-items-center">
30
- <span class="spr-text-xs">{{ item.text }}</span>
31
- </div>
32
- <Icon
33
- v-if="props.dropdownType === 'single-select' && isItemSelected(item)"
34
- class="spr-text-color-brand-base spr-w-[1.39em]"
35
- icon="ph:check"
32
+ <div ref="dropdownRef" class="spr-grid spr-max-h-[300px] spr-gap-0.5 spr-overflow-y-auto spr-p-2">
33
+ <template v-if="dropdownMenuList.length > 0">
34
+ <SprList
35
+ v-model="preSelectedItems"
36
+ :menu-list="dropdownMenuList"
37
+ :group-items-by="props.groupItemsBy"
38
+ :multi-select="props.multiSelect"
39
+ @get-selected-item="handleSelectedItem"
36
40
  />
37
- </div>
41
+ </template>
42
+ <template v-else>
43
+ <div class="spr-flex spr-items-center spr-justify-center spr-p-2 spr-text-center">
44
+ <span class="spr-body-sm-regular spr-m-0">No results found</span>
45
+ </div>
46
+ </template>
38
47
  </div>
39
48
  </template>
40
49
  </Menu>
@@ -42,19 +51,18 @@
42
51
 
43
52
  <script lang="ts" setup>
44
53
  import { Menu } from 'floating-vue';
45
- import { Icon } from '@iconify/vue';
46
54
 
47
55
  import 'floating-vue/dist/style.css';
48
56
 
49
57
  import { dropdownPropTypes, dropdownEmitTypes } from './dropdown';
50
58
  import { useDropdown } from './use-dropdown';
51
59
 
52
- import SprCheckbox from '../checkbox/checkbox.vue';
60
+ import SprList from '../list/list.vue';
53
61
 
54
62
  const props = defineProps(dropdownPropTypes);
55
63
  const emit = defineEmits(dropdownEmitTypes);
56
64
 
57
- const { dropdownItemBaseClasses, menuOpenedState, handleSelectedItem, isItemSelected, checkboxModels } = useDropdown(
65
+ const { dropdownPopperState, dropdownRef, preSelectedItems, dropdownMenuList, handleSelectedItem } = useDropdown(
58
66
  props,
59
67
  emit,
60
68
  );
@@ -1,6 +1,5 @@
1
- import { ref, toRefs, onMounted, watch, computed, ComputedRef } from 'vue';
2
-
3
- import classNames from 'classnames';
1
+ import { ref, toRefs, onMounted, watch } from 'vue';
2
+ import { onClickOutside, useInfiniteScroll } from '@vueuse/core';
4
3
 
5
4
  import type { SetupContext } from 'vue';
6
5
  import type { DropdownPropTypes, DropdownEmitTypes } from './dropdown';
@@ -11,115 +10,67 @@ interface SelectedItem {
11
10
  }
12
11
 
13
12
  export const useDropdown = (props: DropdownPropTypes, emit: SetupContext<DropdownEmitTypes>['emit']) => {
14
- const { menu, preSelectedItems, dropdownType, menuOpened } = toRefs(props);
15
-
16
- const dropdownItemBaseClasses: ComputedRef<string> = computed(() => {
17
- return classNames(
18
- 'spr-flex spr-cursor-pointer spr-items-center spr-justify-between spr-gap-1.5 spr-rounded-lg spr-p-2',
19
- 'spr-transition spr-duration-150 spr-ease-in-out',
20
- 'hover:spr-background-color-hover',
21
- 'active:spr-background-color-single-active active:spr-scale-95',
22
- );
23
- });
13
+ const { modelValue, menuList, searchString, multiSelect } = toRefs(props);
24
14
 
25
- const menuOpenedState = ref<boolean>(false);
15
+ const dropdownPopperState = ref<boolean>(false);
26
16
 
27
- watch(menuOpenedState, () => {
28
- handlePopperState();
29
- });
17
+ const dropdownRef = ref<HTMLDivElement | null>(null);
30
18
 
31
- const isSingleSelect = computed(() => dropdownType.value === 'single-select');
32
- const isMultiSelect = computed(() => dropdownType.value === 'multi-select');
19
+ const preSelectedItems = ref<Array<string>>([]);
33
20
 
34
- const selectedItems = ref<SelectedItem[]>([]);
21
+ const initialMenuList = ref<{ text: string; value: string }[]>([]);
22
+ const dropdownMenuList = ref<{ text: string; value: string }[]>([]);
35
23
 
36
24
  const handleSelectedItem = (item: SelectedItem) => {
37
- if (isSingleSelect.value) {
38
- menuOpenedState.value = false;
39
-
40
- selectedItems.value = [item];
41
-
42
- emit('get-selected-item', selectedItems.value[0]);
25
+ if (!multiSelect.value) {
26
+ dropdownPopperState.value = false;
43
27
  }
44
28
 
45
- if (isMultiSelect.value) {
46
- const index = selectedItems.value.findIndex((selectedItem: SelectedItem) => selectedItem.value === item.value);
47
-
48
- if (index === -1) {
49
- checkboxModels.value[item.text] = true;
50
- selectedItems.value.push(item);
51
- } else {
52
- checkboxModels.value[item.text] = false;
53
- selectedItems.value.splice(index, 1);
54
- }
55
-
56
- emit('get-selected-item', selectedItems.value);
57
- }
29
+ emit('get-selected-item', item);
58
30
  };
59
31
 
60
- const isItemSelected = (item: SelectedItem) => {
61
- if (Array.isArray(selectedItems.value)) {
62
- return selectedItems.value.some((selectedItem) => selectedItem.text === item.text);
63
- }
64
-
65
- return (selectedItems.value[0] as SelectedItem).text === item.text;
32
+ const setDropdownMenuList = () => {
33
+ initialMenuList.value = menuList.value;
34
+ dropdownMenuList.value = initialMenuList.value;
66
35
  };
67
36
 
68
- const checkboxModels = ref<Record<string, boolean>>({});
37
+ const handleSearch = () => {
38
+ if (menuList.value && menuList.value.length > 0) {
39
+ dropdownMenuList.value = initialMenuList.value.filter((item) => {
40
+ const searchTerm = searchString.value.toLowerCase();
69
41
 
70
- const setCheckboxModels = () => {
71
- if (menu.value && menu.value.length > 0) {
72
- menu.value.forEach((item) => {
73
- checkboxModels.value = Object.assign({}, checkboxModels.value, {
74
- [item.text]: false,
75
- });
42
+ return item.text.toLowerCase().includes(searchTerm) || item.value.toLowerCase().includes(searchTerm);
76
43
  });
77
44
  }
78
45
  };
79
46
 
80
- const setPreSelectedItems = () => {
81
- if (menu.value && menu.value.length > 0 && preSelectedItems.value && preSelectedItems.value.length > 0) {
82
- (preSelectedItems.value as string[]).forEach((preSelectedItem: string) => {
83
- const item = menu.value.find((menuItem) => menuItem.text === preSelectedItem);
84
-
85
- if (item) {
86
- if (isMultiSelect.value) {
87
- checkboxModels.value[item.text] = true;
88
- }
89
-
90
- selectedItems.value.push(item);
91
- }
92
- });
93
-
94
- if (isSingleSelect.value) {
95
- if (selectedItems.value.length > 0) {
96
- emit('get-selected-item', selectedItems.value[0]);
97
- }
98
- }
47
+ watch(searchString, () => {
48
+ handleSearch();
49
+ });
99
50
 
100
- if (isMultiSelect.value) {
101
- emit('get-selected-item', selectedItems.value);
102
- }
103
- }
104
- };
51
+ onClickOutside(dropdownRef, () => {
52
+ dropdownPopperState.value = false;
53
+ });
105
54
 
106
- const handlePopperState = () => {
107
- emit('get-popper-state', menuOpenedState.value);
108
- };
55
+ useInfiniteScroll(
56
+ dropdownRef,
57
+ () => {
58
+ emit('infinite-scroll-trigger', true);
59
+ },
60
+ { distance: 10 },
61
+ );
109
62
 
110
63
  onMounted(() => {
111
- menuOpenedState.value = menuOpened.value;
64
+ preSelectedItems.value = modelValue.value;
112
65
 
113
- setCheckboxModels();
114
- setPreSelectedItems();
115
- handlePopperState();
66
+ setDropdownMenuList();
116
67
  });
117
68
 
118
69
  return {
119
- dropdownItemBaseClasses,
120
- menuOpenedState,
70
+ dropdownPopperState,
71
+ dropdownRef,
72
+ preSelectedItems,
73
+ dropdownMenuList,
121
74
  handleSelectedItem,
122
- isItemSelected,
123
- checkboxModels,
124
75
  };
125
76
  };
@@ -5,8 +5,28 @@ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<
5
5
  const TRAILING_SIZES = ['xs', 'sm', 'md'] as const;
6
6
 
7
7
  export const INPUT_TYPES = [
8
- 'button', 'checkbox', 'color', 'date', 'datetime-local', 'email', 'file', 'hidden', 'image', 'month',
9
- 'number', 'password', 'radio', 'range', 'reset', 'search', 'submit', 'tel', 'text', 'time', 'url', 'week'
8
+ 'button',
9
+ 'checkbox',
10
+ 'color',
11
+ 'date',
12
+ 'datetime-local',
13
+ 'email',
14
+ 'file',
15
+ 'hidden',
16
+ 'image',
17
+ 'month',
18
+ 'number',
19
+ 'password',
20
+ 'radio',
21
+ 'range',
22
+ 'reset',
23
+ 'search',
24
+ 'submit',
25
+ 'tel',
26
+ 'text',
27
+ 'time',
28
+ 'url',
29
+ 'week',
10
30
  ] as const;
11
31
 
12
32
  export const inputPropTypes = {
@@ -16,7 +36,11 @@ export const inputPropTypes = {
16
36
  },
17
37
  modelValue: {
18
38
  type: String,
19
- required: true,
39
+ default: '',
40
+ },
41
+ value: {
42
+ type: String,
43
+ default: '',
20
44
  },
21
45
  label: {
22
46
  type: String,
@@ -43,6 +67,14 @@ export const inputPropTypes = {
43
67
  type: Boolean,
44
68
  default: false,
45
69
  },
70
+ minLength: {
71
+ type: Number,
72
+ default: 0,
73
+ },
74
+ maxLength: {
75
+ type: Number,
76
+ default: 0,
77
+ },
46
78
  error: {
47
79
  type: Boolean,
48
80
  default: false,
@@ -54,16 +86,16 @@ export const inputPropTypes = {
54
86
  },
55
87
  helperText: {
56
88
  type: String,
57
- default: ''
89
+ default: '',
58
90
  },
59
91
  helperIcon: {
60
92
  type: String,
61
- default: null
93
+ default: null,
62
94
  },
63
95
  displayHelper: {
64
96
  type: Boolean,
65
97
  default: false,
66
- }
98
+ },
67
99
  };
68
100
 
69
101
  export const inputEmitTypes = {
@@ -3,6 +3,7 @@
3
3
  <label v-if="props.label" :for="id" :class="inputClasses.labelClasses">
4
4
  {{ props.label }}
5
5
  </label>
6
+
6
7
  <div class="spr-relative">
7
8
  <div v-if="$slots.prefix" :class="inputClasses.prefixSlotClasses">
8
9
  <slot name="prefix" />
@@ -12,8 +13,10 @@
12
13
  :placeholder="props.placeholder"
13
14
  :disabled="props.disabled"
14
15
  :readonly="props.readonly"
15
- :value="props.modelValue"
16
+ :value="props.modelValue ? props.modelValue : props.value"
16
17
  :type="props.type"
18
+ :minlength="props.minLength"
19
+ :maxlength="props.maxLength"
17
20
  @input="onInput"
18
21
  />
19
22
  <div v-if="$slots.trailing" :class="inputClasses.trailingSlotClasses">
@@ -32,7 +32,7 @@ export const useInput = (
32
32
  });
33
33
 
34
34
  const inputTextClasses = classNames(
35
- 'spr-block spr-w-full spr-px-size-spacing-2xs spr-py-size-spacing-4xs spr-rounded-border-radius-md spr-outline-none spr-ring-0',
35
+ 'spr-block spr-h-9 spr-w-full spr-px-size-spacing-2xs spr-py-size-spacing-4xs spr-rounded-border-radius-md spr-outline-none spr-ring-0 spr-box-border',
36
36
  'spr-text-color-strong spr-font-size-200 [font-weight:inherit]',
37
37
  'spr-border spr-border-solid',
38
38
  'placeholder:spr-text-mushroom-300',
@@ -44,7 +44,7 @@ export const useInput = (
44
44
  disabled.value,
45
45
  'spr-pr-[5%]': slots.icon,
46
46
  'spr-pl-size-spacing-lg': slots.prefix,
47
- '!spr-pl-size-spacing-3xl': props.type === 'url',
47
+ '!spr-pl-size-spacing-3xl': props.type === 'url',
48
48
  'spr-pr-[93%] sm:spr-pr-[85%]': offsetSize.value === 'xs' && slots.trailing,
49
49
  'spr-pr-[90%] sm:spr-pr-[80%]': offsetSize.value === 'sm' && slots.trailing,
50
50
  'spr-pr-[50%]': offsetSize.value === 'md' && slots.trailing,
@@ -77,20 +77,24 @@ export const useInput = (
77
77
  },
78
78
  );
79
79
 
80
- const helperClasses = classNames(
81
- {
82
- 'spr-text-color-danger-base': error.value,
83
- 'spr-text-color-supporting': !error.value,
84
- }
85
- );
80
+ const helperClasses = classNames({
81
+ 'spr-text-color-danger-base': error.value,
82
+ 'spr-text-color-supporting': !error.value,
83
+ });
86
84
 
87
- return { baseClasses, labelClasses, inputTextClasses, iconSlotClasses, prefixSlotClasses, trailingSlotClasses, helperClasses };
85
+ return {
86
+ baseClasses,
87
+ labelClasses,
88
+ inputTextClasses,
89
+ iconSlotClasses,
90
+ prefixSlotClasses,
91
+ trailingSlotClasses,
92
+ helperClasses,
93
+ };
88
94
  });
89
95
 
90
- const onInput = (event: Event) => {
91
- const target = event.target as HTMLInputElement;
92
-
93
- modelValue.value = target.value;
96
+ const onInput = () => {
97
+ emit('update:modelValue', modelValue.value);
94
98
  };
95
99
 
96
100
  return {
@@ -0,0 +1,34 @@
1
+ import type { PropType, ExtractPropTypes } from 'vue';
2
+
3
+ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<T>;
4
+
5
+ const GROUPED_ITEMS_BY_TYPES = ['A-Z', 'Z-A'] as const;
6
+
7
+ export const listPropTypes = {
8
+ modelValue: {
9
+ type: Array as PropType<string[]>,
10
+ default: () => [],
11
+ },
12
+ menuList: {
13
+ type: Array as PropType<{ text: string; value: string }[]>,
14
+ required: true,
15
+ default: [],
16
+ },
17
+ groupItemsBy: {
18
+ type: String as PropType<(typeof GROUPED_ITEMS_BY_TYPES)[number]>,
19
+ validator: (value: (typeof GROUPED_ITEMS_BY_TYPES)[number] | undefined) => {
20
+ return value === undefined || GROUPED_ITEMS_BY_TYPES.includes(value);
21
+ },
22
+ },
23
+ multiSelect: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
27
+ };
28
+
29
+ export const listEmitTypes = {
30
+ 'get-selected-item': Object,
31
+ };
32
+
33
+ export type ListPropTypes = ExtractPropTypes<typeof listPropTypes>;
34
+ export type ListEmitTypes = typeof listEmitTypes;