@byyuurin/ui 0.2.0 → 0.3.0

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 (140) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +5 -3
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +2 -2
  5. package/dist/runtime/components/Accordion.vue +41 -41
  6. package/dist/runtime/components/Accordion.vue.d.ts +11 -7
  7. package/dist/runtime/components/Alert.vue +63 -63
  8. package/dist/runtime/components/Alert.vue.d.ts +4 -4
  9. package/dist/runtime/components/App.vue +11 -10
  10. package/dist/runtime/components/App.vue.d.ts +11 -7
  11. package/dist/runtime/components/Avatar.vue +29 -29
  12. package/dist/runtime/components/Avatar.vue.d.ts +4 -3
  13. package/dist/runtime/components/AvatarGroup.vue +4 -4
  14. package/dist/runtime/components/AvatarGroup.vue.d.ts +1 -1
  15. package/dist/runtime/components/Badge.vue +32 -32
  16. package/dist/runtime/components/Badge.vue.d.ts +2 -2
  17. package/dist/runtime/components/Breadcrumb.vue +49 -49
  18. package/dist/runtime/components/Breadcrumb.vue.d.ts +10 -6
  19. package/dist/runtime/components/Button.vue +52 -51
  20. package/dist/runtime/components/Button.vue.d.ts +1 -1
  21. package/dist/runtime/components/Calendar.vue +74 -74
  22. package/dist/runtime/components/Calendar.vue.d.ts +16 -12
  23. package/dist/runtime/components/Card.vue +41 -41
  24. package/dist/runtime/components/Card.vue.d.ts +1 -1
  25. package/dist/runtime/components/Carousel.vue +66 -66
  26. package/dist/runtime/components/Carousel.vue.d.ts +14 -10
  27. package/dist/runtime/components/Checkbox.vue +46 -46
  28. package/dist/runtime/components/Checkbox.vue.d.ts +4 -3
  29. package/dist/runtime/components/CheckboxGroup.vue +29 -29
  30. package/dist/runtime/components/CheckboxGroup.vue.d.ts +11 -7
  31. package/dist/runtime/components/Chip.vue +15 -15
  32. package/dist/runtime/components/Chip.vue.d.ts +2 -2
  33. package/dist/runtime/components/Collapsible.vue +14 -14
  34. package/dist/runtime/components/Collapsible.vue.d.ts +2 -2
  35. package/dist/runtime/components/Drawer.vue +76 -76
  36. package/dist/runtime/components/Drawer.vue.d.ts +6 -6
  37. package/dist/runtime/components/DropdownMenu.vue +28 -28
  38. package/dist/runtime/components/DropdownMenu.vue.d.ts +17 -9
  39. package/dist/runtime/components/DropdownMenuContent.vue +152 -153
  40. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +11 -7
  41. package/dist/runtime/components/FieldGroup.vue +3 -3
  42. package/dist/runtime/components/FieldGroup.vue.d.ts +2 -2
  43. package/dist/runtime/components/Form.vue +9 -9
  44. package/dist/runtime/components/Form.vue.d.ts +13 -8
  45. package/dist/runtime/components/FormField.vue +39 -38
  46. package/dist/runtime/components/FormField.vue.d.ts +7 -2
  47. package/dist/runtime/components/Icon.vue +2 -2
  48. package/dist/runtime/components/Icon.vue.d.ts +1 -1
  49. package/dist/runtime/components/Input.vue +48 -48
  50. package/dist/runtime/components/Input.vue.d.ts +16 -12
  51. package/dist/runtime/components/InputNumber.vue +47 -47
  52. package/dist/runtime/components/InputNumber.vue.d.ts +128 -124
  53. package/dist/runtime/components/InputTags.vue +54 -53
  54. package/dist/runtime/components/InputTags.vue.d.ts +16 -11
  55. package/dist/runtime/components/Kbd.vue +3 -3
  56. package/dist/runtime/components/Kbd.vue.d.ts +2 -2
  57. package/dist/runtime/components/Link.vue +26 -25
  58. package/dist/runtime/components/Link.vue.d.ts +16 -6
  59. package/dist/runtime/components/LinkBase.vue +3 -3
  60. package/dist/runtime/components/LinkBase.vue.d.ts +2 -2
  61. package/dist/runtime/components/Marquee.vue +5 -5
  62. package/dist/runtime/components/Marquee.vue.d.ts +3 -3
  63. package/dist/runtime/components/Modal.vue +74 -74
  64. package/dist/runtime/components/Modal.vue.d.ts +6 -6
  65. package/dist/runtime/components/NavigationMenu.vue +228 -228
  66. package/dist/runtime/components/NavigationMenu.vue.d.ts +11 -7
  67. package/dist/runtime/components/OverlayProvider.vue +9 -9
  68. package/dist/runtime/components/Pagination.vue +47 -47
  69. package/dist/runtime/components/Pagination.vue.d.ts +4 -4
  70. package/dist/runtime/components/PinInput.vue +23 -23
  71. package/dist/runtime/components/PinInput.vue.d.ts +14 -10
  72. package/dist/runtime/components/Popover.vue +22 -22
  73. package/dist/runtime/components/Popover.vue.d.ts +11 -7
  74. package/dist/runtime/components/Progress.vue +25 -25
  75. package/dist/runtime/components/Progress.vue.d.ts +2 -2
  76. package/dist/runtime/components/RadioGroup.vue +50 -50
  77. package/dist/runtime/components/RadioGroup.vue.d.ts +11 -7
  78. package/dist/runtime/components/ScrollArea.vue +32 -32
  79. package/dist/runtime/components/ScrollArea.vue.d.ts +2 -2
  80. package/dist/runtime/components/Select.vue +299 -148
  81. package/dist/runtime/components/Select.vue.d.ts +103 -123
  82. package/dist/runtime/components/Separator.vue +30 -30
  83. package/dist/runtime/components/Separator.vue.d.ts +2 -2
  84. package/dist/runtime/components/Skeleton.vue +11 -11
  85. package/dist/runtime/components/Skeleton.vue.d.ts +2 -2
  86. package/dist/runtime/components/Slider.vue +25 -25
  87. package/dist/runtime/components/Slider.vue.d.ts +11 -7
  88. package/dist/runtime/components/Stepper.vue +116 -0
  89. package/dist/runtime/components/Stepper.vue.d.ts +83 -0
  90. package/dist/runtime/components/Switch.vue +30 -30
  91. package/dist/runtime/components/Switch.vue.d.ts +4 -3
  92. package/dist/runtime/components/Table.vue +137 -137
  93. package/dist/runtime/components/Table.vue.d.ts +13 -8
  94. package/dist/runtime/components/Tabs.vue +74 -74
  95. package/dist/runtime/components/Tabs.vue.d.ts +12 -8
  96. package/dist/runtime/components/Textarea.vue +47 -47
  97. package/dist/runtime/components/Textarea.vue.d.ts +16 -11
  98. package/dist/runtime/components/Timeline.vue +47 -47
  99. package/dist/runtime/components/Timeline.vue.d.ts +11 -7
  100. package/dist/runtime/components/Toast.vue +93 -93
  101. package/dist/runtime/components/Toast.vue.d.ts +5 -5
  102. package/dist/runtime/components/ToastProvider.vue +29 -29
  103. package/dist/runtime/components/ToastProvider.vue.d.ts +3 -3
  104. package/dist/runtime/components/Tooltip.vue +24 -25
  105. package/dist/runtime/components/Tooltip.vue.d.ts +2 -2
  106. package/dist/runtime/components/Tree.vue +241 -0
  107. package/dist/runtime/components/Tree.vue.d.ts +121 -0
  108. package/dist/runtime/composables/defineShortcuts.d.ts +1 -0
  109. package/dist/runtime/composables/defineShortcuts.js +44 -8
  110. package/dist/runtime/composables/useLocale.d.ts +12 -0
  111. package/dist/runtime/locale/en.d.ts +6 -0
  112. package/dist/runtime/locale/en.js +6 -0
  113. package/dist/runtime/locale/zh_tw.d.ts +6 -0
  114. package/dist/runtime/locale/zh_tw.js +6 -0
  115. package/dist/runtime/types/html.d.ts +8 -0
  116. package/dist/runtime/types/html.js +0 -0
  117. package/dist/runtime/types/index.d.ts +2 -0
  118. package/dist/runtime/types/index.js +2 -0
  119. package/dist/runtime/types/input.d.ts +5 -5
  120. package/dist/runtime/types/locale.d.ts +6 -0
  121. package/dist/runtime/types/unocss.d.ts +4 -4
  122. package/dist/runtime/types/utils.d.ts +3 -3
  123. package/dist/runtime/utils/index.d.ts +3 -3
  124. package/dist/runtime/utils/link.d.ts +2 -1
  125. package/dist/runtime/utils/link.js +40 -29
  126. package/dist/runtime/vue/components/Icon.vue +2 -2
  127. package/dist/runtime/vue/components/Icon.vue.d.ts +1 -1
  128. package/dist/runtime/vue/components/Link.vue +7 -12
  129. package/dist/runtime/vue/components/Link.vue.d.ts +11 -40
  130. package/dist/setup.d.mts +1 -1
  131. package/dist/shared/{ui.CzIlLITK.mjs → ui.9kQouwss.mjs} +5 -3
  132. package/dist/shared/{ui.DpbffTXs.d.mts → ui.D8Bg1HWt.d.mts} +2 -0
  133. package/dist/shared/{ui.DLOxhmP0.mjs → ui.DpkP12cX.mjs} +262 -17
  134. package/dist/unocss.mjs +1 -1
  135. package/dist/unplugin.d.mts +1 -1
  136. package/dist/unplugin.mjs +2 -2
  137. package/dist/vite.d.mts +1 -1
  138. package/dist/vite.mjs +2 -2
  139. package/package.json +29 -29
  140. package/vue-plugin.d.ts +5 -5
