@sewadah/selaras 0.3.0 → 0.3.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.
Files changed (172) hide show
  1. package/README.md +4 -1
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +21 -6
  4. package/dist/runtime/components/AlertDialog.d.vue.ts +5 -3
  5. package/dist/runtime/components/AlertDialog.vue +17 -9
  6. package/dist/runtime/components/AlertDialog.vue.d.ts +5 -3
  7. package/dist/runtime/components/App.vue +2 -0
  8. package/dist/runtime/components/Autocomplete.d.vue.ts +2 -2
  9. package/dist/runtime/components/Autocomplete.vue +4 -2
  10. package/dist/runtime/components/Autocomplete.vue.d.ts +2 -2
  11. package/dist/runtime/components/Button.d.vue.ts +7 -5
  12. package/dist/runtime/components/Button.vue +14 -3
  13. package/dist/runtime/components/Button.vue.d.ts +7 -5
  14. package/dist/runtime/components/Calendar.d.vue.ts +69 -0
  15. package/dist/runtime/components/Calendar.vue +163 -0
  16. package/dist/runtime/components/Calendar.vue.d.ts +69 -0
  17. package/dist/runtime/components/Callout.vue +12 -1
  18. package/dist/runtime/components/CodeGroup.vue +13 -3
  19. package/dist/runtime/components/CodeTree.d.vue.ts +2 -0
  20. package/dist/runtime/components/CodeTree.vue +52 -1
  21. package/dist/runtime/components/CodeTree.vue.d.ts +2 -0
  22. package/dist/runtime/components/ColorModeSwitch.d.vue.ts +18 -0
  23. package/dist/runtime/components/ColorModeSwitch.vue +59 -0
  24. package/dist/runtime/components/ColorModeSwitch.vue.d.ts +18 -0
  25. package/dist/runtime/components/ColorPicker.d.vue.ts +8 -0
  26. package/dist/runtime/components/ColorPicker.vue +66 -45
  27. package/dist/runtime/components/ColorPicker.vue.d.ts +8 -0
  28. package/dist/runtime/components/Column.js +1 -1
  29. package/dist/runtime/components/CommandPalette.d.vue.ts +3 -1
  30. package/dist/runtime/components/CommandPalette.vue +5 -0
  31. package/dist/runtime/components/CommandPalette.vue.d.ts +3 -1
  32. package/dist/runtime/components/ConfirmRenderer.d.vue.ts +3 -0
  33. package/dist/runtime/components/ConfirmRenderer.vue +39 -0
  34. package/dist/runtime/components/ConfirmRenderer.vue.d.ts +3 -0
  35. package/dist/runtime/components/ContentNavigation.d.vue.ts +8 -1
  36. package/dist/runtime/components/ContentNavigation.vue +9 -2
  37. package/dist/runtime/components/ContentNavigation.vue.d.ts +8 -1
  38. package/dist/runtime/components/ContextMenu.d.vue.ts +8 -1
  39. package/dist/runtime/components/ContextMenu.vue +20 -6
  40. package/dist/runtime/components/ContextMenu.vue.d.ts +8 -1
  41. package/dist/runtime/components/DatePicker.d.vue.ts +10 -3
  42. package/dist/runtime/components/DatePicker.vue +24 -16
  43. package/dist/runtime/components/DatePicker.vue.d.ts +10 -3
  44. package/dist/runtime/components/Drawer.vue +3 -2
  45. package/dist/runtime/components/Dropdown.d.vue.ts +33 -6
  46. package/dist/runtime/components/Dropdown.vue +146 -12
  47. package/dist/runtime/components/Dropdown.vue.d.ts +33 -6
  48. package/dist/runtime/components/FileTree.d.vue.ts +2 -0
  49. package/dist/runtime/components/FileTree.vue +8 -4
  50. package/dist/runtime/components/FileTree.vue.d.ts +2 -0
  51. package/dist/runtime/components/FormField.d.vue.ts +4 -0
  52. package/dist/runtime/components/FormField.vue +19 -4
  53. package/dist/runtime/components/FormField.vue.d.ts +4 -0
  54. package/dist/runtime/components/Input.vue +3 -2
  55. package/dist/runtime/components/Kbd.vue +12 -2
  56. package/dist/runtime/components/Modal.vue +3 -2
  57. package/dist/runtime/components/NavigationMenu.d.vue.ts +10 -10
  58. package/dist/runtime/components/NavigationMenu.vue +13 -9
  59. package/dist/runtime/components/NavigationMenu.vue.d.ts +10 -10
  60. package/dist/runtime/components/NavigationMenuAccordionItem.vue +5 -1
  61. package/dist/runtime/components/NavigationMenuFlyoutList.vue +7 -4
  62. package/dist/runtime/components/Popover.d.vue.ts +8 -2
  63. package/dist/runtime/components/Popover.vue +13 -6
  64. package/dist/runtime/components/Popover.vue.d.ts +8 -2
  65. package/dist/runtime/components/ProsePre.d.vue.ts +2 -0
  66. package/dist/runtime/components/ProsePre.vue +2 -1
  67. package/dist/runtime/components/ProsePre.vue.d.ts +2 -0
  68. package/dist/runtime/components/Select.d.vue.ts +8 -4
  69. package/dist/runtime/components/Select.vue +4 -2
  70. package/dist/runtime/components/Select.vue.d.ts +8 -4
  71. package/dist/runtime/components/Slideover.vue +3 -2
  72. package/dist/runtime/components/SplitterPanel.d.vue.ts +2 -2
  73. package/dist/runtime/components/SplitterPanel.vue.d.ts +2 -2
  74. package/dist/runtime/components/Table.vue +95 -26
  75. package/dist/runtime/components/Tabs.d.vue.ts +44 -4
  76. package/dist/runtime/components/Tabs.vue +171 -18
  77. package/dist/runtime/components/Tabs.vue.d.ts +44 -4
  78. package/dist/runtime/components/Textarea.vue +3 -2
  79. package/dist/runtime/components/Timeline.d.vue.ts +19 -0
  80. package/dist/runtime/components/Timeline.vue +99 -0
  81. package/dist/runtime/components/Timeline.vue.d.ts +19 -0
  82. package/dist/runtime/components/Toast.d.vue.ts +10 -1
  83. package/dist/runtime/components/Toast.vue +94 -8
  84. package/dist/runtime/components/Toast.vue.d.ts +10 -1
  85. package/dist/runtime/components/Tooltip.d.vue.ts +8 -2
  86. package/dist/runtime/components/Tooltip.vue +13 -6
  87. package/dist/runtime/components/Tooltip.vue.d.ts +8 -2
  88. package/dist/runtime/composables/use-confirm.d.ts +14 -0
  89. package/dist/runtime/composables/use-confirm.js +28 -0
  90. package/dist/runtime/composables/use-form-field.d.ts +1 -0
  91. package/dist/runtime/composables/use-table.d.ts +3 -0
  92. package/dist/runtime/composables/use-table.js +10 -4
  93. package/dist/runtime/composables/use-toast.js +5 -1
  94. package/dist/runtime/directives/hotkey.d.ts +13 -0
  95. package/dist/runtime/directives/hotkey.js +107 -0
  96. package/dist/runtime/directives/index.d.ts +2 -0
  97. package/dist/runtime/directives/index.js +2 -0
  98. package/dist/runtime/directives/mask.d.ts +30 -0
  99. package/dist/runtime/directives/mask.js +165 -0
  100. package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +41 -36
  101. package/dist/runtime/internal/ComboboxSelectBase.vue +119 -26
  102. package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +41 -36
  103. package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +23 -17
  104. package/dist/runtime/internal/ComboboxSelectBody.vue +50 -11
  105. package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +23 -17
  106. package/dist/runtime/internal/DatePickerCalendarBody.vue +1 -1
  107. package/dist/runtime/internal/DatePickerRangeCalendarBody.vue +1 -1
  108. package/dist/runtime/internal/ShortcutHint.d.vue.ts +6 -0
  109. package/dist/runtime/internal/ShortcutHint.vue +13 -0
  110. package/dist/runtime/internal/ShortcutHint.vue.d.ts +6 -0
  111. package/dist/runtime/internal/ToastItemRenderer.d.vue.ts +9 -1
  112. package/dist/runtime/internal/ToastItemRenderer.vue +55 -8
  113. package/dist/runtime/internal/ToastItemRenderer.vue.d.ts +9 -1
  114. package/dist/runtime/internal/combobox-select.d.ts +19 -18
  115. package/dist/runtime/internal/combobox-select.js +38 -15
  116. package/dist/runtime/internal/programmatic-services.d.ts +13 -0
  117. package/dist/runtime/internal/programmatic-services.js +9 -0
  118. package/dist/runtime/internal/toast-stack.d.ts +36 -0
  119. package/dist/runtime/internal/toast-stack.js +36 -0
  120. package/dist/runtime/structural.css +1 -1
  121. package/dist/runtime/table.d.ts +1 -1
  122. package/dist/runtime/theme/alert-dialog.js +1 -1
  123. package/dist/runtime/theme/badge.d.ts +9 -0
  124. package/dist/runtime/theme/badge.js +2 -1
  125. package/dist/runtime/theme/button.d.ts +18 -0
  126. package/dist/runtime/theme/button.js +4 -1
  127. package/dist/runtime/theme/calendar.d.ts +86 -0
  128. package/dist/runtime/theme/calendar.js +19 -0
  129. package/dist/runtime/theme/callout.d.ts +0 -12
  130. package/dist/runtime/theme/callout.js +8 -8
  131. package/dist/runtime/theme/code-tree.js +1 -1
  132. package/dist/runtime/theme/command-palette.js +1 -1
  133. package/dist/runtime/theme/content-navigation.d.ts +3 -0
  134. package/dist/runtime/theme/content-navigation.js +1 -0
  135. package/dist/runtime/theme/drawer.js +1 -1
  136. package/dist/runtime/theme/dropdown.d.ts +21 -0
  137. package/dist/runtime/theme/dropdown.js +15 -2
  138. package/dist/runtime/theme/file-tree.js +1 -1
  139. package/dist/runtime/theme/form-field.d.ts +18 -0
  140. package/dist/runtime/theme/form-field.js +6 -1
  141. package/dist/runtime/theme/modal.js +1 -1
  142. package/dist/runtime/theme/slideover.js +1 -1
  143. package/dist/runtime/theme/table.d.ts +27 -0
  144. package/dist/runtime/theme/table.js +11 -2
  145. package/dist/runtime/theme/tabs.d.ts +87 -3
  146. package/dist/runtime/theme/tabs.js +46 -22
  147. package/dist/runtime/theme/timeline.d.ts +251 -0
  148. package/dist/runtime/theme/timeline.js +84 -0
  149. package/dist/runtime/theme/toast.d.ts +92 -0
  150. package/dist/runtime/theme/toast.js +29 -7
  151. package/dist/runtime/theme-config.d.ts +13 -2
  152. package/dist/runtime/types/index.d.ts +10 -2
  153. package/dist/runtime/utils/arrow.d.ts +21 -0
  154. package/dist/runtime/utils/arrow.js +10 -0
  155. package/dist/runtime/utils/autocomplete-contracts.d.ts +4 -4
  156. package/dist/runtime/utils/file-icons.js +3 -0
  157. package/dist/runtime/utils/icons.d.ts +2 -0
  158. package/dist/runtime/utils/icons.js +2 -0
  159. package/dist/runtime/utils/messages.d.ts +7 -0
  160. package/dist/runtime/utils/messages.js +7 -0
  161. package/dist/runtime/utils/navigation-menu.d.ts +7 -0
  162. package/dist/runtime/utils/navigation-menu.js +3 -0
  163. package/dist/runtime/utils/overlay.d.ts +17 -0
  164. package/dist/runtime/utils/overlay.js +7 -0
  165. package/dist/runtime/utils/select-contracts.d.ts +25 -11
  166. package/dist/runtime/utils/table-columns.js +1 -1
  167. package/dist/runtime/utils/table-contracts.d.ts +9 -1
  168. package/dist/runtime/utils/timeline-contracts.d.ts +42 -0
  169. package/dist/runtime/utils/timeline-contracts.js +0 -0
  170. package/dist/runtime/utils/ui.d.ts +11 -0
  171. package/dist/runtime/utils/ui.js +54 -1
  172. package/package.json +6 -5
