@oscarpalmer/oui 0.35.0 → 0.37.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 (128) hide show
  1. package/dist/css/badge.css +18 -15
  2. package/dist/css/button.css +35 -31
  3. package/dist/css/color.css +20 -20
  4. package/dist/css/combobox.css +134 -35
  5. package/dist/css/content.css +29 -10
  6. package/dist/css/floatable.css +10 -10
  7. package/dist/css/form.css +393 -129
  8. package/dist/css/listbox.css +176 -0
  9. package/dist/css/message.css +13 -10
  10. package/dist/css/reset.css +29 -88
  11. package/dist/css/splitter.css +2 -2
  12. package/dist/css/tabs.css +103 -0
  13. package/dist/js/combobox/constants.combobox.d.mts +2 -2
  14. package/dist/js/combobox/constants.combobox.mjs +40 -33
  15. package/dist/js/combobox/dom.combobox.d.mts +8 -91
  16. package/dist/js/combobox/dom.combobox.mjs +204 -2
  17. package/dist/js/combobox/event.combobox.d.mts +14 -8
  18. package/dist/js/combobox/event.combobox.mjs +2 -2
  19. package/dist/js/combobox/index.d.mts +1 -1
  20. package/dist/js/combobox/index.mjs +20 -18
  21. package/dist/js/combobox/misc.combobox.d.mts +2 -2
  22. package/dist/js/combobox/misc.combobox.mjs +2 -2
  23. package/dist/js/combobox/models.combobox.d.mts +44 -2
  24. package/dist/js/combobox/state.combobox.d.mts +9 -10
  25. package/dist/js/combobox/state.combobox.mjs +2 -2
  26. package/dist/js/constants.combobox-DmRAMC64.d.mts +26 -0
  27. package/dist/js/constants.listbox-DRsXUxd3.d.mts +14 -0
  28. package/dist/js/focus-trap/focus-trap.embedded.mjs +6 -10
  29. package/dist/js/index-EfkUSals.d.mts +139 -0
  30. package/dist/js/index.d.mts +5 -2
  31. package/dist/js/index.mjs +5 -2
  32. package/dist/js/internal/attributable.mjs +4 -3
  33. package/dist/js/internal/draggable.mjs +16 -22
  34. package/dist/js/internal/listbox/listbox.constants.d.mts +11 -0
  35. package/dist/js/internal/listbox/listbox.constants.mjs +23 -0
  36. package/dist/js/internal/listbox/listbox.data.d.mts +20 -0
  37. package/dist/js/internal/listbox/listbox.data.mjs +2 -0
  38. package/dist/js/internal/listbox/listbox.dom.d.mts +66 -0
  39. package/dist/js/internal/listbox/listbox.dom.mjs +2 -0
  40. package/dist/js/internal/listbox/listbox.event.d.mts +5 -0
  41. package/dist/js/internal/listbox/listbox.event.mjs +63 -0
  42. package/dist/js/internal/listbox/listbox.form.d.mts +6 -0
  43. package/dist/js/internal/listbox/listbox.form.mjs +52 -0
  44. package/dist/js/internal/listbox/listbox.misc.d.mts +12 -0
  45. package/dist/js/internal/listbox/listbox.misc.mjs +2 -0
  46. package/dist/js/internal/listbox/listbox.model.d.mts +2 -0
  47. package/dist/js/internal/listbox/listbox.model.mjs +1 -0
  48. package/dist/js/internal/listbox/listbox.state.d.mts +7 -0
  49. package/dist/js/internal/listbox/listbox.state.mjs +40 -0
  50. package/dist/js/internal/misc.d.mts +6 -0
  51. package/dist/js/internal/misc.mjs +13 -0
  52. package/dist/js/internal/navigable.d.mts +11 -5
  53. package/dist/js/internal/navigable.mjs +44 -18
  54. package/dist/js/l10n-Bn-7RcwR.d.mts +20 -0
  55. package/dist/js/l10n.d.mts +2 -20
  56. package/dist/js/listbox/constants.listbox.d.mts +2 -0
  57. package/dist/js/listbox/constants.listbox.mjs +40 -0
  58. package/dist/js/listbox/event.listbox.d.mts +8 -0
  59. package/dist/js/listbox/event.listbox.mjs +2 -0
  60. package/dist/js/listbox/index.d.mts +116 -0
  61. package/dist/js/listbox/index.mjs +189 -0
  62. package/dist/js/listbox/misc.listbox.d.mts +2 -0
  63. package/dist/js/listbox/misc.listbox.mjs +2 -0
  64. package/dist/js/listbox/state.listbox.d.mts +11 -0
  65. package/dist/js/listbox/state.listbox.mjs +2 -0
  66. package/dist/js/listbox.data-BWd0PCy7.mjs +424 -0
  67. package/dist/js/listbox.model-CRReGOmu.d.mts +125 -0
  68. package/dist/js/misc.listbox-BI-XsTOf.mjs +197 -0
  69. package/dist/js/misc.listbox-gnoJhrTr.d.mts +20 -0
  70. package/dist/js/movable/movable.embedded.mjs +3 -6
  71. package/dist/js/resizable/resizable.embedded.mjs +16 -26
  72. package/dist/js/sortable/sortable.embedded.mjs +4 -2
  73. package/dist/js/splitter.mjs +15 -12
  74. package/dist/js/state.combobox-4xq0FPCF.mjs +365 -0
  75. package/dist/js/tabs.d.mts +25 -0
  76. package/dist/js/tabs.mjs +240 -0
  77. package/dist/js/tooltip.mjs +13 -12
  78. package/package.json +7 -3
  79. package/src/css/badge.scss +6 -18
  80. package/src/css/button.scss +6 -45
  81. package/src/css/color.scss +20 -20
  82. package/src/css/combobox.scss +21 -52
  83. package/src/css/content.scss +30 -3
  84. package/src/css/floatable.scss +17 -17
  85. package/src/css/form.scss +84 -72
  86. package/src/css/listbox.scss +120 -0
  87. package/src/css/message.scss +13 -28
  88. package/src/css/mixins.scss +253 -28
  89. package/src/css/reset.scss +37 -86
  90. package/src/css/splitter.scss +2 -2
  91. package/src/css/tabs.scss +85 -0
  92. package/src/js/combobox/constants.combobox.ts +46 -25
  93. package/src/js/combobox/dom.combobox.ts +36 -454
  94. package/src/js/combobox/event.combobox.ts +129 -218
  95. package/src/js/combobox/index.ts +37 -30
  96. package/src/js/combobox/misc.combobox.ts +30 -114
  97. package/src/js/combobox/models.combobox.ts +7 -47
  98. package/src/js/combobox/state.combobox.ts +126 -127
  99. package/src/js/focus-trap/focus-trap.embedded.ts +11 -19
  100. package/src/js/index.ts +2 -0
  101. package/src/js/internal/draggable.ts +29 -33
  102. package/src/js/internal/listbox/listbox.constants.ts +25 -0
  103. package/src/js/{combobox/data.combobox.ts → internal/listbox/listbox.data.ts} +94 -43
  104. package/src/js/internal/listbox/listbox.dom.ts +445 -0
  105. package/src/js/internal/listbox/listbox.event.ts +129 -0
  106. package/src/js/{combobox/form.combobox.ts → internal/listbox/listbox.form.ts} +13 -14
  107. package/src/js/internal/listbox/listbox.misc.ts +135 -0
  108. package/src/js/internal/listbox/listbox.model.ts +169 -0
  109. package/src/js/internal/listbox/listbox.state.ts +82 -0
  110. package/src/js/internal/misc.ts +27 -0
  111. package/src/js/internal/navigable.ts +80 -23
  112. package/src/js/l10n.ts +8 -8
  113. package/src/js/listbox/constants.listbox.ts +61 -0
  114. package/src/js/listbox/event.listbox.ts +106 -0
  115. package/src/js/listbox/index.ts +302 -0
  116. package/src/js/listbox/misc.listbox.ts +70 -0
  117. package/src/js/listbox/state.listbox.ts +196 -0
  118. package/src/js/movable/movable.embedded.ts +11 -13
  119. package/src/js/resizable/resizable.embedded.ts +25 -39
  120. package/src/js/splitter.ts +21 -18
  121. package/src/js/tabs.ts +447 -0
  122. package/src/js/tooltip.ts +20 -17
  123. package/dist/js/combobox/data.combobox.d.mts +0 -18
  124. package/dist/js/combobox/data.combobox.mjs +0 -2
  125. package/dist/js/combobox/form.combobox.d.mts +0 -6
  126. package/dist/js/combobox/form.combobox.mjs +0 -2
  127. package/dist/js/constants.combobox-h_kyDegw.d.mts +0 -248
  128. package/dist/js/data.combobox-B8HMkDOh.mjs +0 -1030
