@sewadah/selaras 0.2.0 → 0.3.1

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 (176) hide show
  1. package/README.md +36 -7
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +31 -15
  4. package/dist/runtime/components/Autocomplete.vue +3 -1
  5. package/dist/runtime/components/Badge.d.vue.ts +1 -1
  6. package/dist/runtime/components/Badge.vue.d.ts +1 -1
  7. package/dist/runtime/components/Calendar.d.vue.ts +69 -0
  8. package/dist/runtime/components/Calendar.vue +163 -0
  9. package/dist/runtime/components/Calendar.vue.d.ts +69 -0
  10. package/dist/runtime/components/Callout.vue +12 -1
  11. package/dist/runtime/components/CodeGroup.vue +13 -3
  12. package/dist/runtime/components/CodeTree.d.vue.ts +2 -0
  13. package/dist/runtime/components/CodeTree.vue +52 -1
  14. package/dist/runtime/components/CodeTree.vue.d.ts +2 -0
  15. package/dist/runtime/components/ColorPicker.d.vue.ts +8 -0
  16. package/dist/runtime/components/ColorPicker.vue +66 -45
  17. package/dist/runtime/components/ColorPicker.vue.d.ts +8 -0
  18. package/dist/runtime/components/Column.js +1 -1
  19. package/dist/runtime/components/CommandPalette.d.vue.ts +3 -1
  20. package/dist/runtime/components/CommandPalette.vue +5 -0
  21. package/dist/runtime/components/CommandPalette.vue.d.ts +3 -1
  22. package/dist/runtime/components/ContentNavigation.d.vue.ts +8 -1
  23. package/dist/runtime/components/ContentNavigation.vue +9 -2
  24. package/dist/runtime/components/ContentNavigation.vue.d.ts +8 -1
  25. package/dist/runtime/components/ContentToc.vue +14 -7
  26. package/dist/runtime/components/ContextMenu.d.vue.ts +8 -1
  27. package/dist/runtime/components/ContextMenu.vue +16 -4
  28. package/dist/runtime/components/ContextMenu.vue.d.ts +8 -1
  29. package/dist/runtime/components/DatePicker.d.vue.ts +10 -3
  30. package/dist/runtime/components/DatePicker.vue +24 -16
  31. package/dist/runtime/components/DatePicker.vue.d.ts +10 -3
  32. package/dist/runtime/components/Dropdown.d.vue.ts +33 -6
  33. package/dist/runtime/components/Dropdown.vue +143 -11
  34. package/dist/runtime/components/Dropdown.vue.d.ts +33 -6
  35. package/dist/runtime/components/FileTree.d.vue.ts +2 -0
  36. package/dist/runtime/components/FileTree.vue +8 -4
  37. package/dist/runtime/components/FileTree.vue.d.ts +2 -0
  38. package/dist/runtime/components/FileUpload.vue +1 -1
  39. package/dist/runtime/components/FormField.d.vue.ts +4 -0
  40. package/dist/runtime/components/FormField.vue +19 -4
  41. package/dist/runtime/components/FormField.vue.d.ts +4 -0
  42. package/dist/runtime/components/Input.vue +3 -2
  43. package/dist/runtime/components/Kbd.vue +12 -2
  44. package/dist/runtime/components/NavigationMenu.d.vue.ts +10 -10
  45. package/dist/runtime/components/NavigationMenu.vue +13 -7
  46. package/dist/runtime/components/NavigationMenu.vue.d.ts +10 -10
  47. package/dist/runtime/components/NavigationMenuAccordionItem.vue +5 -1
  48. package/dist/runtime/components/NavigationMenuFlyoutList.vue +7 -4
  49. package/dist/runtime/components/PinInput.vue +1 -1
  50. package/dist/runtime/components/Popover.d.vue.ts +8 -2
  51. package/dist/runtime/components/Popover.vue +9 -4
  52. package/dist/runtime/components/Popover.vue.d.ts +8 -2
  53. package/dist/runtime/components/ProsePre.d.vue.ts +6 -2
  54. package/dist/runtime/components/ProsePre.vue +11 -4
  55. package/dist/runtime/components/ProsePre.vue.d.ts +6 -2
  56. package/dist/runtime/components/Select.vue +3 -1
  57. package/dist/runtime/components/SplitterPanel.d.vue.ts +2 -2
  58. package/dist/runtime/components/SplitterPanel.vue.d.ts +2 -2
  59. package/dist/runtime/components/Table.vue +95 -26
  60. package/dist/runtime/components/Tabs.d.vue.ts +44 -4
  61. package/dist/runtime/components/Tabs.vue +171 -18
  62. package/dist/runtime/components/Tabs.vue.d.ts +44 -4
  63. package/dist/runtime/components/Textarea.vue +3 -2
  64. package/dist/runtime/components/Timeline.d.vue.ts +19 -0
  65. package/dist/runtime/components/Timeline.vue +99 -0
  66. package/dist/runtime/components/Timeline.vue.d.ts +19 -0
  67. package/dist/runtime/components/Toast.d.vue.ts +10 -1
  68. package/dist/runtime/components/Toast.vue +94 -8
  69. package/dist/runtime/components/Toast.vue.d.ts +10 -1
  70. package/dist/runtime/components/Tooltip.d.vue.ts +8 -2
  71. package/dist/runtime/components/Tooltip.vue +9 -4
  72. package/dist/runtime/components/Tooltip.vue.d.ts +8 -2
  73. package/dist/runtime/composables/use-form-field.d.ts +1 -0
  74. package/dist/runtime/composables/use-table.d.ts +3 -0
  75. package/dist/runtime/composables/use-table.js +10 -4
  76. package/dist/runtime/composables/use-toast.js +5 -1
  77. package/dist/runtime/default-colors.css +1 -1
  78. package/dist/runtime/directives/hotkey.d.ts +13 -0
  79. package/dist/runtime/directives/hotkey.js +107 -0
  80. package/dist/runtime/directives/index.d.ts +2 -0
  81. package/dist/runtime/directives/index.js +2 -0
  82. package/dist/runtime/directives/mask.d.ts +30 -0
  83. package/dist/runtime/directives/mask.js +165 -0
  84. package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +29 -25
  85. package/dist/runtime/internal/ComboboxSelectBase.vue +104 -20
  86. package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +29 -25
  87. package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +16 -11
  88. package/dist/runtime/internal/ComboboxSelectBody.vue +49 -10
  89. package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +16 -11
  90. package/dist/runtime/internal/DatePickerCalendarBody.vue +1 -1
  91. package/dist/runtime/internal/DatePickerRangeCalendarBody.vue +1 -1
  92. package/dist/runtime/internal/ShortcutHint.d.vue.ts +6 -0
  93. package/dist/runtime/internal/ShortcutHint.vue +13 -0
  94. package/dist/runtime/internal/ShortcutHint.vue.d.ts +6 -0
  95. package/dist/runtime/internal/ToastItemRenderer.d.vue.ts +9 -1
  96. package/dist/runtime/internal/ToastItemRenderer.vue +55 -8
  97. package/dist/runtime/internal/ToastItemRenderer.vue.d.ts +9 -1
  98. package/dist/runtime/internal/combobox-select.js +2 -1
  99. package/dist/runtime/internal/programmatic-services.d.ts +2 -0
  100. package/dist/runtime/internal/programmatic-services.js +8 -0
  101. package/dist/runtime/internal/toast-stack.d.ts +36 -0
  102. package/dist/runtime/internal/toast-stack.js +36 -0
  103. package/dist/runtime/structural.css +1 -1
  104. package/dist/runtime/table.d.ts +1 -1
  105. package/dist/runtime/theme/alert-dialog.js +1 -1
  106. package/dist/runtime/theme/avatar.js +7 -7
  107. package/dist/runtime/theme/badge.js +2 -2
  108. package/dist/runtime/theme/calendar.d.ts +86 -0
  109. package/dist/runtime/theme/calendar.js +19 -0
  110. package/dist/runtime/theme/callout.d.ts +0 -12
  111. package/dist/runtime/theme/callout.js +8 -8
  112. package/dist/runtime/theme/checkbox.js +1 -1
  113. package/dist/runtime/theme/code-tree.js +1 -1
  114. package/dist/runtime/theme/command-palette.js +1 -1
  115. package/dist/runtime/theme/content-navigation.d.ts +3 -0
  116. package/dist/runtime/theme/content-navigation.js +1 -0
  117. package/dist/runtime/theme/date-picker.js +1 -1
  118. package/dist/runtime/theme/drawer.js +1 -1
  119. package/dist/runtime/theme/dropdown.d.ts +21 -0
  120. package/dist/runtime/theme/dropdown.js +15 -2
  121. package/dist/runtime/theme/file-tree.js +1 -1
  122. package/dist/runtime/theme/file-upload.js +2 -2
  123. package/dist/runtime/theme/form-field.d.ts +18 -0
  124. package/dist/runtime/theme/form-field.js +6 -1
  125. package/dist/runtime/theme/icon.js +1 -1
  126. package/dist/runtime/theme/input-number.js +1 -1
  127. package/dist/runtime/theme/input.js +1 -1
  128. package/dist/runtime/theme/modal.js +1 -1
  129. package/dist/runtime/theme/pin-input.js +1 -1
  130. package/dist/runtime/theme/progress.js +2 -2
  131. package/dist/runtime/theme/prose.d.ts +6 -0
  132. package/dist/runtime/theme/prose.js +2 -0
  133. package/dist/runtime/theme/radio-group.js +4 -4
  134. package/dist/runtime/theme/rating.js +1 -1
  135. package/dist/runtime/theme/select.js +2 -2
  136. package/dist/runtime/theme/separator.js +1 -1
  137. package/dist/runtime/theme/slideover.js +1 -1
  138. package/dist/runtime/theme/slider.js +2 -2
  139. package/dist/runtime/theme/splitter-resize-handle.js +1 -1
  140. package/dist/runtime/theme/switch.js +1 -1
  141. package/dist/runtime/theme/table.d.ts +27 -0
  142. package/dist/runtime/theme/table.js +11 -2
  143. package/dist/runtime/theme/tabs.d.ts +87 -3
  144. package/dist/runtime/theme/tabs.js +46 -22
  145. package/dist/runtime/theme/textarea.js +1 -1
  146. package/dist/runtime/theme/timeline.d.ts +251 -0
  147. package/dist/runtime/theme/timeline.js +84 -0
  148. package/dist/runtime/theme/toast.d.ts +92 -0
  149. package/dist/runtime/theme/toast.js +29 -7
  150. package/dist/runtime/theme-config.d.ts +12 -1
  151. package/dist/runtime/types/index.d.ts +6 -1
  152. package/dist/runtime/utils/arrow.d.ts +21 -0
  153. package/dist/runtime/utils/arrow.js +10 -0
  154. package/dist/runtime/utils/color-registry.d.ts +3 -1
  155. package/dist/runtime/utils/color-registry.js +4 -0
  156. package/dist/runtime/utils/file-icons.d.ts +8 -0
  157. package/dist/runtime/utils/file-icons.js +133 -0
  158. package/dist/runtime/utils/functional-tokens.d.ts +1 -1
  159. package/dist/runtime/utils/functional-tokens.js +1 -1
  160. package/dist/runtime/utils/icons.d.ts +2 -0
  161. package/dist/runtime/utils/icons.js +2 -0
  162. package/dist/runtime/utils/messages.d.ts +6 -0
  163. package/dist/runtime/utils/messages.js +6 -0
  164. package/dist/runtime/utils/navigation-menu.d.ts +10 -0
  165. package/dist/runtime/utils/navigation-menu.js +3 -0
  166. package/dist/runtime/utils/overlay.d.ts +17 -0
  167. package/dist/runtime/utils/overlay.js +7 -0
  168. package/dist/runtime/utils/seed-colors.d.ts +2 -1
  169. package/dist/runtime/utils/seed-colors.js +24 -16
  170. package/dist/runtime/utils/select-contracts.d.ts +7 -1
  171. package/dist/runtime/utils/table-columns.js +1 -1
  172. package/dist/runtime/utils/table-contracts.d.ts +9 -1
  173. package/dist/runtime/utils/timeline-contracts.d.ts +42 -0
  174. package/dist/runtime/utils/timeline-contracts.js +0 -0
  175. package/dist/tokens/default-colors.tokens.json +100 -100
  176. package/package.json +21 -9