@@ -1,6 +1,9 @@
1
1
  import type { VariantProps } from 'tailwind-variants';
2
2
  import type { SelectThemeSlots } from '../theme/select.js';
3
+ import type { RoundedArrowConfig } from '../utils/arrow.js';
3
4
  import type { ColorRole } from '../utils/color-registry.js';
5
+ import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
6
+ import type { SelectModelValue } from '../utils/select-contracts.js';
4
7
  import type { UiProp } from '../utils/ui.js';
5
8
  import type { SelectItems, SelectOption } from './combobox-select.js';
6
9
  import { selectTheme } from '../theme/select.js';
@@ -16,9 +19,9 @@ export interface ComboboxSelectBaseProps {
16
19
  open?: boolean;
17
20
  /** Initial uncontrolled open state. */
18
21
  defaultOpen?: boolean;
19
- modelValue?: string | number | (string | number)[];
22
+ modelValue?: SelectModelValue | SelectModelValue[];
20
23
  /** Initial uncontrolled selection and native form reset target. */
21
- defaultValue?: string | number | (string | number)[];
24
+ defaultValue?: SelectModelValue | SelectModelValue[];
22
25
  multiple?: boolean;
23
26
  searchable?: boolean;
24
27
  virtualize?: boolean | {
@@ -43,76 +46,78 @@ export interface ComboboxSelectBaseProps {
43
46
  resetSearchTermOnBlur?: boolean;
44
47
  resetSearchTermOnSelect?: boolean;
45
48
  /** Shows a small pointer triangle connecting the panel to its trigger. */
46
- arrow?: boolean;
49
+ arrow?: boolean | RoundedArrowConfig;
50
+ positioning?: OverlayPositioning;
51
+ portal?: OverlayPortal;
47
52
  /** Opts into the component's accessible small-screen presentation. */
48
53
  adaptive?: boolean;
49
54
  ui?: UiProp<SelectThemeSlots>;
50
55
  }
51
56
  export interface ComboboxSelectBaseEmits {
52
57
  'update:open': [value: boolean];
53
- 'update:modelValue': [value: string | number | (string | number)[] | undefined];
58
+ 'update:modelValue': [value: SelectModelValue | SelectModelValue[] | undefined];
54
59
  'update:searchTerm': [value: string];
55
60
  }
56
61
  declare var __VLS_43: {
57
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
58
- }, __VLS_94: {}, __VLS_101: {}, __VLS_116: {}, __VLS_140: {
59
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
60
- }, __VLS_160: {
62
+ item: SelectModelValue | SelectOption<SelectModelValue>;
63
+ }, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_144: {
64
+ item: SelectModelValue | SelectOption<SelectModelValue>;
65
+ }, __VLS_164: {
61
66
  selected: import("./combobox-select.js").ResolvedOption | undefined;
62
- }, __VLS_171: {}, __VLS_178: {}, __VLS_185: {}, __VLS_213: {}, __VLS_216: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {
63
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
64
- }, __VLS_228: {
65
- group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
66
- }, __VLS_231: {}, __VLS_267: string, __VLS_268: {}, __VLS_271: {
67
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
68
- }, __VLS_274: {
69
- group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
67
+ }, __VLS_175: {}, __VLS_182: {}, __VLS_189: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {}, __VLS_228: {}, __VLS_231: {
68
+ item: SelectModelValue | SelectOption<SelectModelValue>;
69
+ }, __VLS_234: {
70
+ group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
71
+ }, __VLS_237: {}, __VLS_273: string, __VLS_274: {}, __VLS_277: {
72
+ item: SelectModelValue | SelectOption<SelectModelValue>;
73
+ }, __VLS_280: {
74
+ group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
70
75
  };
71
76
  type __VLS_Slots = {} & {
72
- [K in NonNullable<typeof __VLS_267>]?: (props: typeof __VLS_268) => any;
77
+ [K in NonNullable<typeof __VLS_273>]?: (props: typeof __VLS_274) => any;
73
78
  } & {
74
79
  item?: (props: typeof __VLS_43) => any;
75
80
  } & {
76
- 'clear-icon'?: (props: typeof __VLS_94) => any;
81
+ 'clear-icon'?: (props: typeof __VLS_98) => any;
77
82
  } & {
78
- 'loading-icon'?: (props: typeof __VLS_101) => any;
83
+ 'loading-icon'?: (props: typeof __VLS_105) => any;
79
84
  } & {
80
- 'dropdown-icon'?: (props: typeof __VLS_116) => any;
85
+ 'dropdown-icon'?: (props: typeof __VLS_120) => any;
81
86
  } & {
82
- item?: (props: typeof __VLS_140) => any;
87
+ item?: (props: typeof __VLS_144) => any;
83
88
  } & {
84
- value?: (props: typeof __VLS_160) => any;
89
+ value?: (props: typeof __VLS_164) => any;
85
90
  } & {
86
- 'clear-icon'?: (props: typeof __VLS_171) => any;
91
+ 'clear-icon'?: (props: typeof __VLS_175) => any;
87
92
  } & {
88
- 'loading-icon'?: (props: typeof __VLS_178) => any;
93
+ 'loading-icon'?: (props: typeof __VLS_182) => any;
89
94
  } & {
90
- 'dropdown-icon'?: (props: typeof __VLS_185) => any;
95
+ 'dropdown-icon'?: (props: typeof __VLS_189) => any;
91
96
  } & {
92
- header?: (props: typeof __VLS_213) => any;
97
+ header?: (props: typeof __VLS_219) => any;
93
98
  } & {
94
- 'filter-icon'?: (props: typeof __VLS_216) => any;
99
+ 'filter-icon'?: (props: typeof __VLS_222) => any;
95
100
  } & {
96
- empty?: (props: typeof __VLS_219) => any;
101
+ empty?: (props: typeof __VLS_225) => any;
97
102
  } & {
98
- 'empty-filter'?: (props: typeof __VLS_222) => any;
103
+ 'empty-filter'?: (props: typeof __VLS_228) => any;
99
104
  } & {
100
- item?: (props: typeof __VLS_225) => any;
105
+ item?: (props: typeof __VLS_231) => any;
101
106
  } & {
102
- group?: (props: typeof __VLS_228) => any;
107
+ group?: (props: typeof __VLS_234) => any;
103
108
  } & {
104
- footer?: (props: typeof __VLS_231) => any;
109
+ footer?: (props: typeof __VLS_237) => any;
105
110
  } & {
106
- item?: (props: typeof __VLS_271) => any;
111
+ item?: (props: typeof __VLS_277) => any;
107
112
  } & {
108
- group?: (props: typeof __VLS_274) => any;
113
+ group?: (props: typeof __VLS_280) => any;
109
114
  };
110
115
  declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
111
- "update:modelValue": (value: string | number | (string | number)[] | undefined) => any;
116
+ "update:modelValue": (value: SelectModelValue | SelectModelValue[] | undefined) => any;
112
117
  "update:open": (value: boolean) => any;
113
118
  "update:searchTerm": (value: string) => any;
114
119
  }, string, import("vue").PublicProps, Readonly<ComboboxSelectBaseProps> & Readonly<{
115
- "onUpdate:modelValue"?: ((value: string | number | (string | number)[] | undefined) => any) | undefined;
120
+ "onUpdate:modelValue"?: ((value: SelectModelValue | SelectModelValue[] | undefined) => any) | undefined;
116
121
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
117
122
  "onUpdate:searchTerm"?: ((value: string) => any) | undefined;
118
123
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -27,7 +27,9 @@ import { useIcons } from "../composables/use-icons";
27
27
  import { useIsMobile } from "../composables/use-media-query";
28
28
  import { useMessages } from "../composables/use-messages";
29
29
  import { selectTheme } from "../theme/select";
30
+ import { arrowContentProps, arrowElementProps } from "../utils/arrow";
30
31
  import { isNativeInputA11yAttr, isNativeInputAttr, isNativeInputEvent } from "../utils/native-input";
32
+ import { overlayPortalProps } from "../utils/overlay";
31
33
  import { resolveRegisteredColorRole } from "../utils/registered-colors";
32
34
  import { resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps, useThemeBindings } from "../utils/ui";
33
35
  import { useComboboxSelect } from "./combobox-select";
@@ -42,8 +44,8 @@ const props = defineProps({
42
44
  labelKey: { type: String, required: false },
43
45
  open: { type: Boolean, required: false },
44
46
  defaultOpen: { type: Boolean, required: false },
45
- modelValue: { type: [String, Number, Array], required: false },
46
- defaultValue: { type: [String, Number, Array], required: false },
47
+ modelValue: { type: [String, Number, Object, Array], required: false },
48
+ defaultValue: { type: [String, Number, Object, Array], required: false },
47
49
  multiple: { type: Boolean, required: false },
48
50
  searchable: { type: Boolean, required: false },
49
51
  virtualize: { type: [Boolean, Object], required: false },
@@ -63,7 +65,9 @@ const props = defineProps({
63
65
  searchTerm: { type: String, required: false },
64
66
  resetSearchTermOnBlur: { type: Boolean, required: false, default: true },
65
67
  resetSearchTermOnSelect: { type: Boolean, required: false, default: true },
66
- arrow: { type: Boolean, required: false, default: false },
68
+ arrow: { type: [Boolean, Object], required: false, default: false },
69
+ positioning: { type: Object, required: false },
70
+ portal: { type: [Boolean, String], required: false, skipCheck: true, default: void 0 },
67
71
  adaptive: { type: Boolean, required: false },
68
72
  ui: { type: Object, required: false }
69
73
  });
@@ -210,11 +214,13 @@ function onTriggerKeydown(event) {
210
214
  }
211
215
  const internalSearchText = ref(props.searchTerm ?? (props.creatable && !props.multiple && props.resetSearchTermOnSelect ? selectedOptions.value[0]?.label ?? "" : ""));
212
216
  const modeSearchLock = ref(false);
217
+ const keyboardNavigatedOptions = ref(false);
213
218
  const searchText = computed({
214
219
  get: () => props.searchTerm ?? internalSearchText.value,
215
220
  set: (value) => {
216
221
  if (modeSearchLock.value)
217
222
  return;
223
+ keyboardNavigatedOptions.value = false;
218
224
  internalSearchText.value = value;
219
225
  emit("update:searchTerm", value);
220
226
  }
@@ -235,23 +241,78 @@ function revertUnmatchedText() {
235
241
  return true;
236
242
  }
237
243
  function onSearchKeydown(event) {
238
- if (event.key !== "Enter" || event.isComposing || isSearchComposing.value || event.keyCode === 229)
244
+ if (event.target !== editableInput.value)
239
245
  return;
246
+ if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key) && !event.isComposing && !isSearchComposing.value) {
247
+ keyboardNavigatedOptions.value = true;
248
+ return;
249
+ }
250
+ if (event.key === "Backspace" && props.creatable && props.multiple && props.displayMode === "comma" && !event.isComposing && !isSearchComposing.value && event.keyCode !== 229 && !searchText.value && !editableInput.value.value && selectedValues.value.length) {
251
+ removeValue(selectedValues.value.at(-1));
252
+ event.preventDefault();
253
+ return;
254
+ }
255
+ if (event.key !== "Enter")
256
+ return;
257
+ if (event.isComposing || isSearchComposing.value || event.keyCode === 229) {
258
+ event.stopPropagation();
259
+ return;
260
+ }
240
261
  if (revertUnmatchedText()) {
241
262
  event.preventDefault();
263
+ event.stopPropagation();
242
264
  return;
243
265
  }
244
- if (commitCreatableText(searchText.value)) {
245
- searchText.value = "";
266
+ if (props.forceSelection)
267
+ return;
268
+ if (props.creatable && !searchText.value.trim()) {
269
+ const activeId2 = editableInput.value?.getAttribute("aria-activedescendant");
270
+ const activeOption2 = activeId2 ? document.getElementById(activeId2) : null;
271
+ if (keyboardNavigatedOptions.value && activeOption2?.getAttribute("aria-selected") === "false")
272
+ return;
273
+ event.stopPropagation();
274
+ return;
275
+ }
276
+ const activeId = editableInput.value?.getAttribute("aria-activedescendant");
277
+ const activeOption = activeId ? document.getElementById(activeId) : null;
278
+ if ((!hasMatchingOption(searchText.value) || !activeOption || activeOption.hasAttribute("data-selaras-create-option")) && commitCreatableText(searchText.value)) {
279
+ if (props.multiple)
280
+ searchText.value = "";
246
281
  event.preventDefault();
282
+ event.stopPropagation();
247
283
  }
248
284
  }
285
+ const pointerInSuggestionContent = ref(false);
286
+ function endSuggestionPointer() {
287
+ pointerInSuggestionContent.value = false;
288
+ window.removeEventListener("pointerup", endSuggestionPointer);
289
+ window.removeEventListener("pointercancel", endSuggestionPointer);
290
+ }
291
+ function startSuggestionPointer() {
292
+ pointerInSuggestionContent.value = true;
293
+ window.addEventListener("pointerup", endSuggestionPointer);
294
+ window.addEventListener("pointercancel", endSuggestionPointer);
295
+ }
296
+ onUnmounted(() => {
297
+ if (typeof window !== "undefined")
298
+ endSuggestionPointer();
299
+ });
249
300
  function onSearchBlur() {
301
+ if (pointerInSuggestionContent.value)
302
+ return;
250
303
  if (revertUnmatchedText())
251
304
  return;
252
- if (commitCreatableText(searchText.value))
305
+ if (props.forceSelection)
306
+ return;
307
+ if (commitCreatableText(searchText.value) && props.multiple)
253
308
  searchText.value = "";
254
309
  }
310
+ function onComboboxValueUpdate(value) {
311
+ setValue(value ?? (props.multiple ? [] : void 0));
312
+ if (props.creatable && props.multiple) {
313
+ searchText.value = "";
314
+ }
315
+ }
255
316
  function onDropdownClick() {
256
317
  searchText.value = "";
257
318
  }
@@ -332,6 +393,11 @@ const field = useFormField();
332
393
  const selectId = computed(() => props.id ?? field?.id);
333
394
  const selectInvalid = computed(() => props.invalid || (field?.invalid.value ?? false));
334
395
  const describedBy = computed(() => field?.describedBy.value);
396
+ const selectedSummaryId = `selaras-autocomplete-selection-${useId()}`;
397
+ const searchDescribedBy = computed(() => [
398
+ describedBy.value,
399
+ props.creatable && props.multiple && props.displayMode === "comma" && selectedOptions.value.length ? selectedSummaryId : void 0
400
+ ].filter(Boolean).join(" ") || void 0);
335
401
  const effectiveSize = computed(() => props.size ?? field?.size ?? "md");
336
402
  const clearSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
337
403
  const icons = useIcons();
@@ -367,8 +433,9 @@ const searchInputProps = computed(() => mergeProps(
367
433
  nativeSearchInputAttrs.value,
368
434
  { onCompositionstart: onSearchCompositionStart, onCompositionend: onSearchCompositionEnd }
369
435
  ));
370
- const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
371
- const arrowProps = computed(() => resolveSlot(ui.value.arrow, props.ui?.arrow));
436
+ const contentProps = computed(() => ({ ...resolveSlot(ui.value.content, props.ui?.content), ...arrowContentProps(props.arrow), ...props.positioning }));
437
+ const portalProps = computed(() => overlayPortalProps(props.portal));
438
+ const arrowProps = computed(() => ({ ...resolveSlot(ui.value.arrow, props.ui?.arrow), ...arrowElementProps(props.arrow) }));
372
439
  const viewportProps = computed(() => resolveSlot(ui.value.viewport, props.ui?.viewport));
373
440
  const groupProps = computed(() => resolveSlot(ui.value.group, props.ui?.group));
374
441
  const itemProps = computed(() => resolveSlot(ui.value.item, props.ui?.item));
@@ -440,6 +507,15 @@ function onModalSelection(value) {
440
507
  if (!props.multiple)
441
508
  updateOpen(false);
442
509
  }
510
+ function serializeFormValue(value) {
511
+ if (typeof value !== "object")
512
+ return String(value);
513
+ try {
514
+ return JSON.stringify(value) ?? "";
515
+ } catch {
516
+ return String(value);
517
+ }
518
+ }
443
519
  const adaptiveUi = computed(() => ({
444
520
  content: {
445
521
  class: "rounded-[var(--selaras-resolved-radius-md)]",
@@ -461,6 +537,9 @@ const adaptiveUi = computed(() => ({
461
537
  const bodyProps = computed(() => ({
462
538
  searchable: props.searchable,
463
539
  creatable: props.creatable,
540
+ multiple: props.multiple,
541
+ forceSelection: props.forceSelection,
542
+ selectedValues: selectedValues.value,
464
543
  searchText: searchText.value,
465
544
  displayValue,
466
545
  items: props.items,
@@ -488,13 +567,13 @@ const bodyProps = computed(() => ({
488
567
  :model-value="rekaSelection"
489
568
  :multiple="multiple"
490
569
  :disabled="disabled"
491
- :ignore-filter="!searchable"
570
+ :ignore-filter="!searchable || creatable && multiple"
492
571
  :reset-search-term-on-blur="resetSearchTermOnBlur"
493
572
  :reset-search-term-on-select="resetSearchTermOnSelect"
494
573
  :data-selaras-color="colorRoleMarker"
495
574
  v-bind="rootProps"
496
575
  @update:open="updateOpen($event)"
497
- @update:model-value="(value2) => setValue(value2 == null ? multiple ? [] : void 0 : value2)"
576
+ @update:model-value="(value2) => onComboboxValueUpdate(value2)"
498
577
  >
499
578
  <ComboboxAnchor>
500
579
  <!--
@@ -506,7 +585,10 @@ const bodyProps = computed(() => ({
506
585
  <div
507
586
  v-if="creatable"
508
587
  data-ui-group-item
588
+ :data-selaras-field-filled="selectedValues.length ? '' : void 0"
589
+ :data-selaras-field-active="open ? '' : void 0"
509
590
  v-bind="triggerProps"
591
+ @keydown.capture="onSearchKeydown"
510
592
  >
511
593
  <!--
512
594
  TagsInputRoot doesn't own selection truth here - it only reads
@@ -535,7 +617,7 @@ const bodyProps = computed(() => ({
535
617
  -->
536
618
  <TagsInputItem
537
619
  v-for="option in visibleOptions"
538
- :key="option.value"
620
+ :key="option.key"
539
621
  :value="option.value"
540
622
  as-child
541
623
  >
@@ -547,7 +629,7 @@ const bodyProps = computed(() => ({
547
629
  :ui="{ root: 'data-[state=active]:ring-2 data-[state=active]:ring-[var(--_selaras-color-fill)]' }"
548
630
  >
549
631
  <TagsInputItemText as="span">
550
- <slot v-if="option.raw" name="item" :item="option.raw">
632
+ <slot v-if="option.raw !== void 0" name="item" :item="option.raw">
551
633
  {{ option.label }}
552
634
  </slot>
553
635
  <template v-else>
@@ -561,6 +643,9 @@ const bodyProps = computed(() => ({
561
643
  </template>
562
644
  </Chip>
563
645
  </TagsInputItem>
646
+ <Tooltip v-if="overflowOptions.length" :text="overflowOptions.map((o) => o.label).join(', ')">
647
+ <span v-bind="chipOverflowProps">{{ messages.moreItems(overflowOptions.length) }}</span>
648
+ </Tooltip>
564
649
  <ComboboxInput v-model="searchText" as-child>
565
650
  <TagsInputInput
566
651
  :id="selectId"
@@ -568,31 +653,35 @@ const bodyProps = computed(() => ({
568
653
  :display-value="displayValue"
569
654
  :placeholder="placeholder"
570
655
  :aria-invalid="selectInvalid || void 0"
571
- :aria-describedby="describedBy"
656
+ :aria-describedby="searchDescribedBy"
572
657
  :aria-busy="loading || void 0"
573
658
  v-bind="searchInputProps"
574
- @keydown="onSearchKeydown"
575
659
  @blur="onSearchBlur"
576
660
  />
577
661
  </ComboboxInput>
578
662
  </TagsInputRoot>
663
+ <span v-if="multiple && displayMode === 'comma' && selectedOptions.length" :id="selectedSummaryId" class="sr-only">
664
+ {{ selectedOptions.map((o) => o.label).join(", ") }}
665
+ </span>
666
+ <span v-if="multiple && displayMode === 'comma' && selectedOptions.length" aria-hidden="true" v-bind="commaValueProps">
667
+ {{ commaText }}
668
+ </span>
669
+ <Tooltip v-if="multiple && displayMode === 'comma' && overflowOptions.length" :text="overflowOptions.map((o) => o.label).join(', ')">
670
+ <span v-bind="chipOverflowProps">{{ messages.moreItems(overflowOptions.length) }}</span>
671
+ </Tooltip>
579
672
  <ComboboxInput
580
- v-else
673
+ v-if="!(multiple && displayMode === 'chip')"
581
674
  :id="selectId"
582
675
  :ref="setEditableInput"
583
676
  v-model="searchText"
584
677
  :display-value="displayValue"
585
- :placeholder="placeholder"
678
+ :placeholder="multiple && displayMode === 'comma' && selectedOptions.length ? void 0 : placeholder"
586
679
  :aria-invalid="selectInvalid || void 0"
587
- :aria-describedby="describedBy"
680
+ :aria-describedby="searchDescribedBy"
588
681
  :aria-busy="loading || void 0"
589
682
  v-bind="searchInputProps"
590
- @keydown="onSearchKeydown"
591
683
  @blur="onSearchBlur"
592
684
  />
593
- <Tooltip v-if="overflowOptions.length" :text="overflowOptions.map((o) => o.label).join(', ')">
594
- <span v-bind="chipOverflowProps">{{ messages.moreItems(overflowOptions.length) }}</span>
595
- </Tooltip>
596
685
  <!--
597
686
  A plain Button, not ComboboxCancel as-child - this trigger is a
598
687
  <div>, so unlike the non-creatable branch below there's no real
@@ -635,6 +724,8 @@ const bodyProps = computed(() => ({
635
724
  :id="selectId"
636
725
  ref="selectTrigger"
637
726
  data-ui-group-item
727
+ :data-selaras-field-filled="selectedValues.length ? '' : void 0"
728
+ :data-selaras-field-active="open ? '' : void 0"
638
729
  :aria-invalid="selectInvalid || void 0"
639
730
  :aria-describedby="describedBy"
640
731
  :aria-busy="loading || void 0"
@@ -654,7 +745,7 @@ const bodyProps = computed(() => ({
654
745
  <div v-if="displayMode === 'chip'" class="flex flex-1 flex-wrap items-center gap-1.5">
655
746
  <Chip
656
747
  v-for="option in visibleOptions"
657
- :key="option.value"
748
+ :key="option.key"
658
749
  size="sm"
659
750
  color="primary"
660
751
  variant="soft"
@@ -663,7 +754,7 @@ const bodyProps = computed(() => ({
663
754
  :aria-current="option.value === selectedChipValue || void 0"
664
755
  :ui="{ root: 'data-[state=active]:ring-2 data-[state=active]:ring-[var(--_selaras-color-fill)]' }"
665
756
  >
666
- <slot v-if="option.raw" name="item" :item="option.raw">
757
+ <slot v-if="option.raw !== void 0" name="item" :item="option.raw">
667
758
  {{ option.label }}
668
759
  </slot>
669
760
  <template v-else>
@@ -740,11 +831,13 @@ const bodyProps = computed(() => ({
740
831
  </ComboboxTrigger>
741
832
  </ComboboxAnchor>
742
833
 
743
- <ComboboxPortal v-if="!showMobileSelectModal">
834
+ <ComboboxPortal v-if="!showMobileSelectModal" v-bind="portalProps">
744
835
  <ComboboxContent
745
836
  position="popper" :side-offset="4"
837
+ :hide-when-empty="creatable && !multiple && !forceSelection"
746
838
  :data-selaras-theme="themeBindings['data-selaras-theme']" :data-selaras-mode="themeBindings['data-selaras-mode']" :style="themeBindings.style" :data-selaras-color="colorRoleMarker"
747
839
  v-bind="showMobileAutocompletePanel ? mergeProps(contentProps, mobilePanelProps) : contentProps"
840
+ @pointerdown.capture="startSuggestionPointer"
748
841
  >
749
842
  <ComboboxSelectBody v-bind="bodyProps" @update:search-text="searchText = $event">
750
843
  <template #header>
@@ -829,7 +922,7 @@ const bodyProps = computed(() => ({
829
922
  type="hidden"
830
923
  :name="name ?? field?.name"
831
924
  :form="form"
832
- :value="String(value)"
925
+ :value="serializeFormValue(value)"
833
926
  :disabled="disabled"
834
927
  :required="required && !disabled && index === 0"
835
928
  >
@@ -1,6 +1,9 @@
1
1
  import type { VariantProps } from 'tailwind-variants';
2
2
  import type { SelectThemeSlots } from '../theme/select.js';
3
+ import type { RoundedArrowConfig } from '../utils/arrow.js';
3
4
  import type { ColorRole } from '../utils/color-registry.js';
5
+ import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
6
+ import type { SelectModelValue } from '../utils/select-contracts.js';
4
7
  import type { UiProp } from '../utils/ui.js';
5
8
  import type { SelectItems, SelectOption } from './combobox-select.js';
6
9
  import { selectTheme } from '../theme/select.js';
@@ -16,9 +19,9 @@ export interface ComboboxSelectBaseProps {
16
19
  open?: boolean;
17
20
  /** Initial uncontrolled open state. */
18
21
  defaultOpen?: boolean;
19
- modelValue?: string | number | (string | number)[];
22
+ modelValue?: SelectModelValue | SelectModelValue[];
20
23
  /** Initial uncontrolled selection and native form reset target. */
21
- defaultValue?: string | number | (string | number)[];
24
+ defaultValue?: SelectModelValue | SelectModelValue[];
22
25
  multiple?: boolean;
23
26
  searchable?: boolean;
24
27
  virtualize?: boolean | {
@@ -43,76 +46,78 @@ export interface ComboboxSelectBaseProps {
43
46
  resetSearchTermOnBlur?: boolean;
44
47
  resetSearchTermOnSelect?: boolean;
45
48
  /** Shows a small pointer triangle connecting the panel to its trigger. */
46
- arrow?: boolean;
49
+ arrow?: boolean | RoundedArrowConfig;
50
+ positioning?: OverlayPositioning;
51
+ portal?: OverlayPortal;
47
52
  /** Opts into the component's accessible small-screen presentation. */
48
53
  adaptive?: boolean;
49
54
  ui?: UiProp<SelectThemeSlots>;
50
55
  }
51
56
  export interface ComboboxSelectBaseEmits {
52
57
  'update:open': [value: boolean];
53
- 'update:modelValue': [value: string | number | (string | number)[] | undefined];
58
+ 'update:modelValue': [value: SelectModelValue | SelectModelValue[] | undefined];
54
59
  'update:searchTerm': [value: string];
55
60
  }
56
61
  declare var __VLS_43: {
57
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
58
- }, __VLS_94: {}, __VLS_101: {}, __VLS_116: {}, __VLS_140: {
59
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
60
- }, __VLS_160: {
62
+ item: SelectModelValue | SelectOption<SelectModelValue>;
63
+ }, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_144: {
64
+ item: SelectModelValue | SelectOption<SelectModelValue>;
65
+ }, __VLS_164: {
61
66
  selected: import("./combobox-select.js").ResolvedOption | undefined;
62
- }, __VLS_171: {}, __VLS_178: {}, __VLS_185: {}, __VLS_213: {}, __VLS_216: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {
63
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
64
- }, __VLS_228: {
65
- group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
66
- }, __VLS_231: {}, __VLS_267: string, __VLS_268: {}, __VLS_271: {
67
- item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
68
- }, __VLS_274: {
69
- group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
67
+ }, __VLS_175: {}, __VLS_182: {}, __VLS_189: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {}, __VLS_228: {}, __VLS_231: {
68
+ item: SelectModelValue | SelectOption<SelectModelValue>;
69
+ }, __VLS_234: {
70
+ group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
71
+ }, __VLS_237: {}, __VLS_273: string, __VLS_274: {}, __VLS_277: {
72
+ item: SelectModelValue | SelectOption<SelectModelValue>;
73
+ }, __VLS_280: {
74
+ group: import("./combobox-select.js").SelectOptionGroup<SelectModelValue>;
70
75
  };
71
76
  type __VLS_Slots = {} & {
72
- [K in NonNullable<typeof __VLS_267>]?: (props: typeof __VLS_268) => any;
77
+ [K in NonNullable<typeof __VLS_273>]?: (props: typeof __VLS_274) => any;
73
78
  } & {
74
79
  item?: (props: typeof __VLS_43) => any;
75
80
  } & {
76
- 'clear-icon'?: (props: typeof __VLS_94) => any;
81
+ 'clear-icon'?: (props: typeof __VLS_98) => any;
77
82
  } & {
78
- 'loading-icon'?: (props: typeof __VLS_101) => any;
83
+ 'loading-icon'?: (props: typeof __VLS_105) => any;
79
84
  } & {
80
- 'dropdown-icon'?: (props: typeof __VLS_116) => any;
85
+ 'dropdown-icon'?: (props: typeof __VLS_120) => any;
81
86
  } & {
82
- item?: (props: typeof __VLS_140) => any;
87
+ item?: (props: typeof __VLS_144) => any;
83
88
  } & {
84
- value?: (props: typeof __VLS_160) => any;
89
+ value?: (props: typeof __VLS_164) => any;
85
90
  } & {
86
- 'clear-icon'?: (props: typeof __VLS_171) => any;
91
+ 'clear-icon'?: (props: typeof __VLS_175) => any;
87
92
  } & {
88
- 'loading-icon'?: (props: typeof __VLS_178) => any;
93
+ 'loading-icon'?: (props: typeof __VLS_182) => any;
89
94
  } & {
90
- 'dropdown-icon'?: (props: typeof __VLS_185) => any;
95
+ 'dropdown-icon'?: (props: typeof __VLS_189) => any;
91
96
  } & {
92
- header?: (props: typeof __VLS_213) => any;
97
+ header?: (props: typeof __VLS_219) => any;
93
98
  } & {
94
- 'filter-icon'?: (props: typeof __VLS_216) => any;
99
+ 'filter-icon'?: (props: typeof __VLS_222) => any;
95
100
  } & {
96
- empty?: (props: typeof __VLS_219) => any;
101
+ empty?: (props: typeof __VLS_225) => any;
97
102
  } & {
98
- 'empty-filter'?: (props: typeof __VLS_222) => any;
103
+ 'empty-filter'?: (props: typeof __VLS_228) => any;
99
104
  } & {
100
- item?: (props: typeof __VLS_225) => any;
105
+ item?: (props: typeof __VLS_231) => any;
101
106
  } & {
102
- group?: (props: typeof __VLS_228) => any;
107
+ group?: (props: typeof __VLS_234) => any;
103
108
  } & {
104
- footer?: (props: typeof __VLS_231) => any;
109
+ footer?: (props: typeof __VLS_237) => any;
105
110
  } & {
106
- item?: (props: typeof __VLS_271) => any;
111
+ item?: (props: typeof __VLS_277) => any;
107
112
  } & {
108
- group?: (props: typeof __VLS_274) => any;
113
+ group?: (props: typeof __VLS_280) => any;
109
114
  };
110
115
  declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
111
- "update:modelValue": (value: string | number | (string | number)[] | undefined) => any;
116
+ "update:modelValue": (value: SelectModelValue | SelectModelValue[] | undefined) => any;
112
117
  "update:open": (value: boolean) => any;
113
118
  "update:searchTerm": (value: string) => any;
114
119
  }, string, import("vue").PublicProps, Readonly<ComboboxSelectBaseProps> & Readonly<{
115
- "onUpdate:modelValue"?: ((value: string | number | (string | number)[] | undefined) => any) | undefined;
120
+ "onUpdate:modelValue"?: ((value: SelectModelValue | SelectModelValue[] | undefined) => any) | undefined;
116
121
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
117
122
  "onUpdate:searchTerm"?: ((value: string) => any) | undefined;
118
123
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;