@@ -3,29 +3,37 @@ import theme from "#build/ui/select";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { reactivePick } from "@vueuse/core";
6
+ import { createReusableTemplate, reactivePick } from "@vueuse/core";
7
7
  import { defu } from "defu";
8
- import { SelectArrow, SelectContent, SelectGroup, SelectItem as RekaSelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectPortal, SelectRoot, SelectSeparator, SelectTrigger, useForwardPropsEmits } from "reka-ui";
9
- import { computed, onMounted, shallowRef, toRef } from "vue";
8
+ import { ComboboxAnchor, ComboboxArrow, ComboboxCancel, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxItemIndicator, ComboboxLabel, ComboboxPortal, ComboboxRoot, ComboboxSeparator, ComboboxTrigger, FocusScope, useFilter, useForwardPropsEmits } from "reka-ui";
9
+ import { computed, onMounted, shallowRef, toRaw, toRef } from "vue";
10
10
  import { useAppConfig } from "#imports";
11
11
  import { useComponentIcons } from "../composables/useComponentIcons";
12
12
  import { useFieldGroup } from "../composables/useFieldGroup";
13
13
  import { useFormField } from "../composables/useFormField";
14
+ import { useLocale } from "../composables/useLocale";
14
15
  import { usePortal } from "../composables/usePortal";