@@ -0,0 +1,165 @@
1
+ const defaultMaskTokens = {
2
+ "#": { pattern: /\d/ },
3
+ "@": { pattern: /[a-z]/i },
4
+ "*": { pattern: /[\da-z]/i }
5
+ };
6
+ function formatMask(input, mask, tokens = defaultMaskTokens, raw = true) {
7
+ let masked = "";
8
+ let unmasked = "";
9
+ let inputIndex = 0;
10
+ let maskIndex = 0;
11
+ let skipped = 0;
12
+ const slotEnds = [];
13
+ while (maskIndex < mask.length && inputIndex < input.length) {
14
+ const maskChar = mask[maskIndex];
15
+ const token = tokens[maskChar];
16
+ const char = input[inputIndex];
17
+ if (token) {
18
+ if (token.pattern.test(char)) {
19
+ const accepted = token.transform ? token.transform(char) : char;
20
+ masked += accepted;
21
+ unmasked += accepted;
22
+ slotEnds.push(masked.length);
23
+ maskIndex++;
24
+ } else {
25
+ skipped++;
26
+ }
27
+ inputIndex++;
28
+ } else {
29
+ masked += maskChar;
30
+ if (!raw && char === maskChar && inputIndex - skipped === maskIndex)
31
+ inputIndex++;
32
+ maskIndex++;
33
+ }
34
+ }
35
+ let slotCount = 0;
36
+ for (const char of mask) {
37
+ if (tokens[char])
38
+ slotCount++;
39
+ }
40
+ return { masked, unmasked, completed: slotEnds.length === slotCount, slotEnds };
41
+ }
42
+ const states = /* @__PURE__ */ new WeakMap();
43
+ let nativeDescriptor;
44
+ function nativeValue() {
45
+ return nativeDescriptor ??= Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
46
+ }
47
+ function readNative(input) {
48
+ return nativeValue().get.call(input);
49
+ }
50
+ function writeNative(input, value) {
51
+ if (readNative(input) !== value)
52
+ nativeValue().set.call(input, value);
53
+ }
54
+ function resolveInput(element) {
55
+ if (element instanceof HTMLInputElement)
56
+ return element;
57
+ return element.querySelector("input") ?? void 0;
58
+ }
59
+ function normalize(value) {
60
+ if (!value)
61
+ return void 0;
62
+ return typeof value === "string" ? { mask: value } : value.mask ? value : void 0;
63
+ }
64
+ function resolveTokens(options) {
65
+ return options.tokens ? { ...defaultMaskTokens, ...options.tokens } : defaultMaskTokens;
66
+ }
67
+ function commit(state, result) {
68
+ state.masked = result.masked;
69
+ state.unmasked = result.unmasked;
70
+ writeNative(state.input, result.masked);
71
+ if (state.reported === result.masked)
72
+ return;
73
+ state.reported = result.masked;
74
+ const detail = { value: result.unmasked, maskedValue: result.masked, completed: result.completed };
75
+ state.onMask?.(detail);
76
+ state.input.dispatchEvent(new CustomEvent("mask", { bubbles: true, detail }));
77
+ }
78
+ function handleInput(state, event) {
79
+ if (event.isComposing)
80
+ return;
81
+ const { input, mask, tokens } = state;
82
+ const current = readNative(input);
83
+ const caret = input.selectionStart ?? current.length;
84
+ const result = formatMask(current, mask, tokens, false);
85
+ const inputType = event.inputType ?? "";
86
+ if (inputType.startsWith("delete"))
87
+ result.masked = result.masked.slice(0, result.slotEnds.at(-1) ?? 0);
88
+ const position = Math.min(formatMask(current.slice(0, caret), mask, tokens, false).masked.length, result.masked.length);
89
+ commit(state, result);
90
+ if (document.activeElement === input)
91
+ input.setSelectionRange(position, position);
92
+ }
93
+ function install(element, input, options) {
94
+ const state = {
95
+ input,
96
+ mask: options.mask,
97
+ tokens: resolveTokens(options),
98
+ onMask: options.onMask,
99
+ masked: "",
100
+ unmasked: "",
101
+ onInput: (event) => handleInput(state, event)
102
+ };
103
+ Object.defineProperty(input, "value", {
104
+ configurable: true,
105
+ enumerable: nativeValue().enumerable,
106
+ get: () => {
107
+ const current = readNative(input);
108
+ return current === state.masked ? state.unmasked : formatMask(current, state.mask, state.tokens, false).unmasked;
109
+ },
110
+ set: (value) => {
111
+ commit(state, formatMask(value == null ? "" : String(value), state.mask, state.tokens));
112
+ }
113
+ });
114
+ input.addEventListener("input", state.onInput, true);
115
+ states.set(element, state);
116
+ commit(state, formatMask(readNative(input), state.mask, state.tokens));
117
+ }
118
+ function uninstall(element, state) {
119
+ state.input.removeEventListener("input", state.onInput, true);
120
+ Reflect.deleteProperty(state.input, "value");
121
+ states.delete(element);
122
+ }
123
+ function apply(element, value) {
124
+ const options = normalize(value);
125
+ const input = resolveInput(element);
126
+ const state = states.get(element);
127
+ if (state && (!options || state.input !== input))
128
+ uninstall(element, state);
129
+ if (!options || !input)
130
+ return;
131
+ const existing = states.get(element);
132
+ if (!existing) {
133
+ install(element, input, options);
134
+ return;
135
+ }
136
+ existing.onMask = options.onMask;
137
+ const tokens = resolveTokens(options);
138
+ if (existing.mask === options.mask && sameTokens(existing.tokens, tokens))
139
+ return;
140
+ existing.mask = options.mask;
141
+ existing.tokens = tokens;
142
+ commit(existing, formatMask(existing.unmasked, existing.mask, existing.tokens));
143
+ }
144
+ function sameTokens(left, right) {
145
+ if (left === right)
146
+ return true;
147
+ const keys = Object.keys(left);
148
+ return keys.length === Object.keys(right).length && keys.every((key) => right[key] && String(left[key].pattern) === String(right[key].pattern));
149
+ }
150
+ export const vMask = {
151
+ getSSRProps() {
152
+ return void 0;
153
+ },
154
+ mounted(element, binding) {
155
+ apply(element, binding.value);
156
+ },
157
+ updated(element, binding) {
158
+ apply(element, binding.value);
159
+ },
160
+ beforeUnmount(element) {
161
+ const state = states.get(element);
162
+ if (state)
163
+ uninstall(element, state);
164
+ }
165
+ };
@@ -1,6 +1,8 @@
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';
4
6
  import type { UiProp } from '../utils/ui.js';
