@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
@@ -0,0 +1,196 @@
1
+ import {noop} from '@oscarpalmer/atoms/function';
2
+ import {setAttribute, setAttributes} from '@oscarpalmer/toretto/attribute';
3
+ import {getData} from '@oscarpalmer/toretto/data';
4
+ import {createListboxContent} from '../internal/listbox/listbox.dom';
5
+ import {generateListboxIds} from '../internal/listbox/listbox.misc';
6
+ import type {
7
+ OuiListboxAutoCompleteType,
8
+ OuiListboxCallbacks,
9
+ OuiListboxLocalizations,
10
+ OuiListboxState,
11
+ OuiListboxStates,
12
+ } from '../internal/listbox/listbox.model';
13
+ import {initializeListboxState} from '../internal/listbox/listbox.state';
14
+ import {getBooleanAriaValue} from '../internal/misc';
15
+ import {getLocalizations} from '../l10n';
16
+ import {LISTBOX_ATTRIBUTES, LISTBOX_MESSAGES} from './constants.listbox';
17
+ import {
18
+ onListboxEnter,
19
+ onListboxFilter,
20
+ onListboxNavigation,
21
+ onListboxToggle,
22
+ } from './event.listbox';
23
+ import type {OuiListboxElement} from './index';
24
+ import {getListboxId} from './misc.listbox';
25
+
26
+ // #region Functions
27
+
28
+ export function createListboxState(
29
+ element: OuiListboxElement,
30
+ internals: ElementInternals,
31
+ ): OuiListboxState {
32
+ const select = element.querySelector('select');
33
+
34
+ if (select == null) {
35
+ throw new Error(LISTBOX_MESSAGES.select);
36
+ }
37
+
38
+ const label = element.querySelector(`label[for="${select.id}"]`) as HTMLLabelElement;
39
+
40
+ if (label == null) {
41
+ throw new Error(LISTBOX_MESSAGES.label);
42
+ }
43
+
44
+ element.id = select.id;
45
+
46
+ setAttribute(element, 'name', select.name === '' ? select.id : select.name);
47
+
48
+ const disabled = getBooleanAriaValue(element, 'disabled') || select.disabled;
49
+ const multiple = element.multiple || select.multiple;
50
+ const readonly = getBooleanAriaValue(element, 'readonly');
51
+ const required = getBooleanAriaValue(element, 'required') || select.required;
52
+
53
+ setAttributes(element, {
54
+ autocomplete: 'none',
55
+ name: select.name === '' ? select.id : select.name,
56
+ });
57
+
58
+ const id = getListboxId();
59
+
60
+ const labelId = label.id;
61
+
62
+ label.htmlFor = id;
63
+ label.id = `${id}_label`;
64
+
65
+ generateListboxIds(id, select);
66
+
67
+ const type = 'select';
68
+
69
+ const content = createListboxContent({
70
+ element,
71
+ id,
72
+ label,
73
+ multiple,
74
+ select,
75
+ type,
76
+ attributes: LISTBOX_ATTRIBUTES,
77
+ autocomplete: listboxAutoComplete,
78
+ listbox: true,
79
+ });
80
+
81
+ const {selected} = content.list.options;
82
+
83
+ const values =
84
+ selected.length === 0 ? [''] : selected.map(option => getData(option, 'value', false) ?? '');
85
+
86
+ const state: OuiListboxState = {
87
+ disabled,
88
+ id,
89
+ internals,
90
+ message: content.message,
91
+ multiple,
92
+ readonly,
93
+ required,
94
+ select,
95
+ type,
96
+ active: selected[0],
97
+ attributes: LISTBOX_ATTRIBUTES,
98
+ autocomplete: listboxAutoComplete,
99
+ callbacks: listboxCallbacks,
100
+ content: content.element,
101
+ elements: [element, content.filter!.element],
102
+ filter: {
103
+ element: content.filter!.element,
104
+ value: '',
105
+ },
106
+ host: element,
107
+ label: {
108
+ id: labelId,
109
+ element: label,
110
+ },
111
+ list: content.list.element,
112
+ listeners: [],
113
+ listbox: true,
114
+ localizations: {
115
+ component: {},
116
+ global: listboxLocalizations,
117
+ },
118
+ name: element.name,
119
+ options: content.list.options,
120
+ values: {
121
+ current: values.slice(),
122
+ initial: values.slice(),
123
+ label: content.value,
124
+ },
125
+ };
126
+
127
+ return initializeListboxState(state, listboxStates, onAttachListbox);
128
+ }
129
+
130
+ // #endregion
131
+
132
+ // #region Functions
133
+
134
+ export function onAttachListbox(state: OuiListboxState): void {
135
+ const {content, select} = state;
136
+
137
+ select.hidden = true;
138
+
139
+ select.insertAdjacentElement('afterend', content);
140
+
141
+ select.remove();
142
+ }
143
+
144
+ export function onDetachListbox(state: OuiListboxState): void {
145
+ const {content, select} = state;
146
+
147
+ content.insertAdjacentElement('beforebegin', select);
148
+
149
+ content.remove();
150
+
151
+ select.hidden = false;
152
+ }
153
+
154
+ // #endregion
155
+
156
+ // #region Variables
157
+
158
+ const listboxAutoComplete: Record<OuiListboxAutoCompleteType, boolean> = {
159
+ both: false,
160
+ inline: false,
161
+ list: false,
162
+ none: true,
163
+ };
164
+
165
+ const listboxCallbacks: OuiListboxCallbacks = {
166
+ data: {
167
+ onApply: noop,
168
+ onFilter: onListboxFilter,
169
+ onForm: noop,
170
+ onPreview: noop,
171
+ onToggle: onListboxToggle,
172
+ },
173
+ keydown: {
174
+ onEnter: onListboxEnter,
175
+ onNavigation: onListboxNavigation,
176
+ onToggle: onListboxToggle,
177
+ },
178
+ };
179
+
180
+ export const listboxLocalizations = getLocalizations<OuiListboxLocalizations>({
181
+ empty: 'No results found',
182
+ input: '',
183
+ invalid: 'Please select an option from the list',
184
+ max: max => `Please select fewer options (maximum is ${max})`,
185
+ min: min => `Please select more options (minimum is ${min})`,
186
+ remove: '',
187
+ results: amount => `${amount} results available`,
188
+ selected: amount => `${amount} selected`,
189
+ });
190
+
191
+ export const listboxStates: OuiListboxStates = {
192
+ map: new WeakMap(),
193
+ set: new Set(),
194
+ };
195
+
196
+ // #endregion
@@ -199,20 +199,18 @@ function onEnd(
199
199
  setOffset(state, container);
200
200
  }