15
- import { get, getDisplayValue, isArrayOfArray } from "../utils";
16
+ import { compare, get, getDisplayValue, isArrayOfArray, looseToNumber } from "../utils";
16
17
  import { cv, merge } from "../utils/style";
17
18
  import Avatar from "./Avatar.vue";
19
+ import Button from "./Button.vue";
18
20
  import Chip from "./Chip.vue";
19
21
  import Icon from "./Icon.vue";
22
+ import Input from "./Input.vue";
20
23
  defineOptions({ inheritAttrs: false });
21
24
  const props = defineProps({
22
25
  id: { type: String, required: false },
23
26
  placeholder: { type: String, required: false },
27
+ searchInput: { type: [Boolean, Object], required: false, default: false },
28
+ searchTerm: { type: String, required: false, default: "" },
29
+ required: { type: Boolean, required: false },
24
30
  variant: { type: null, required: false },
25
31
  size: { type: null, required: false },
26
32
  color: { type: null, required: false },
27
33
  trailingIcon: { type: [String, Object], required: false },
28
34
  selectedIcon: { type: [String, Object], required: false },
35
+ clear: { type: [Boolean, Object], required: false },
36
+ clearIcon: { type: [String, Object], required: false },
29
37
  content: { type: Object, required: false },
30
38
  arrow: { type: [Boolean, Object], required: false },
31
39
  portal: { type: [Boolean, String], required: false, skipCheck: true, default: true },
@@ -35,8 +43,12 @@ const props = defineProps({
35
43
  items: { type: null, required: false },
36
44
  defaultValue: { type: null, required: false },
37
45
  modelValue: { type: null, required: false },
46
+ modelModifiers: { type: Object, required: false },
38
47
  multiple: { type: Boolean, required: false },
39
48
  highlight: { type: Boolean, required: false },
49
+ createItem: { type: [Boolean, String, Object], required: false },
50
+ filterFields: { type: Array, required: false },
51
+ ignoreFilter: { type: Boolean, required: false },
40
52
  autofocus: { type: Boolean, required: false },
41
53
  autofocusDelay: { type: Number, required: false, default: 0 },
42
54
  ui: { type: null, required: false },
@@ -50,17 +62,25 @@ const props = defineProps({
50
62
  loadingIcon: { type: [String, Object], required: false },
51
63
  open: { type: Boolean, required: false },
52
64
  defaultOpen: { type: Boolean, required: false },
53
- autocomplete: { type: String, required: false },
54
65
  disabled: { type: Boolean, required: false },
55
66
  name: { type: String, required: false },
56
- required: { type: Boolean, required: false }
67
+ resetSearchTermOnBlur: { type: Boolean, required: false, default: true },
68
+ resetSearchTermOnSelect: { type: Boolean, required: false, default: true },
69
+ resetModelValueOnClear: { type: Boolean, required: false, default: true },
70
+ highlightOnHover: { type: Boolean, required: false }
57
71
  });
58
- const emit = defineEmits(["update:open", "change", "blur", "focus", "update:modelValue"]);
72
+ const emit = defineEmits(["highlight", "update:open", "change", "blur", "focus", "create", "clear", "update:searchTerm", "update:modelValue"]);
59
73
  const slots = defineSlots();
60
- const rootProps = useForwardPropsEmits(reactivePick(props, "open", "defaultOpen", "disabled", "autocomplete", "required", "multiple"), emit);
74
+ const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate();
75
+ const { t } = useLocale();
76
+ const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" } });
77
+ const { contains } = useFilter({ sensitivity: "base" });
78
+ const rootProps = useForwardPropsEmits(reactivePick(props, "modelValue", "defaultValue", "open", "defaultOpen", "required", "multiple", "resetSearchTermOnBlur", "resetSearchTermOnSelect", "resetModelValueOnClear", "highlightOnHover"), emit);
61
79
  const portalProps = usePortal(toRef(() => props.portal));
62
80
  const contentProps = toRef(() => defu(props.content, { side: "bottom", sideOffset: 8, collisionPadding: 8, position: "popper" }));
63
81
  const arrowProps = toRef(() => props.arrow);
82
+ const clearProps = computed(() => typeof props.clear === "object" ? props.clear : {});
83
+ const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t("select.search"), ...props.searchInput ? {} : { readonly: true } }));
64
84
  const { id, name, size: formFieldSize, color, highlight, disabled, ariaAttrs, emitFormChange, emitFormInput, emitFormBlur, emitFormFocus } = useFormField(props);
65
85
  const { size: fieldGroupSize, orientation } = useFieldGroup(props);
66
86
  const appConfig = useAppConfig();
@@ -76,13 +96,41 @@ const ui = computed(() => {
76
96
  color: color.value,
77
97
  highlight: highlight.value,
78
98
  leading: isLeading.value || !!props.avatar || !!slots.leading,
79
- trailing: isTrailing.value || !!slots.trailing
99
+ trailing: isTrailing.value || !!slots.trailing,
100
+ searchInput: !!props.searchInput
80
101
  });
81
102
  });