5
7
  import type { SelectItems, SelectOption } from './combobox-select.js';
6
8
  import { selectTheme } from '../theme/select.js';
@@ -43,7 +45,9 @@ export interface ComboboxSelectBaseProps {
43
45
  resetSearchTermOnBlur?: boolean;
44
46
  resetSearchTermOnSelect?: boolean;
45
47
  /** Shows a small pointer triangle connecting the panel to its trigger. */
46
- arrow?: boolean;
48
+ arrow?: boolean | RoundedArrowConfig;
49
+ positioning?: OverlayPositioning;
50
+ portal?: OverlayPortal;
47
51
  /** Opts into the component's accessible small-screen presentation. */
48
52
  adaptive?: boolean;
49
53
  ui?: UiProp<SelectThemeSlots>;
@@ -55,57 +59,57 @@ export interface ComboboxSelectBaseEmits {
55
59
  }
56
60
  declare var __VLS_43: {
57
61
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
58
- }, __VLS_94: {}, __VLS_101: {}, __VLS_116: {}, __VLS_140: {
62
+ }, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_144: {
59
63
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
60
- }, __VLS_160: {
64
+ }, __VLS_164: {
61
65
  selected: import("./combobox-select.js").ResolvedOption | undefined;
62
- }, __VLS_171: {}, __VLS_178: {}, __VLS_185: {}, __VLS_213: {}, __VLS_216: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {
66
+ }, __VLS_175: {}, __VLS_182: {}, __VLS_189: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {}, __VLS_228: {}, __VLS_231: {
63
67
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
64
- }, __VLS_228: {
68
+ }, __VLS_234: {
65
69
  group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
66
- }, __VLS_231: {}, __VLS_267: string, __VLS_268: {}, __VLS_271: {
70
+ }, __VLS_237: {}, __VLS_273: string, __VLS_274: {}, __VLS_277: {
67
71
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
68
- }, __VLS_274: {
72
+ }, __VLS_280: {
69
73
  group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
70
74
  };
71
75
  type __VLS_Slots = {} & {
72
- [K in NonNullable<typeof __VLS_267>]?: (props: typeof __VLS_268) => any;
76
+ [K in NonNullable<typeof __VLS_273>]?: (props: typeof __VLS_274) => any;
73
77
  } & {
74
78
  item?: (props: typeof __VLS_43) => any;
75
79
  } & {
76
- 'clear-icon'?: (props: typeof __VLS_94) => any;
80
+ 'clear-icon'?: (props: typeof __VLS_98) => any;
77
81
  } & {
78
- 'loading-icon'?: (props: typeof __VLS_101) => any;
82
+ 'loading-icon'?: (props: typeof __VLS_105) => any;
79
83
  } & {
80
- 'dropdown-icon'?: (props: typeof __VLS_116) => any;
84
+ 'dropdown-icon'?: (props: typeof __VLS_120) => any;
81
85
  } & {
82
- item?: (props: typeof __VLS_140) => any;
86
+ item?: (props: typeof __VLS_144) => any;
83
87
  } & {
84
- value?: (props: typeof __VLS_160) => any;
88
+ value?: (props: typeof __VLS_164) => any;
85
89
  } & {
86
- 'clear-icon'?: (props: typeof __VLS_171) => any;
90
+ 'clear-icon'?: (props: typeof __VLS_175) => any;
87
91
  } & {
88
- 'loading-icon'?: (props: typeof __VLS_178) => any;
92
+ 'loading-icon'?: (props: typeof __VLS_182) => any;
89
93
  } & {
90
- 'dropdown-icon'?: (props: typeof __VLS_185) => any;
94
+ 'dropdown-icon'?: (props: typeof __VLS_189) => any;
91
95
  } & {
92
- header?: (props: typeof __VLS_213) => any;
96
+ header?: (props: typeof __VLS_219) => any;
93
97
  } & {
94
- 'filter-icon'?: (props: typeof __VLS_216) => any;
98
+ 'filter-icon'?: (props: typeof __VLS_222) => any;
95
99
  } & {
96
- empty?: (props: typeof __VLS_219) => any;
100
+ empty?: (props: typeof __VLS_225) => any;
97
101
  } & {
98
- 'empty-filter'?: (props: typeof __VLS_222) => any;
102
+ 'empty-filter'?: (props: typeof __VLS_228) => any;
99
103
  } & {
100
- item?: (props: typeof __VLS_225) => any;
104
+ item?: (props: typeof __VLS_231) => any;
101
105
  } & {
102
- group?: (props: typeof __VLS_228) => any;
106
+ group?: (props: typeof __VLS_234) => any;
103
107
  } & {
104
- footer?: (props: typeof __VLS_231) => any;
108
+ footer?: (props: typeof __VLS_237) => any;
105
109
  } & {
106
- item?: (props: typeof __VLS_271) => any;
110
+ item?: (props: typeof __VLS_277) => any;
107
111
  } & {
108
- group?: (props: typeof __VLS_274) => any;
112
+ group?: (props: typeof __VLS_280) => any;
109
113
  };
110
114
  declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
111
115
  "update:modelValue": (value: string | number | (string | number)[] | undefined) => 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";
@@ -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,22 +241,77 @@ 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)
308
+ searchText.value = "";
309
+ }
310
+ function onComboboxValueUpdate(value) {
311
+ setValue(value ?? (props.multiple ? [] : void 0));
312
+ if (props.creatable && props.multiple) {
253
313
  searchText.value = "";
314
+ }
254
315
  }
