@oscarpalmer/oui 0.32.0 → 0.34.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 (59) hide show
  1. package/dist/css/combobox.css +93 -42
  2. package/dist/js/combobox/constants.combobox.d.mts +2 -0
  3. package/dist/js/combobox/constants.combobox.mjs +46 -0
  4. package/dist/js/combobox/data.combobox.d.mts +18 -0
  5. package/dist/js/combobox/data.combobox.mjs +2 -0
  6. package/dist/js/combobox/dom.combobox.d.mts +110 -0
  7. package/dist/js/combobox/dom.combobox.mjs +2 -0
  8. package/dist/js/combobox/event.combobox.d.mts +17 -0
  9. package/dist/js/combobox/event.combobox.mjs +2 -0
  10. package/dist/js/combobox/form.combobox.d.mts +6 -0
  11. package/dist/js/combobox/form.combobox.mjs +2 -0
  12. package/dist/js/combobox/i18n.combobox.d.mts +2 -0
  13. package/dist/js/combobox/i18n.combobox.mjs +2 -0
  14. package/dist/js/combobox/index.d.mts +2 -0
  15. package/dist/js/combobox/index.mjs +194 -0
  16. package/dist/js/combobox/misc.combobox.d.mts +14 -0
  17. package/dist/js/combobox/misc.combobox.mjs +2 -0
  18. package/dist/js/combobox/models.combobox.d.mts +2 -0
  19. package/dist/js/combobox/models.combobox.mjs +1 -0
  20. package/dist/js/combobox/state.combobox.d.mts +11 -0
  21. package/dist/js/combobox/state.combobox.mjs +2 -0
  22. package/dist/js/constants.combobox-DqNUGBLS.d.mts +243 -0
  23. package/dist/js/data.combobox-8RwBv5ey.mjs +1077 -0
  24. package/dist/js/dialog.mjs +3 -2
  25. package/dist/js/floatable/floatable.embedded.mjs +4 -4
  26. package/dist/js/focus-trap/focus-trap.embedded.mjs +3 -3
  27. package/dist/js/index.d.mts +3 -3
  28. package/dist/js/index.mjs +3 -2
  29. package/dist/js/internal/draggable.mjs +6 -6
  30. package/dist/js/internal/navigable.mjs +3 -3
  31. package/dist/js/menu.mjs +3 -2
  32. package/dist/js/movable/movable.embedded.mjs +3 -3
  33. package/dist/js/popover.mjs +1 -1
  34. package/dist/js/resizable/resizable.embedded.mjs +7 -7
  35. package/dist/js/sortable/sortable.embedded.mjs +7 -6
  36. package/dist/js/splitter.mjs +7 -13
  37. package/dist/js/tooltip.mjs +3 -3
  38. package/package.json +6 -6
  39. package/src/css/combobox.scss +98 -31
  40. package/src/js/combobox/constants.combobox.ts +62 -0
  41. package/src/js/combobox/data.combobox.ts +236 -0
  42. package/src/js/combobox/dom.combobox.ts +794 -0
  43. package/src/js/combobox/event.combobox.ts +454 -0
  44. package/src/js/combobox/form.combobox.ts +115 -0
  45. package/src/js/combobox/i18n.combobox.ts +179 -0
  46. package/src/js/combobox/index.ts +307 -0
  47. package/src/js/combobox/misc.combobox.ts +138 -0
  48. package/src/js/combobox/models.combobox.ts +94 -0
  49. package/src/js/combobox/state.combobox.ts +235 -0
  50. package/src/js/index.ts +1 -1
  51. package/src/js/internal/draggable.ts +3 -3
  52. package/src/js/internal/navigable.ts +10 -3
  53. package/src/js/movable/movable.embedded.ts +2 -2
  54. package/src/js/resizable/resizable.embedded.ts +3 -3
  55. package/src/js/sortable/sortable.embedded.ts +2 -2
  56. package/src/js/splitter.ts +2 -2
  57. package/dist/js/combobox.d.mts +0 -91
  58. package/dist/js/combobox.mjs +0 -855
  59. package/src/js/combobox.ts +0 -1634