201
201
 
202
- const dispatched = dispatch(state.element, 'movable:end', {
203
- detail: {
204
- from: {...globals.original},
205
- to: getEventPosition(event),
206
- },
207
- });
208
-
209
- setTimeout(() => {
210
- if (dispatched.defaultPrevented) {
211
- onCancel(globals, item);
212
- }
202
+ if (
203
+ dispatch(state.element, 'oui:movable:end', {
204
+ detail: {
205
+ from: {...globals.original},
206
+ to: getEventPosition(event),
207
+ },
208
+ }).defaultPrevented
209
+ ) {
210
+ onCancel(globals, item);
211
+ }
213
212
 
214
- reset();
215
- });
213
+ reset();
216
214
  }
217
215
 
218
216
  function onMove(
@@ -101,7 +101,7 @@ function cancelResize(item?: OuiResizableItem): void {
101
101
 
102
102
  resetResizable();
103
103
 
104
- dispatch(item.state.element, 'resizable:cancel');
104
+ dispatch(item.state.element, 'oui:resizable:cancel');
105
105
  }
106
106
 
107
107
  /**
@@ -289,19 +289,15 @@ function onPointerdown(event: MouseEvent | TouchEvent): void {
289
289
  event.preventDefault();
290
290
  }
291
291
 
292
- const dispatched = dispatch(element!, 'resizable:begin');
293
-
294
- setTimeout(() => {
295
- if (dispatched.defaultPrevented) {
296
- return;
297
- }
292
+ if (dispatch(element!, 'oui:resizable:begin').defaultPrevented) {
293
+ return;
294
+ }
298
295
 
299
- current = stored;
300
- start = position;
296
+ current = stored;
297
+ start = position;
301
298
 
302
- current.state.styles.set();
303
- styleToggler.set();
304
- });
299
+ current.state.styles.set();
300
+ styleToggler.set();
305
301
  }
306
302
 
307
303
  function onPointermove(event: MouseEvent | TouchEvent): void {
@@ -320,41 +316,31 @@ function onPointermove(event: MouseEvent | TouchEvent): void {
320
316
 
321
317
  getAndSetDimensions(current.state.element, current.state.options, {height, width});
322
318
 
323
- const dispatched = dispatch(current.state.element, 'resizable:resize', {
324
- detail: {
325
- height,
326
- width,
327
- },
328
- });
329
-
330
- setTimeout(() => {
331
- if (dispatched.defaultPrevented) {
332
- cancelResize(current);
333
- }
334
- });
319
+ if (
320
+ dispatch(current.state.element, 'oui:resizable:resize', {
321
+ detail: {
322
+ height,
323
+ width,
324
+ },
325
+ }).defaultPrevented
326
+ ) {
327
+ cancelResize(current);
328
+ }
335
329
  }
336
330
 
337
331
  function onPointerup(): void {
338
- if (current == null) {
332
+ if (current == null || dispatch(current.state.element, 'oui:resizable:end').defaultPrevented) {
333
+ cancelResize(current);
334
+
339
335
  return;
340
336
  }
341
337
 
342
- const dispatched = dispatch(current.state.element, 'resizable:end');
343
-
344
- setTimeout(() => {
345
- if (current == null || dispatched.defaultPrevented) {
346
- cancelResize(current);
338
+ const {height, width} = current.state.element.getBoundingClientRect();
347
339
 
348
- return;
349
- }
350
-
351
- const {height, width} = current.state.element.getBoundingClientRect();
340
+ current.state.height = height;
341
+ current.state.width = width;
352
342
 
353
- current.state.height = height;
354
- current.state.width = width;
355
-
356
- resetResizable();
357
- });
343
+ resetResizable();
358
344
  }
359
345
 
360
346
  function removeResizable(element: HTMLElement): void {
@@ -3,6 +3,7 @@ import {round} from '@oscarpalmer/atoms/math';
3
3
  import {clamp} from '@oscarpalmer/atoms/number';
4
4
  import {setAria} from '@oscarpalmer/toretto/aria';
5
5
  import {getAttribute, setAttribute} from '@oscarpalmer/toretto/attribute';
6
+ import {createElement} from '@oscarpalmer/toretto/create';
6
7
  import {getEventPosition, on} from '@oscarpalmer/toretto/event';
7
8
  import {findAncestor} from '@oscarpalmer/toretto/find';
8
9
  import {setStyle, toggleStyles} from '@oscarpalmer/toretto/style';
@@ -238,28 +239,30 @@ type OuiSplitterValuesNow = {
238
239
  // #region Functions
239
240
 
240
241
  function createHandle(): HTMLSpanElement {
241
- const handle = document.createElement('span');
242
-
243
- setAria(handle, 'hidden', 'true');
244
- setAttribute(handle, ATTRIBUTE_HANDLE, '');
245
-
246
- return handle;
242
+ return createElement('span', {
243
+ aria: {
244
+ hidden: true,
245
+ },
246
+ attribute: {
247
+ [ATTRIBUTE_HANDLE]: '',
248
+ },
249
+ });
247
250
  }
248
251
 
249
252
  function createSeparator(splitter: OuiSplitter): HTMLDivElement {
250
- const separator = document.createElement('div');
251
-
252
- separator.role = 'separator';
253
- separator.tabIndex = 0;
254
-
255
- setAria(separator, {
256
- controls: splitter.element.id,
257
- label: 'Resize panels',
253
+ return createElement('div', {
254
+ aria: {
255
+ controls: splitter.element.id,
256
+ label: 'Resize panels',
257
+ },
258
+ attribute: {
259
+ [ATTRIBUTE_SEPARATOR]: '',
260
+ },
261
+ property: {
262
+ role: 'separator',
263
+ tabIndex: 0,
264
+ },
258
265
  });
259
-
260
- setAttribute(separator, ATTRIBUTE_SEPARATOR, '');
261
-
262
- return separator;
263
266
  }
264
267
 
265
268
  function getContained(min: number, value: number, max: number): number {