255
316
  function onDropdownClick() {
256
317
  searchText.value = "";
@@ -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();
@@ -339,7 +405,7 @@ const messages = useMessages();
339
405
  const theme = useComponentTheme("select", selectTheme);
340
406
  const themeBindings = useThemeBindings();
341
407
  const effectiveColor = computed(() => resolveRegisteredColorRole(props.color ?? "primary", "primary"));
342
- const colorRoleMarker = computed(() => effectiveColor.value);
408
+ const colorRoleMarker = computed(() => selectInvalid.value ? "danger" : effectiveColor.value);
343
409
  const ui = computed(() => theme.value({ size: effectiveSize.value, color: effectiveColor.value, invalid: selectInvalid.value }));
344
410
  const nativeTriggerAttrs = useFallthroughAttrs((key) => !props.creatable && (isNativeInputA11yAttr(key) || !props.searchable && isNativeInputEvent(key)));
345
411
  const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root, { exclude: (key) => isNativeInputA11yAttr(key) || isNativeInputEvent(key) || (props.creatable || props.searchable) && isNativeInputAttr(key) });
@@ -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));
@@ -461,6 +528,9 @@ const adaptiveUi = computed(() => ({
461
528
  const bodyProps = computed(() => ({
462
529
  searchable: props.searchable,
463
530
  creatable: props.creatable,
531
+ multiple: props.multiple,
532
+ forceSelection: props.forceSelection,
533
+ selectedValues: selectedValues.value,
464
534
  searchText: searchText.value,
465
535
  displayValue,
466
536
  items: props.items,
@@ -488,13 +558,13 @@ const bodyProps = computed(() => ({
488
558
  :model-value="rekaSelection"
489
559
  :multiple="multiple"
490
560
  :disabled="disabled"
491
- :ignore-filter="!searchable"
561
+ :ignore-filter="!searchable || creatable && multiple"
492
562
  :reset-search-term-on-blur="resetSearchTermOnBlur"
493
563
  :reset-search-term-on-select="resetSearchTermOnSelect"
494
564
  :data-selaras-color="colorRoleMarker"
495
565
  v-bind="rootProps"
496
566
  @update:open="updateOpen($event)"
497
- @update:model-value="(value2) => setValue(value2 == null ? multiple ? [] : void 0 : value2)"
567
+ @update:model-value="(value2) => onComboboxValueUpdate(value2)"
498
568
  >
499
569
  <ComboboxAnchor>
500
570
  <!--
@@ -506,7 +576,10 @@ const bodyProps = computed(() => ({
506
576
  <div
507
577
  v-if="creatable"
508
578
  data-ui-group-item
579
+ :data-selaras-field-filled="selectedValues.length ? '' : void 0"
580
+ :data-selaras-field-active="open ? '' : void 0"
509
581
  v-bind="triggerProps"
582
+ @keydown.capture="onSearchKeydown"
510
583
  >
511
584
  <!--
512
585
  TagsInputRoot doesn't own selection truth here - it only reads
@@ -561,6 +634,9 @@ const bodyProps = computed(() => ({
561
634
  </template>
562
635
  </Chip>
563
636
  </TagsInputItem>
637
+ <Tooltip v-if="overflowOptions.length" :text="overflowOptions.map((o) => o.label).join(', ')">
638
+ <span v-bind="chipOverflowProps">{{ messages.moreItems(overflowOptions.length) }}</span>
639
+ </Tooltip>
564
640
  <ComboboxInput v-model="searchText" as-child>
565
641
  <TagsInputInput
566
642
  :id="selectId"
@@ -568,31 +644,35 @@ const bodyProps = computed(() => ({
568
644
  :display-value="displayValue"
569
645
  :placeholder="placeholder"
570
646
  :aria-invalid="selectInvalid || void 0"
571
- :aria-describedby="describedBy"
647
+ :aria-describedby="searchDescribedBy"
572
648
  :aria-busy="loading || void 0"
573
649
  v-bind="searchInputProps"
574
- @keydown="onSearchKeydown"
575
650
  @blur="onSearchBlur"
576
651
  />
577
652
  </ComboboxInput>
578
653
  </TagsInputRoot>
654
+ <span v-if="multiple && displayMode === 'comma' && selectedOptions.length" :id="selectedSummaryId" class="sr-only">
655
+ {{ selectedOptions.map((o) => o.label).join(", ") }}
656
+ </span>
657
+ <span v-if="multiple && displayMode === 'comma' && selectedOptions.length" aria-hidden="true" v-bind="commaValueProps">
658
+ {{ commaText }}
659
+ </span>
660
+ <Tooltip v-if="multiple && displayMode === 'comma' && overflowOptions.length" :text="overflowOptions.map((o) => o.label).join(', ')">
661
+ <span v-bind="chipOverflowProps">{{ messages.moreItems(overflowOptions.length) }}</span>
662
+ </Tooltip>
579
663
  <ComboboxInput
580
- v-else
664
+ v-if="!(multiple && displayMode === 'chip')"
581
665
  :id="selectId"
582
666
  :ref="setEditableInput"
583
667
  v-model="searchText"
584
668
  :display-value="displayValue"
585
- :placeholder="placeholder"
669
+ :placeholder="multiple && displayMode === 'comma' && selectedOptions.length ? void 0 : placeholder"
586
670
  :aria-invalid="selectInvalid || void 0"
587
- :aria-describedby="describedBy"
671
+ :aria-describedby="searchDescribedBy"
588
672
  :aria-busy="loading || void 0"
589
673
  v-bind="searchInputProps"
590
- @keydown="onSearchKeydown"
591
674
  @blur="onSearchBlur"
592
675
  />
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
676
  <!--
597
677
  A plain Button, not ComboboxCancel as-child - this trigger is a
598
678
  <div>, so unlike the non-creatable branch below there's no real
@@ -635,6 +715,8 @@ const bodyProps = computed(() => ({
635
715
  :id="selectId"
636
716
  ref="selectTrigger"
637
717
  data-ui-group-item
718
+ :data-selaras-field-filled="selectedValues.length ? '' : void 0"
719
+ :data-selaras-field-active="open ? '' : void 0"
638
720
  :aria-invalid="selectInvalid || void 0"
639
721
  :aria-describedby="describedBy"
640
722
  :aria-busy="loading || void 0"
@@ -740,11 +822,13 @@ const bodyProps = computed(() => ({
740
822
  </ComboboxTrigger>
741
823
  </ComboboxAnchor>
742
824
 
743
- <ComboboxPortal v-if="!showMobileSelectModal">
825
+ <ComboboxPortal v-if="!showMobileSelectModal" v-bind="portalProps">
744
826
  <ComboboxContent
745
827
  position="popper" :side-offset="4"
828
+ :hide-when-empty="creatable && !multiple && !forceSelection"
746
829
  :data-selaras-theme="themeBindings['data-selaras-theme']" :data-selaras-mode="themeBindings['data-selaras-mode']" :style="themeBindings.style" :data-selaras-color="colorRoleMarker"
747
830
  v-bind="showMobileAutocompletePanel ? mergeProps(contentProps, mobilePanelProps) : contentProps"
831
+ @pointerdown.capture="startSuggestionPointer"
748
832
  >
749
833
  <ComboboxSelectBody v-bind="bodyProps" @update:search-text="searchText = $event">
750
834
  <template #header>
@@ -1,6 +1,8 @@
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';
4
6
  import type { UiProp } from '../utils/ui.js';
5
7
  import type { SelectItems, SelectOption } from './combobox-select.js';
6
8
  import { selectTheme } from '../theme/select.js';
@@ -43,7 +45,9 @@ export interface ComboboxSelectBaseProps {
43
45
  resetSearchTermOnBlur?: boolean;
44
46
  resetSearchTermOnSelect?: boolean;
45
47
  /** Shows a small pointer triangle connecting the panel to its trigger. */
46
- arrow?: boolean;
48
+ arrow?: boolean | RoundedArrowConfig;
49
+ positioning?: OverlayPositioning;
50
+ portal?: OverlayPortal;
47
51
  /** Opts into the component's accessible small-screen presentation. */
48
52
  adaptive?: boolean;
49
53
  ui?: UiProp<SelectThemeSlots>;
@@ -55,57 +59,57 @@ export interface ComboboxSelectBaseEmits {
55
59
  }
56
60
  declare var __VLS_43: {
57
61
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
58
- }, __VLS_94: {}, __VLS_101: {}, __VLS_116: {}, __VLS_140: {
62
+ }, __VLS_98: {}, __VLS_105: {}, __VLS_120: {}, __VLS_144: {
59
63
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
60
- }, __VLS_160: {
64
+ }, __VLS_164: {
61
65
  selected: import("./combobox-select.js").ResolvedOption | undefined;
62
- }, __VLS_171: {}, __VLS_178: {}, __VLS_185: {}, __VLS_213: {}, __VLS_216: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {
66
+ }, __VLS_175: {}, __VLS_182: {}, __VLS_189: {}, __VLS_219: {}, __VLS_222: {}, __VLS_225: {}, __VLS_228: {}, __VLS_231: {
63
67
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
64
- }, __VLS_228: {
68
+ }, __VLS_234: {
65
69
  group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
66
- }, __VLS_231: {}, __VLS_267: string, __VLS_268: {}, __VLS_271: {
70
+ }, __VLS_237: {}, __VLS_273: string, __VLS_274: {}, __VLS_277: {
67
71
  item: SelectOption<import("../utils/select-contracts.js").SelectValue>;
68
- }, __VLS_274: {
72
+ }, __VLS_280: {
69
73
  group: import("./combobox-select.js").SelectOptionGroup<import("../utils/select-contracts.js").SelectValue>;
70
74
  };
71
75
  type __VLS_Slots = {} & {
72
- [K in NonNullable<typeof __VLS_267>]?: (props: typeof __VLS_268) => any;
76
+ [K in NonNullable<typeof __VLS_273>]?: (props: typeof __VLS_274) => any;
73
77
  } & {
74
78
  item?: (props: typeof __VLS_43) => any;
75
79
  } & {
76
- 'clear-icon'?: (props: typeof __VLS_94) => any;
80
+ 'clear-icon'?: (props: typeof __VLS_98) => any;
77
81
  } & {
78
- 'loading-icon'?: (props: typeof __VLS_101) => any;
82
+ 'loading-icon'?: (props: typeof __VLS_105) => any;
79
83
  } & {
80
- 'dropdown-icon'?: (props: typeof __VLS_116) => any;
84
+ 'dropdown-icon'?: (props: typeof __VLS_120) => any;
81
85
  } & {
82
- item?: (props: typeof __VLS_140) => any;
86
+ item?: (props: typeof __VLS_144) => any;
83
87
  } & {
84
- value?: (props: typeof __VLS_160) => any;
88
+ value?: (props: typeof __VLS_164) => any;
85
89
  } & {
86
- 'clear-icon'?: (props: typeof __VLS_171) => any;
90
+ 'clear-icon'?: (props: typeof __VLS_175) => any;
87
91
  } & {
88
- 'loading-icon'?: (props: typeof __VLS_178) => any;
92
+ 'loading-icon'?: (props: typeof __VLS_182) => any;
89
93
  } & {
90
- 'dropdown-icon'?: (props: typeof __VLS_185) => any;
94
+ 'dropdown-icon'?: (props: typeof __VLS_189) => any;
91
95
  } & {
92
- header?: (props: typeof __VLS_213) => any;
96
+ header?: (props: typeof __VLS_219) => any;
93
97
  } & {
94
- 'filter-icon'?: (props: typeof __VLS_216) => any;
98
+ 'filter-icon'?: (props: typeof __VLS_222) => any;
95
99
  } & {
96
- empty?: (props: typeof __VLS_219) => any;
100
+ empty?: (props: typeof __VLS_225) => any;
97
101
  } & {
98
- 'empty-filter'?: (props: typeof __VLS_222) => any;
102
+ 'empty-filter'?: (props: typeof __VLS_228) => any;
99
103
  } & {
100
- item?: (props: typeof __VLS_225) => any;
104
+ item?: (props: typeof __VLS_231) => any;
101
105
  } & {
102
- group?: (props: typeof __VLS_228) => any;
106
+ group?: (props: typeof __VLS_234) => any;
103
107
  } & {
104
- footer?: (props: typeof __VLS_231) => any;
108
+ footer?: (props: typeof __VLS_237) => any;
105
109
  } & {
106
- item?: (props: typeof __VLS_271) => any;
110
+ item?: (props: typeof __VLS_277) => any;
107
111
  } & {
108
- group?: (props: typeof __VLS_274) => any;
112
+ group?: (props: typeof __VLS_280) => any;
109
113
  };
110
114
  declare const __VLS_base: import("vue").DefineComponent<ComboboxSelectBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
111
115
  "update:modelValue": (value: string | number | (string | number)[] | undefined) => any;