package/src/js/index.ts CHANGED
@@ -5,9 +5,11 @@ export * from './combobox/index';
5
5
  export * from './dialog';
6
6
  export * from './floatable/floatable.standalone';
7
7
  export * from './focus-trap/focus-trap.standalone';
8
+ export * from './listbox/index';
8
9
  export * from './movable/movable.standalone';
9
10
  export * from './popover';
10
11
  export * from './resizable/resizable.standalone';
11
12
  export * from './sortable/sortable.standalone';
12
13
  export * from './splitter';
14
+ export * from './tabs';
13
15
  export * from './tooltip';
@@ -258,7 +258,7 @@ function cancelDrag(item?: OuiDraggableItem): void {
258
258
 
259
259
  item.state.options.drag.onCancel?.(globals, item);
260
260
 
261
- dispatch(item.state.element, `${item.state.name}:cancel`, {
261
+ dispatch(item.state.element, `oui:${item.state.name}:cancel`, {
262
262
  detail: {
263
263
  element: item.state.options.getOrigin(),
264
264
  },
@@ -406,35 +406,33 @@ function onPointerdown(event: MouseEvent | TouchEvent): void {
406
406
  globals.offset = item.state.options.position.getOffset(globals, item, element, position);
407
407
  globals.original = item.state.options.position.getOriginal(globals, item, position);
408
408
 
409
- const dispatched = dispatch(item.state.element, `${item.state.name}:begin`, {
410
- detail: {
411
- element,
412
- position: {...globals.original},
413
- },
414
- });
415
-
416
- setTimeout(() => {
417
- if (dispatched.defaultPrevented) {
418
- item.state.options.drag.onCancel?.(globals, item);
409
+ if (
410
+ dispatch(item.state.element, `oui:${item.state.name}:begin`, {
411
+ detail: {
412
+ element,
413
+ position: {...globals.original},
414
+ },
415
+ }).defaultPrevented
416
+ ) {
417
+ item.state.options.drag.onCancel?.(globals, item);
419
418
 
420
- reset();
419
+ reset();
421
420
 
422
- return;
423
- }
421
+ return;
422
+ }
424
423
 
425
- const next = getNextPosition(item, position);
424
+ const next = getNextPosition(item, position);
426
425
 
427
- setStyles(dragged, {
428
- position: 'fixed',
429
- inset: `${next.y}px auto auto ${next.x}px`,
430
- transform: 'translate3d(0, 0, 0)',
431
- });
426
+ setStyles(dragged, {
427
+ position: 'fixed',
428
+ inset: `${next.y}px auto auto ${next.x}px`,
429
+ transform: 'translate3d(0, 0, 0)',
430
+ });
432
431
 
433
- item.state.options.drag.onBegin?.(event, globals, item, element, handle, next);
432
+ item.state.options.drag.onBegin?.(event, globals, item, element, handle, next);
434
433
 
435
- item.state.styling.set();
436
- styleToggler.set();
437
- });
434
+ item.state.styling.set();
435
+ styleToggler.set();
438
436
  }
439
437
 
440
438
  function onPointermove(event: MouseEvent | TouchEvent): void {
@@ -459,15 +457,13 @@ function onPointermove(event: MouseEvent | TouchEvent): void {
459
457
  original: position,
460
458
  });
461
459
 
462
- const dispatched = dispatch(current.state.element, `${current.state.name}:move`, {
463
- detail,
464
- });
465
-
466
- setTimeout(() => {
467
- if (dispatched.defaultPrevented) {
468
- cancelDrag(current);
469
- }
470
- });
460
+ if (
461
+ dispatch(current.state.element, `oui:${current.state.name}:move`, {
462
+ detail,
463
+ }).defaultPrevented
464
+ ) {
465
+ cancelDrag(current);
466
+ }
471
467
  }
472
468
 
473
469
  function onPointerup(event: MouseEvent | TouchEvent): void {
@@ -0,0 +1,25 @@
1
+ import type {OuiListboxType} from './listbox.model';
2
+
3
+ // #region Variables
4
+
5
+ const keysActivation = new Set([' ', 'Backspace', 'Delete', 'Enter']);
6
+
7
+ const keysNavigation = new Set(['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp']);
8
+
9
+ const keysSelection = new Set(['ArrowRight', 'End']);
10
+
11
+ export const LISTBOX_KEYS = {
12
+ activation: keysActivation,
13
+ navigation: keysNavigation,
14
+ selection: keysSelection,
15
+ };
16
+
17
+ export const LISTBOX_TYPES = new Set<OuiListboxType>(['autocomplete', 'select']);
18
+
19
+ export const listboxScrollOptions: ScrollIntoViewOptions = {
20
+ behavior: 'auto',
21
+ block: 'nearest',
22
+ inline: 'nearest',
23
+ };
24
+
25
+ // #endregion
@@ -1,23 +1,22 @@
1
1
  import {getString} from '@oscarpalmer/atoms/string';
2
2
  import {setAria} from '@oscarpalmer/toretto/aria';
3
+ import {setAttribute} from '@oscarpalmer/toretto/attribute';
3
4
  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';
5
+ import {dispatch} from '@oscarpalmer/toretto/event';
6
+ import {updateListboxMessage, updateListboxPreview, updateListboxValueLabel} from './listbox.dom';
7
+ import {updateListboxForm} from './listbox.form';
8
+ import {setListboxFilter} from './listbox.misc';
9
+ import type {OuiListboxPreview, OuiListboxState} from './listbox.model';
12
10
 
13
11
  // #region Types
14
12
 
15
- type ApplySelectionParameters = {
13
+ type ApplySelectionParameters<State extends OuiListboxState = OuiListboxState> = {
16
14
  added: boolean;
17
15
  emit?: boolean;
18
16
  option?: HTMLElement;
17
+ scroll?: boolean;
19
18
  selected?: HTMLElement[];
20
- state: OuiComboboxState;
19
+ state: State;
21
20
  values?: string[];
22
21
  };
23
22
 
@@ -25,20 +24,26 @@ type ApplySelectionParameters = {
25
24
 
26
25
  // #region Functions
27
26
 
28
- export function applyComboboxSelection(parameters: ApplySelectionParameters): void {
29
- const {added, emit, option, selected, state} = parameters;
30
-
27
+ export function applyListboxSelection<State extends OuiListboxState>(
28
+ parameters: ApplySelectionParameters<State>,
29
+ ): void {
30
+ const {added, emit, option, scroll, selected, state} = parameters;
31
31
  const {length} = state.options.all;
32
32
 
33
33
  for (let index = 0; index < length; index += 1) {
34
34
  const option = state.options.all[index];
35
35
 
36
- setAria(option, 'selected', (selected ?? state.options.selected).includes(option));
36
+ setAria(
37
+ option,
38
+ 'selected',
39
+ (state.type === 'select' || !state.autocomplete.none) &&
40
+ (selected ?? state.options.selected).includes(option),
41
+ );
37
42
  }
38
43
 
39
44
  const values =
40
45
  parameters.values ??
41
- (state.autocomplete.none
46
+ (state.autocomplete.none && !state.listbox
42
47
  ? [state.filter.element.value]
43
48
  : (selected ?? state.options.selected).map(option => getData(option, 'value', false) ?? ''));
44
49
 
@@ -59,13 +64,44 @@ export function applyComboboxSelection(parameters: ApplySelectionParameters): vo
59
64
  return;
60
65
  }
61
66
 
62
- updateComboboxForm(state, values, emit);
63
- updateComboboxPreview('set', state, option);
64
- updateComboboxSelection(state, option, added, selected);
67
+ updateListboxForm(state, values, emit);
68
+ updateListboxMessage(state);
69
+ updateListboxPreview('set', state, option, scroll);
70
+ updateListboxValueLabel(state);
71
+
72
+ state.callbacks.data.onApply(state, option, values, added, selected, emit);
65
73
  }
66
74
 
67
- export function filterComboboxOption(
68
- state: OuiComboboxState,
75
+ export function filterListbox(type: InputEvent['inputType'], state: OuiListboxState): void {
76
+ if (state.disabled || state.readonly) {
77
+ return;
78
+ }
79
+
80
+ const update = state.filter.element.value !== state.filter.value;
81
+
82
+ const option = filterListboxOptions(state);
83
+
84
+ let preview: OuiListboxPreview | undefined;
85
+
86
+ if (type.includes('delete')) {
87
+ preview = 'none';
88
+ } else if (type.includes('insert')) {
89
+ preview = 'typed';
90
+ }
91
+
92
+ if (preview != null) {
93
+ state.callbacks.data.onFilter(preview, state, update, option);
94
+ }
95
+
96
+ if (update) {
97
+ state.filter.value = state.filter.element.value;
98
+
99
+ dispatch(state.host, 'input');
100
+ }
101
+ }
102
+
103
+ export function filterListboxOption(
104
+ state: OuiListboxState,
69
105
  value: unknown,
70
106
  textContent?: boolean,
71
107
  ): HTMLElement | undefined {
@@ -73,9 +109,10 @@ export function filterComboboxOption(
73
109
 
74
110
  const filter = getString(value).toLocaleLowerCase();
75
111
 
76
- filterComboboxOptions(state);
112
+ filterListboxOptions(state);
77
113
 
78
114
  const {length} = state.options.all;
115
+
79
116
  let match: HTMLElement | undefined;
80
117
 
81
118
  for (let index = 0; index < length; index += 1) {
@@ -95,7 +132,7 @@ export function filterComboboxOption(
95
132
  return match;
96
133
  }
97
134
 
98
- export function filterComboboxOptions(state: OuiComboboxState): HTMLElement | undefined {
135
+ export function filterListboxOptions(state: OuiListboxState): HTMLElement | undefined {
99
136
  function filter(options: HTMLElement[]): boolean {
100
137
  const {length} = options;
101
138
 
@@ -105,7 +142,8 @@ export function filterComboboxOptions(state: OuiComboboxState): HTMLElement | un
105
142
  const option = options[index];
106
143
 
107
144
  option.hidden =
108
- !state.autocomplete.none && !option.textContent.toLocaleLowerCase().includes(value);
145
+ (state.type === 'select' || !state.autocomplete.none) &&
146
+ !option.textContent.toLocaleLowerCase().includes(value);
109
147
 
110
148
  if (!option.hidden) {
111
149
  count += 1;
@@ -133,28 +171,36 @@ export function filterComboboxOptions(state: OuiComboboxState): HTMLElement | un
133
171
  }
134
172
  }
135
173
 
136
- updateComboboxMessage(state, visible.length);
174
+ setAttribute(state.list, state.attributes.empty, visible.length === 0 ? '' : undefined);
175
+
176
+ updateListboxMessage(state);
137
177
 
138
178
  return state.active != null && visible.includes(state.active) ? state.active : visible[0];
139
179
  }
140
180
 
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);
181
+ export function setListboxValue<State extends OuiListboxState>(
182
+ state: State,
183
+ value: unknown,
184
+ emit?: boolean,
185
+ ): void {
186
+ if (state.autocomplete.none && !state.listbox) {
187
+ setListboxFilter(state, getString(value));
146
188
 
147
189
  return;
148
190
  }
149
191
 
150
- const option = filterComboboxOption(state, value);
192
+ const option = filterListboxOption(state, value);
151
193
 
152
194
  if (option != null) {
153
- setComboboxValues(state, [value], emit);
195
+ setListboxValues(state, [value], emit);
154
196
  }
155
197
  }
156
198
 
157
- export function setComboboxValues(state: OuiComboboxState, value: unknown, emit?: boolean): void {
199
+ export function setListboxValues<State extends OuiListboxState>(
200
+ state: State,
201
+ value: unknown[],
202
+ emit?: boolean,
203
+ ): void {
158
204
  if (!Array.isArray(value)) {
159
205
  return;
160
206
  }
@@ -167,8 +213,8 @@ export function setComboboxValues(state: OuiComboboxState, value: unknown, emit?
167
213
  values.push('');
168
214
  }
169
215
 
170
- if (state.autocomplete.none) {
171
- setComboboxValue(state, values[0], emit);
216
+ if (state.autocomplete.none && !state.listbox) {
217
+ setListboxValue(state, values[0], emit);
172
218
 
173
219
  return;
174
220
  }
@@ -185,19 +231,22 @@ export function setComboboxValues(state: OuiComboboxState, value: unknown, emit?
185
231
  }
186
232
  }
187
233
 
188
- applyComboboxSelection({
234
+ applyListboxSelection({
189
235
  emit,
190
236
  selected,
191
237
  state,
192
238
  added: true,
193
239
  option: selected[0] ?? state.options.all[0],
194
- values: state.autocomplete.none ? values : undefined,
240
+ values: state.autocomplete.none && !state.listbox ? values : undefined,
195
241
  });
196
242
  }
197
243
 
198
- export function toggleComboboxOption(state: OuiComboboxState, option?: HTMLElement): void {
244
+ export function toggleListboxOption<State extends OuiListboxState>(
245
+ state: State,
246
+ option?: HTMLElement,
247
+ ): void {
199
248
  if (option == null || (!state.multiple && state.options.selected.includes(option))) {
200
- state.floatable.hide();
249
+ state.callbacks.data.onToggle(state);
201
250
 
202
251
  return;
203
252
  }
@@ -220,17 +269,19 @@ export function toggleComboboxOption(state: OuiComboboxState, option?: HTMLEleme
220
269
  selected.splice(0, selected.length, option);
221
270
  }
222
271
 
223
- applyComboboxSelection({
272
+ applyListboxSelection({
224
273
  added,
225
274
  option,
226
275
  selected,
227
276
  state,
228
- values: state.autocomplete.none && option != null ? [option.textContent] : undefined,
277
+ scroll: false,
278
+ values:
279
+ state.autocomplete.none && !state.listbox && option != null
280
+ ? [option.textContent]
281
+ : undefined,
229
282
  });
230
283
 
231
- if (!state.multiple) {
232
- state.floatable.hide();
233
- }
284
+ state.callbacks.data.onToggle(state);
234
285
  }
235
286
 
236
287
  // #endregion