82
103
  const groups = computed(
83
104
  () => props.items?.length ? isArrayOfArray(props.items) ? props.items : [props.items] : []
84
105
  );
85
106
  const items = computed(() => groups.value.flat());
107
+ const filteredGroups = computed(() => {
108
+ if (props.ignoreFilter || !searchTerm.value)
109
+ return groups.value;
110
+ const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey];
111
+ return groups.value.map((items2) => items2.filter((item) => {
112
+ if (item == null)
113
+ return false;
114
+ if (typeof item !== "object")
115
+ return contains(String(item), searchTerm.value);
116
+ if (item.type && ["label", "separator"].includes(item.type))
117
+ return true;
118
+ return fields.some((field) => {
119
+ const value = get(item, field);
120
+ return value != null && contains(String(value), searchTerm.value);
121
+ });
122
+ })).filter((group) => group.some((item) => !isSelectItem(item) || (!item.type || !["label", "separator"].includes(item.type))));
123
+ });
124
+ const filteredItems = computed(() => filteredGroups.value.flat());
125
+ const createItem = computed(() => {
126
+ if (!props.createItem || !searchTerm.value)
127
+ return false;
128
+ const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } : searchTerm.value;
129
+ if (typeof props.createItem === "object" && props.createItem.when === "always" || props.createItem === "always")
130
+ return !filteredItems.value.some((item) => compare(item, newItem, props.valueKey));
131
+ return !filteredItems.value.length;
132
+ });
133
+ const createItemPosition = computed(() => typeof props.createItem === "object" ? props.createItem.position : "bottom");
86
134
  function displayValue(value) {
87
135
  if (props.multiple && Array.isArray(value)) {
88
136
  const displayedValues = value.map((item) => getDisplayValue(items.value, item, {
@@ -108,167 +156,270 @@ onMounted(() => {
108
156
  setTimeout(() => autoFocus(), props.autofocusDelay);
109
157
  });
110
158
  function onUpdate(value) {
159
+ if (toRaw(props.modelValue) === value)
160
+ return;
161
+ if (props.modelModifiers?.trim)
162
+ value = value?.trim() ?? null;
163
+ if (props.modelModifiers?.number)
164
+ value = looseToNumber(value);
165
+ if (props.modelModifiers?.nullable)
166
+ value ??= null;
167
+ if (props.modelModifiers?.optional)
168
+ value ??= void 0;
111
169
  const event = new Event("change", { target: { value } });
112
170
  emit("change", event);
113
171
  emitFormChange();
114
172
  emitFormInput();
173
+ if (props.resetSearchTermOnSelect)
174
+ searchTerm.value = "";
115
175
  }
116
176
  function onUpdateOpen(value) {
177
+ let timeoutId;
117
178
  if (value) {
118
179
  const event = new FocusEvent("focus");
119
180
  emit("focus", event);
120
181
  emitFormFocus();
182
+ clearTimeout(timeoutId);
121
183
  } else {
122
184
  const event = new FocusEvent("blur");
123
185
  emit("blur", event);
124
186
  emitFormBlur();
187
+ if (props.resetSearchTermOnBlur) {
188
+ const STATE_ANIMATION_DELAY_MS = 100;
189
+ timeoutId = setTimeout(() => {
190
+ searchTerm.value = "";
191
+ }, STATE_ANIMATION_DELAY_MS);
192
+ }
193
+ }
194
+ }
195
+ function onCreate(e) {
196
+ e.preventDefault();
197
+ e.stopPropagation();
198
+ emit("create", searchTerm.value);
199
+ }
200
+ function onSelect(e, item) {
201
+ if (!isSelectItem(item))
202
+ return;
203
+ if (item.disabled) {
204
+ e.preventDefault();
205
+ return;
125
206
  }
207
+ item.onSelect?.(e);
126
208
  }
127
209
  function isSelectItem(item) {
128
210
  return typeof item === "object" && item !== null;
129
211
  }
212
+ function isModelValueEmpty(modelValue) {
213
+ if (props.multiple && Array.isArray(modelValue))
214
+ return modelValue.length === 0;
215
+ return modelValue == null || modelValue === "";
216
+ }
217
+ function onClear() {
218
+ emit("clear");
219
+ }
130
220
  defineExpose({
131
- triggerRef
221
+ triggerRef: toRef(() => triggerRef.value?.$el)
132
222
  });
133
223
  </script>
134
224
 
135
225
  <template>
136
- <SelectRoot
137
- v-slot="{ modelValue, open }"
138
- :name="name"
139
- v-bind="rootProps"
140
- :default-value="defaultValue"
141
- :model-value="modelValue"
142
- :autocomplete="props.autocomplete"
143
- :disabled="disabled"
144
- @update:model-value="onUpdate"
145
- @update:open="onUpdateOpen"
146
- >
147
- <SelectTrigger
148
- ref="triggerRef"
149
- v-bind="{ id, ...$attrs, ...ariaAttrs }"
150
- :class="ui.base({ class: [props.ui?.base, props.class] })"
151
- data-part="base"
152
- >
153
- <span v-if="isLeading || !!props.avatar || slots.leading" :class="ui.leading({ class: props.ui?.leading })" data-part="leading">
154
- <slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
155
- <Icon
156
- v-if="isLeading && leadingIconName"
157
- :name="leadingIconName"
158
- :class="ui.leadingIcon({ class: props.ui?.leadingIcon })"
159
- data-part="leadingIcon"
160
- />
161
- <Avatar
162
- v-else-if="props.avatar"
163
- :size="props.ui?.itemLeadingChipSize || ui.itemLeadingAvatarSize()"
164
- v-bind="props.avatar"
165
- :class="ui.leadingAvatar({ class: props.ui?.leadingAvatar })"
166
- data-part="leadingAvatar"
167
- />
168
- </slot>
169
- </span>
170
-
171
- <slot :model-value="modelValue" :open="open" :ui="ui">
172
- <template v-for="displayedModelValue in [displayValue(modelValue)]" :key="displayedModelValue">
173
- <span v-if="displayedModelValue != null" :class="ui.value({ class: props.ui?.value })" data-part="value">
174
- {{ displayedModelValue }}
175
- </span>
176
- <span v-else :class="ui.placeholder({ class: props.ui?.placeholder })" data-part="placeholder">
177
- <template v-if="props.placeholder">{{ props.placeholder }}</template>
178
- <template v-else>&nbsp;</template>
179
- </span>
180
- </template>
181
- </slot>
182
-
183
- <span v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })" data-part="trailing">
184
- <slot name="trailing" :model-value="modelValue" :open="open" :ui="ui">
185
- <Icon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" data-part="trailingIcon" />
186
- </slot>
187
- </span>
188
- </SelectTrigger>
189
-
190
- <SelectPortal v-bind="portalProps">
191
- <SelectContent v-bind="contentProps" :class="ui.content({ class: props.ui?.content })" data-part="content">
192
- <slot name="content-top"></slot>
193
-
194
- <div role="presentation" :class="ui.viewport({ class: props.ui?.viewport })" data-part="viewport">
195
- <SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })" data-part="group">
196
- <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
197
- <SelectLabel v-if="isSelectItem(item) && item.type === 'label'" :class="ui.label({ class: [props.ui?.label, item.ui?.label, item.class] })" data-part="label">
198
- {{ get(item, props.labelKey) }}
199
- </SelectLabel>
200
-
201
- <SelectSeparator v-else-if="isSelectItem(item) && item.type === 'separator'" :class="ui.separator({ class: [props.ui?.separator, item.ui?.separator, item.class] })" data-part="separator" />
202
-
203
- <RekaSelectItem
204
- v-else
205
- :value="isSelectItem(item) ? get(item, props.valueKey) : item"
206
- :disabled="isSelectItem(item) && item.disabled"
207
- :class="ui.item({ class: [props.ui?.item, ...isSelectItem(item) ? [item.ui?.item, item.class] : []] })"
208
- data-part="item"
209
- @select="isSelectItem(item) && item.onSelect?.($event)"
210
- >
211
- <slot name="item" :item="item" :index="index" :ui="ui">
212
- <slot name="item-leading" :item="item" :index="index" :ui="ui">
213
- <Icon
214
- v-if="isSelectItem(item) && item.icon"
215
- :name="item.icon"
216
- :class="ui.itemLeadingIcon({ class: [props.ui?.itemLeadingIcon, item.ui?.itemLeadingIcon] })"
217
- data-part="itemLeadingIcon"
218
- />
219
- <Avatar
220
- v-else-if="isSelectItem(item) && item.avatar"
221
- :size="item.ui?.itemLeadingAvatarSize || props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()"
222
- v-bind="item.avatar"
223
- :class="ui.itemLeadingAvatar({ class: [props.ui?.leadingAvatar, item.ui?.itemLeadingAvatar] })"
224
- data-part="itemLeadingAvatar"
225
- />
226
- <Chip
227
- v-else-if="isSelectItem(item) && item.chip"
228
- :size="item.ui?.itemLeadingChipSize || props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()"
229
- inset
230
- standalone
231
- v-bind="item.chip"
232
- :class="ui.itemLeadingChip({ class: [props.ui?.itemLeadingChip, item.ui?.itemLeadingChip] })"
233
- data-part="itemLeadingChip"
234
- />
235
- </slot>
236
-
237
- <span :class="ui.itemWrapper({ class: [props.ui?.itemWrapper, ...isSelectItem(item) ? [item.ui?.itemWrapper] : []] })" data-part="itemWrapper">
238
- <SelectItemText :class="ui.itemLabel({ class: [props.ui?.itemLabel, isSelectItem(item) && item.ui?.itemLabel] })" data-part="itemLabel">
239
- <slot name="item-label" :item="item" :index="index">
240
- {{ isSelectItem(item) ? get(item, props.labelKey) : item }}
241
- </slot>
242
- </SelectItemText>
243
-
244
- <span
245
- v-if="isSelectItem(item) && get(item, props.descriptionKey) || !!slots['item-description']"
246
- :class="ui.itemDescription({ class: [props.ui?.itemDescription, ...isSelectItem(item) ? [item.ui?.itemDescription] : []] })"
247
- data-part="itemDescription"
248
- >
249
- <slot name="item-description" :item="item" :index="index">
250
- {{ isSelectItem(item) ? get(item, props.descriptionKey) : "" }}
251
- </slot>
252
- </span>
253
- </span>
254
-
255
- <span :class="ui.itemTrailing({ class: [props.ui?.itemTrailing, isSelectItem(item) && item.ui?.itemTrailing] })" data-part="itemTrailing">
256
- <slot name="item-trailing" :item="item" :index="index" :ui="ui"></slot>
257
-
258
- <SelectItemIndicator as-child>
259
- <Icon :name="props.selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: [props.ui?.itemTrailingIcon, isSelectItem(item) && item.ui?.itemTrailingIcon] })" data-part="itemTrailingIcon" />
260
- </SelectItemIndicator>
261
- </span>
262
- </slot>
263
- </RekaSelectItem>
264
- </template>
265
- </SelectGroup>
266
- </div>
267
-
268
- <slot name="content-bottom"></slot>
269
-
270
- <SelectArrow v-if="props.arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" data-part="arrow" />
271
- </SelectContent>
272
- </SelectPortal>
273
- </SelectRoot>
226
+ <DefineCreateItemTemplate>
227
+ <ComboboxItem
228
+ :value="searchTerm"
229
+ :class="ui.item({ class: props.ui?.item })"
230
+ data-part="item"
231
+ @select="onCreate"
232
+ >
233
+ <span :class="ui.itemLabel({ class: props.ui?.itemLabel })" data-part="itemLabel">
234
+ <slot name="create-item-label" :item="searchTerm">
235
+ {{ t("select.create", { label: searchTerm }) }}
236
+ </slot>
237
+ </span>
238
+ </ComboboxItem>
239
+ </DefineCreateItemTemplate>
240
+
241
+ <ComboboxRoot
242
+ :id="id"
243
+ v-slot="{ modelValue, open }"
244
+ v-bind="{ ...rootProps, ...$attrs, ...ariaAttrs }"
245
+ :name="name"
246
+ :disabled="disabled"
247
+ ignore-filter
248
+ as-child
249
+ @update:model-value="onUpdate"
250
+ @update:open="onUpdateOpen"
251
+ >
252
+ <ComboboxAnchor as-child>
253
+ <ComboboxTrigger ref="triggerRef" :class="ui.base({ class: [props.ui?.base, props.class] })" data-part="base" tabindex="0">
254
+ <span v-if="isLeading || !!props.avatar || slots.leading" :class="ui.leading({ class: props.ui?.leading })" data-part="leading">
255
+ <slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
256
+ <Icon
257
+ v-if="isLeading && leadingIconName"
258
+ :name="leadingIconName"
259
+ :class="ui.leadingIcon({ class: props.ui?.leadingIcon })"
260
+ data-part="leadingIcon"
261
+ />
262
+ <Avatar
263
+ v-else-if="props.avatar"
264
+ :size="props.ui?.itemLeadingChipSize || ui.itemLeadingAvatarSize()"
265
+ v-bind="props.avatar"
266
+ :class="ui.leadingAvatar({ class: props.ui?.leadingAvatar })"
267
+ data-part="leadingAvatar"
268
+ />
269
+ </slot>
270
+ </span>
271
+
272
+ <slot :model-value="modelValue" :open="open" :ui="ui">
273
+ <template v-for="displayedModelValue in [displayValue(modelValue)]" :key="displayedModelValue">
274
+ <span v-if="displayedModelValue != null" :class="ui.value({ class: props.ui?.value })" data-part="value">
275
+ {{ displayedModelValue }}
276
+ </span>
277
+ <span v-else :class="ui.placeholder({ class: props.ui?.placeholder })" data-part="placeholder">
278
+ <template v-if="props.placeholder">{{ props.placeholder }}</template>
279
+ <template v-else>&nbsp;</template>
280
+ </span>
281
+ </template>
282
+ </slot>
283
+
284
+ <span v-if="isTrailing || !!slots.trailing || props.clear" :class="ui.trailing({ class: props.ui?.trailing })" data-part="trailing">
285
+ <slot name="trailing" :model-value="modelValue" :open="open" :ui="ui">
286
+ <ComboboxCancel v-if="props.clear && !isModelValueEmpty(modelValue)" as-child>
287
+ <Button
288
+ as="span"
289
+ :icon="props.clearIcon || appConfig.ui.icons.close"
290
+ variant="link"
291
+ color="neutral"
292
+ tabindex="-1"
293
+ v-bind="clearProps"
294
+ :class="ui.trailingClear({ class: props.ui?.trailingClear })"
295
+ data-part="trailingClear"
296
+ @click.stop="onClear"
297
+ />
298
+ </ComboboxCancel>
299
+ <Icon v-else-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" data-part="trailingIcon" />
300
+ </slot>
301
+ </span>
302
+ </ComboboxTrigger>
303
+ </ComboboxAnchor>
304
+
305
+ <ComboboxPortal v-bind="portalProps">
306
+ <ComboboxContent v-bind="contentProps" :class="ui.content({ class: props.ui?.content })" data-part="content">
307
+ <FocusScope trapped :class="ui.focusScope({ class: props.ui?.focusScope })" data-part="focusScope">
308
+ <slot name="content-top"></slot>
309
+
310
+ <ComboboxInput v-model="searchTerm" :display-value="() => searchTerm" as-child>
311
+ <Input
312
+ autofocus
313
+ autocomplete="off"
314
+ :size="props.size"
315
+ v-bind="searchInputProps"
316
+ :class="ui.input({ class: props.ui?.input })"
317
+ data-part="input"
318
+ @change.stop
319
+ />
320
+ </ComboboxInput>
321
+
322
+ <ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })" data-part="empty">
323
+ <slot name="empty" :search-term="searchTerm">
324
+ {{ searchTerm ? t("select.noMatch", { searchTerm }) : t("select.noData") }}
325
+ </slot>
326
+ </ComboboxEmpty>
327
+
328
+ <div role="presentation" :class="ui.viewport({ class: props.ui?.viewport })" data-part="viewport">
329
+ <ComboboxGroup v-if="createItem && createItemPosition === 'top'" :class="ui.group({ class: props.ui?.group })" data-part="group">
330
+ <ReuseCreateItemTemplate />
331
+ </ComboboxGroup>
332
+
333
+ <ComboboxGroup v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })" data-part="group">
334
+ <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
335
+ <ComboboxLabel
336
+ v-if="isSelectItem(item) && item.type === 'label'"
337
+ :class="ui.label({ class: [props.ui?.label, item.ui?.label, item.class] })"
338
+ data-part="label"
339
+ >
340
+ {{ get(item, props.labelKey) }}
341
+ </ComboboxLabel>
342
+
343
+ <ComboboxSeparator
344
+ v-else-if="isSelectItem(item) && item.type === 'separator'"
345
+ :class="ui.separator({ class: [props.ui?.separator, item.ui?.separator, item.class] })"
346
+ data-part="separator"
347
+ />
348
+
349
+ <ComboboxItem
350
+ v-else
351
+ :value="props.valueKey && isSelectItem(item) ? get(item, props.valueKey) : item"
352
+ :disabled="isSelectItem(item) && item.disabled"
353
+ :class="ui.item({ class: [props.ui?.item, ...isSelectItem(item) ? [item.ui?.item, item.class] : []] })"
354
+ data-part="item"
355
+ @select="onSelect($event, item)"
356
+ >
357
+ <slot name="item" :item="item" :index="index" :ui="ui">
358
+ <slot name="item-leading" :item="item" :index="index" :ui="ui">
359
+ <Icon
360
+ v-if="isSelectItem(item) && item.icon"
361
+ :name="item.icon"
362
+ :class="ui.itemLeadingIcon({ class: [props.ui?.itemLeadingIcon, item.ui?.itemLeadingIcon] })"
363
+ data-part="itemLeadingIcon"
364
+ />
365
+ <Avatar
366
+ v-else-if="isSelectItem(item) && item.avatar"
367
+ :size="item.ui?.itemLeadingAvatarSize || props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()"
368
+ v-bind="item.avatar"
369
+ :class="ui.itemLeadingAvatar({ class: [props.ui?.leadingAvatar, item.ui?.itemLeadingAvatar] })"
370
+ data-part="itemLeadingAvatar"
371
+ />
372
+ <Chip
373
+ v-else-if="isSelectItem(item) && item.chip"
374
+ :size="item.ui?.itemLeadingChipSize || props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()"
375
+ inset
376
+ standalone
377
+ v-bind="item.chip"
378
+ :class="ui.itemLeadingChip({ class: [props.ui?.itemLeadingChip, item.ui?.itemLeadingChip] })"
379
+ data-part="itemLeadingChip"
380
+ />
381
+ </slot>
382
+
383
+ <span :class="ui.itemWrapper({ class: [props.ui?.itemWrapper, isSelectItem(item) && item.ui?.itemWrapper] })" data-part="itemWrapper">
384
+ <span :class="ui.itemLabel({ class: [props.ui?.itemLabel, isSelectItem(item) && item.ui?.itemLabel] })" data-part="itemLabel">
385
+ <slot name="item-label" :item="item" :index="index">
386
+ {{ isSelectItem(item) ? get(item, props.labelKey) : item }}
387
+ </slot>
388
+ </span>
389
+
390
+ <span
391
+ v-if="isSelectItem(item) && get(item, props.descriptionKey) || !!slots['item-description']"
392
+ :class="ui.itemDescription({ class: [props.ui?.itemDescription, isSelectItem(item) && item.ui?.itemDescription] })"
393
+ data-part="itemDescription"
394
+ >
395
+ <slot name="item-description" :item="item" :index="index">
396
+ {{ isSelectItem(item) ? get(item, props.descriptionKey) : "" }}
397
+ </slot>
398
+ </span>
399
+ </span>
400
+
401
+ <span :class="ui.itemTrailing({ class: [props.ui?.itemTrailing, isSelectItem(item) && item.ui?.itemTrailing] })" data-part="itemTrailing">
402
+ <slot name="item-trailing" :item="item" :index="index" :ui="ui"></slot>
403
+
404
+ <ComboboxItemIndicator as-child>
405
+ <Icon :name="props.selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: [props.ui?.itemTrailingIcon, isSelectItem(item) && item.ui?.itemTrailingIcon] })" data-part="itemTrailingIcon" />
406
+ </ComboboxItemIndicator>
407
+ </span>
408
+ </slot>
409
+ </ComboboxItem>
410
+ </template>
411
+ </ComboboxGroup>
412
+
413
+ <ComboboxGroup v-if="createItem && createItemPosition === 'bottom'" :class="ui.group({ class: props.ui?.group })" data-part="group">
414
+ <ReuseCreateItemTemplate />
415
+ </ComboboxGroup>
416
+ </div>
417
+
418
+ <slot name="content-bottom"></slot>
419
+ </FocusScope>
420
+
421
+ <ComboboxArrow v-if="props.arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" data-part="arrow" />
422
+ </ComboboxContent>
423
+ </ComboboxPortal>
424
+ </ComboboxRoot>
274
425
  </template>