@@ -0,0 +1,62 @@
1
+ import type {OuiComboboxAutoCompleteType, OuiComboboxType} from './models.combobox';
2
+
3
+ // #region Variables
4
+
5
+ export const COMBOBOX_TAGNAME = 'oui-combobox';
6
+
7
+ export const COMBOBOX_ATTRIBUTE_ANCHOR = `${COMBOBOX_TAGNAME}-anchor`;
8
+
9
+ export const COMBOBOX_ATTRIBUTE_CONTENT = `${COMBOBOX_TAGNAME}-content`;
10
+
11
+ export const COMBOBOX_ATTRIBUTE_FILTER = `${COMBOBOX_TAGNAME}-filter`;
12
+
13
+ export const COMBOBOX_ATTRIBUTE_FILTER_INPUT = `${COMBOBOX_ATTRIBUTE_FILTER}-input`;
14
+
15
+ export const COMBOBOX_ATTRIBUTE_HEADER = `${COMBOBOX_TAGNAME}-header`;
16
+
17
+ export const COMBOBOX_ATTRIBUTE_HIDDEN = `${COMBOBOX_TAGNAME}-hidden`;
18
+
19
+ export const COMBOBOX_ATTRIBUTE_LIST = `${COMBOBOX_TAGNAME}-list`;
20
+
21
+ export const COMBOBOX_ATTRIBUTE_MESSAGE = `${COMBOBOX_TAGNAME}-message`;
22
+
23
+ export const COMBOBOX_ATTRIBUTE_OPTION = `${COMBOBOX_TAGNAME}-option`;
24
+
25
+ export const COMBOBOX_ATTRIBUTE_OPTION_ACTIVE = `${COMBOBOX_TAGNAME}-option-active`;
26
+
27
+ export const COMBOBOX_ATTRIBUTE_SELECTION = `${COMBOBOX_TAGNAME}-selection`;
28
+
29
+ export const COMBOBOX_ATTRIBUTE_SELECTION_ITEM = `${COMBOBOX_TAGNAME}-selection-item`;
30
+
31
+ export const COMBOBOX_AUTOCOMPLETES = new Set<OuiComboboxAutoCompleteType>([
32
+ 'both',
33
+ 'inline',
34
+ 'list',
35
+ 'none',
36
+ ]);
37
+
38
+ export const COMBOBOX_KEYS_ACTIVATION = new Set([' ', 'Backspace', 'Delete', 'Enter']);
39
+
40
+ export const COMBOBOX_KEYS_NAVIGATION = new Set(['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp']);
41
+
42
+ export const COMBOBOX_KEYS_SELECTION = new Set(['ArrowRight', 'End']);
43
+
44
+ export const COMBOBOX_MESSAGE_LABEL = `<${COMBOBOX_TAGNAME}> must contain a <label> element for the <select> element`;
45
+
46
+ export const COMBOBOX_MESSAGE_SELECT = `<${COMBOBOX_TAGNAME}> must contain a valid <select> element`;
47
+
48
+ export const COMBOBOX_SELECTOR_ANCHOR = `[${COMBOBOX_ATTRIBUTE_ANCHOR}]`;
49
+
50
+ export const COMBOBOX_SELECTOR_SELECTION_ITEM = `[${COMBOBOX_ATTRIBUTE_SELECTION_ITEM}]`;
51
+
52
+ export const COMBOBOX_SELECTOR_OPTION = `[${COMBOBOX_ATTRIBUTE_OPTION}]`;
53
+
54
+ export const COMBOBOX_TYPES = new Set<OuiComboboxType>(['autocomplete', 'select']);
55
+
56
+ export const comboboxScrollOptions: ScrollIntoViewOptions = {
57
+ behavior: 'auto',
58
+ block: 'nearest',
59
+ inline: 'nearest',
60
+ };
61
+
62
+ // #endregion
@@ -0,0 +1,236 @@
1
+ import {getString} from '@oscarpalmer/atoms/string';
2
+ import {setAria} from '@oscarpalmer/toretto/aria';
3
+ import {getData} from '@oscarpalmer/toretto/data';
4
+ import {
5
+ updateComboboxMessage,
6
+ updateComboboxPreview,
7
+ updateComboboxSelection,
8
+ } from './dom.combobox';
9
+ import {onComboboxFilter} from './event.combobox';
10
+ import {updateComboboxForm} from './form.combobox';
11
+ import type {OuiComboboxState} from './models.combobox';
12
+
13
+ // #region Types
14
+
15
+ type ApplySelectionParameters = {
16
+ added: boolean;
17
+ emit?: boolean;
18
+ option?: HTMLElement;
19
+ selected?: HTMLElement[];
20
+ state: OuiComboboxState;
21
+ values?: string[];
22
+ };
23
+
24
+ // #endregion
25
+
26
+ // #region Functions
27
+
28
+ export function applyComboboxSelection(parameters: ApplySelectionParameters): void {
29
+ const {added, emit, option, selected, state} = parameters;
30
+
31
+ const {length} = state.options.all;
32
+
33
+ for (let index = 0; index < length; index += 1) {
34
+ const option = state.options.all[index];
35
+
36
+ setAria(option, 'selected', (selected ?? state.options.selected).includes(option));
37
+ }
38
+
39
+ const values =
40
+ parameters.values ??
41
+ (state.autocomplete.none
42
+ ? [state.filter.element.value]
43
+ : (selected ?? state.options.selected).map(option => getData(option, 'value', false) ?? ''));
44
+
45
+ if (values.length === 0) {
46
+ values.push('');
47
+ }
48
+
49
+ if (selected != null) {
50
+ state.options.selected = selected;
51
+ }
52
+
53
+ const update =
54
+ values.length === state.values.current.length
55
+ ? values.some(value => !state.values.current.includes(value))
56
+ : true;
57
+
58
+ if (!update) {
59
+ return;
60
+ }
61
+
62
+ updateComboboxForm(state, values, emit);
63
+ updateComboboxPreview('set', state, option);
64
+ updateComboboxSelection(state, option, added, selected);
65
+ }
66
+
67
+ export function filterComboboxOption(
68
+ state: OuiComboboxState,
69
+ value: unknown,
70
+ textContent?: boolean,
71
+ ): HTMLElement | undefined {
72
+ const filterTextContent = textContent ?? false;
73
+
74
+ const filter = getString(value).toLocaleLowerCase();
75
+
76
+ filterComboboxOptions(state);
77
+
78
+ const {length} = state.options.all;
79
+ let match: HTMLElement | undefined;
80
+
81
+ for (let index = 0; index < length; index += 1) {
82
+ const option = state.options.all[index];
83
+
84
+ const value = (
85
+ filterTextContent ? option.textContent : (getData(option, 'value', false) ?? '')
86
+ ).toLocaleLowerCase();
87
+
88
+ if (value === filter) {
89
+ match = option;
90
+
91
+ break;
92
+ }
93
+ }
94
+
95
+ return match;
96
+ }
97
+
98
+ export function filterComboboxOptions(state: OuiComboboxState): HTMLElement | undefined {
99
+ function filter(options: HTMLElement[]): boolean {
100
+ const {length} = options;
101
+
102
+ let count = 0;
103
+
104
+ for (let index = 0; index < length; index += 1) {
105
+ const option = options[index];
106
+
107
+ option.hidden =
108
+ !state.autocomplete.none && !option.textContent.toLocaleLowerCase().includes(value);
109
+
110
+ if (!option.hidden) {
111
+ count += 1;
112
+
113
+ visible.push(option);
114
+ }
115
+ }
116
+
117
+ return count === 0;
118
+ }
119
+
120
+ const value = state.filter.element.value.toLocaleLowerCase();
121
+
122
+ const visible: HTMLElement[] = [];
123
+
124
+ if (state.groups == null) {
125
+ filter(state.options.all);
126
+ } else {
127
+ const groupsLength = state.groups.length;
128
+
129
+ for (let groupIndex = 0; groupIndex < groupsLength; groupIndex += 1) {
130
+ const {element, options} = state.groups[groupIndex];
131
+
132
+ element.hidden = filter(options);
133
+ }
134
+ }
135
+
136
+ updateComboboxMessage(state, visible.length);
137
+
138
+ return state.active != null && visible.includes(state.active) ? state.active : visible[0];
139
+ }
140
+
141
+ export function setComboboxValue(state: OuiComboboxState, value: unknown, emit?: boolean): void {
142
+ if (state.autocomplete.none) {
143
+ state.filter.element.value = getString(value);
144
+
145
+ onComboboxFilter('insertText', state, true, emit);
146
+
147
+ return;
148
+ }
149
+
150
+ const option = filterComboboxOption(state, value);
151
+
152
+ if (option != null) {
153
+ setComboboxValues(state, [value], emit);
154
+ }
155
+ }
156
+
157
+ export function setComboboxValues(state: OuiComboboxState, value: unknown, emit?: boolean): void {
158
+ if (!Array.isArray(value)) {
159
+ return;
160
+ }
161
+
162
+ const values = (state.multiple ? value : value.slice(0, 1)).map(value =>
163
+ getString(value).toLocaleLowerCase(),
164
+ );
165
+
166
+ if (values.length === 0) {
167
+ values.push('');
168
+ }
169
+
170
+ if (state.autocomplete.none) {
171
+ setComboboxValue(state, values[0], emit);
172
+
173
+ return;
174
+ }
175
+
176
+ const {length} = state.options.all;
177
+
178
+ const selected: HTMLElement[] = [];
179
+
180
+ for (let index = 0; index < length; index += 1) {
181
+ const option = state.options.all[index];
182
+
183
+ if (values.includes(getData(option, 'value', false)?.toLocaleLowerCase() ?? '')) {
184
+ selected.push(option);
185
+ }
186
+ }
187
+
188
+ applyComboboxSelection({
189
+ emit,
190
+ selected,
191
+ state,
192
+ added: true,
193
+ option: selected[0] ?? state.options.all[0],
194
+ values: state.autocomplete.none ? values : undefined,
195
+ });
196
+ }
197
+
198
+ export function toggleComboboxOption(state: OuiComboboxState, option?: HTMLElement): void {
199
+ if (option == null || (!state.multiple && state.options.selected.includes(option))) {
200
+ state.floatable.hide();
201
+
202
+ return;
203
+ }
204
+
205
+ const selected = state.options.selected.slice();
206
+
207
+ let added = true;
208
+
209
+ if (state.multiple) {
210
+ const index = selected.indexOf(option);
211
+
212
+ if (index === -1) {
213
+ selected.push(option);
214
+ } else {
215
+ added = false;
216
+
217
+ selected.splice(index, 1);
218
+ }
219
+ } else {
220
+ selected.splice(0, selected.length, option);
221
+ }
222
+
223
+ applyComboboxSelection({
224
+ added,
225
+ option,
226
+ selected,
227
+ state,
228
+ values: state.autocomplete.none && option != null ? [option.textContent] : undefined,
229
+ });
230
+
231
+ if (!state.multiple) {
232
+ state.floatable.hide();
233
+ }
234
+ }
235
+
236
+ // #endregion