@oscarpalmer/oui 0.36.0 → 0.38.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.
- package/dist/css/a11y.css +1 -0
- package/dist/css/badge.css +19 -15
- package/dist/css/button.css +40 -31
- package/dist/css/color-picker.css +377 -0
- package/dist/css/color.css +20 -21
- package/dist/css/combobox.css +140 -34
- package/dist/css/content.css +30 -10
- package/dist/css/floatable.css +12 -10
- package/dist/css/form.css +400 -129
- package/dist/css/listbox.css +43 -17
- package/dist/css/message.css +15 -10
- package/dist/css/mixins/badge.mixins.css +2 -0
- package/dist/css/mixins/button.mixins.css +2 -0
- package/dist/css/mixins/message.mixins.css +1 -0
- package/dist/css/mixins/misc.mixins.css +2 -0
- package/dist/css/mixins/shadow.mixins.css +1 -0
- package/dist/css/reset.css +31 -90
- package/dist/css/splitter.css +3 -3
- package/dist/css/tabs.css +103 -0
- package/dist/js/color-picker.d.mts +213 -0
- package/dist/js/color-picker.mjs +924 -0
- package/dist/js/combobox/dom.combobox.mjs +8 -4
- package/dist/js/combobox/event.combobox.mjs +1 -1
- package/dist/js/combobox/index.d.mts +1 -1
- package/dist/js/combobox/index.mjs +56 -2
- package/dist/js/combobox/misc.combobox.d.mts +1 -1
- package/dist/js/combobox/misc.combobox.mjs +1 -1
- package/dist/js/combobox/state.combobox.d.mts +1 -1
- package/dist/js/combobox/state.combobox.mjs +1 -1
- package/dist/js/dialog.mjs +2 -2
- package/dist/js/floatable/floatable.embedded.mjs +13 -10
- package/dist/js/focus-trap/focus-trap.embedded.mjs +9 -13
- package/dist/js/{index-EfkUSals.d.mts → index-DJdFlTLm.d.mts} +39 -1
- package/dist/js/index.d.mts +4 -2
- package/dist/js/index.mjs +5 -3
- package/dist/js/internal/draggable.mjs +20 -26
- package/dist/js/internal/listbox/listbox.data.mjs +1 -1
- package/dist/js/internal/listbox/listbox.dom.mjs +1 -1
- package/dist/js/internal/listbox/listbox.event.mjs +1 -1
- package/dist/js/internal/listbox/listbox.form.mjs +17 -16
- package/dist/js/internal/listbox/listbox.misc.mjs +1 -1
- package/dist/js/internal/listbox/listbox.state.mjs +4 -4
- package/dist/js/internal/navigable.d.mts +11 -5
- package/dist/js/internal/navigable.mjs +46 -19
- package/dist/js/listbox/event.listbox.mjs +1 -1
- package/dist/js/listbox/index.d.mts +38 -0
- package/dist/js/listbox/index.mjs +56 -2
- package/dist/js/listbox/misc.listbox.mjs +1 -1
- package/dist/js/listbox/state.listbox.mjs +1 -1
- package/dist/js/{listbox.data-BWd0PCy7.mjs → listbox.data-C7CRa5Ya.mjs} +5 -4
- package/dist/js/menu.mjs +1 -1
- package/dist/js/{misc.listbox-BI-XsTOf.mjs → misc.listbox-Cyz2CRDy.mjs} +2 -3
- package/dist/js/movable/movable.embedded.mjs +5 -8
- package/dist/js/popover.mjs +2 -2
- package/dist/js/resizable/resizable.embedded.mjs +21 -31
- package/dist/js/sortable/sortable.embedded.mjs +4 -4
- package/dist/js/splitter.mjs +20 -17
- package/dist/js/{state.combobox-4xq0FPCF.mjs → state.combobox-Qm3FWzYW.mjs} +3 -3
- package/dist/js/tabs.d.mts +25 -0
- package/dist/js/tabs.mjs +237 -0
- package/dist/js/tooltip.mjs +16 -15
- package/package.json +7 -5
- package/src/css/a11y.scss +2 -2
- package/src/css/badge.scss +8 -20
- package/src/css/button.scss +8 -47
- package/src/css/color-picker.scss +344 -0
- package/src/css/color.scss +20 -22
- package/src/css/combobox.scss +29 -57
- package/src/css/content.scss +34 -6
- package/src/css/floatable.scss +22 -19
- package/src/css/form.scss +94 -80
- package/src/css/listbox.scss +6 -34
- package/src/css/message.scss +16 -30
- package/src/css/mixins/badge.mixins.scss +53 -0
- package/src/css/mixins/button.mixins.scss +112 -0
- package/src/css/mixins/input.mixins.scss +114 -0
- package/src/css/mixins/message.mixins.scss +41 -0
- package/src/css/mixins/misc.mixins.scss +48 -0
- package/src/css/mixins/shadow.mixins.scss +57 -0
- package/src/css/reset.scss +39 -88
- package/src/css/splitter.scss +3 -3
- package/src/css/tabs.scss +74 -0
- package/src/js/color-picker.ts +1653 -0
- package/src/js/combobox/dom.combobox.ts +4 -0
- package/src/js/combobox/index.ts +63 -1
- package/src/js/dialog.ts +1 -1
- package/src/js/floatable/floatable.embedded.ts +18 -14
- package/src/js/focus-trap/focus-trap.embedded.ts +11 -19
- package/src/js/index.ts +2 -0
- package/src/js/internal/draggable.ts +29 -33
- package/src/js/internal/listbox/listbox.dom.ts +2 -1
- package/src/js/internal/listbox/listbox.form.ts +32 -22
- package/src/js/internal/listbox/listbox.state.ts +3 -3
- package/src/js/internal/navigable.ts +82 -23
- package/src/js/listbox/index.ts +62 -0
- package/src/js/listbox/state.listbox.ts +0 -2
- package/src/js/movable/movable.embedded.ts +11 -13
- package/src/js/popover.ts +1 -1
- package/src/js/resizable/resizable.embedded.ts +25 -39
- package/src/js/splitter.ts +21 -18
- package/src/js/tabs.ts +441 -0
- package/src/js/tooltip.ts +20 -17
- package/src/css/mixins.scss +0 -194
- /package/dist/css/{mixins.css → mixins/input.mixins.css} +0 -0
package/src/js/tabs.ts
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import {getAria, setAria} from '@oscarpalmer/toretto/aria';
|
|
2
|
+
import {getAttribute, setAttribute} from '@oscarpalmer/toretto/attribute';
|
|
3
|
+
import {createElement} from '@oscarpalmer/toretto/create';
|
|
4
|
+
import {
|
|
5
|
+
getNavigableOrientation,
|
|
6
|
+
OuiNavigable,
|
|
7
|
+
type OuiNavigableOrientation,
|
|
8
|
+
} from './internal/navigable';
|
|
9
|
+
|
|
10
|
+
// #region Types
|
|
11
|
+
|
|
12
|
+
declare global {
|
|
13
|
+
interface HTMLElementTagNameMap {
|
|
14
|
+
[TAGNAME]: OuiTabsElement;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class OuiTabsEvent extends Event {
|
|
19
|
+
constructor(
|
|
20
|
+
name: 'oui:beforechange' | 'oui:change',
|
|
21
|
+
public oldIndex: number,
|
|
22
|
+
public newIndex: number,
|
|
23
|
+
cancelable: boolean,
|
|
24
|
+
) {
|
|
25
|
+
super(name, {
|
|
26
|
+
cancelable,
|
|
27
|
+
bubbles: true,
|
|
28
|
+
composed: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type OuiTabsContent = {
|
|
34
|
+
element: HTMLDivElement;
|
|
35
|
+
panels: OuiTabsPanels;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export class OuiTabsElement extends HTMLElement {
|
|
39
|
+
static observedAttributes = ['active'];
|
|
40
|
+
|
|
41
|
+
#state?: OuiTabsState;
|
|
42
|
+
|
|
43
|
+
get active(): number {
|
|
44
|
+
return this.#state?.active ?? 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set active(value: number) {
|
|
48
|
+
setActive(this.#state, value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get panel(): HTMLElement {
|
|
52
|
+
return this.#state?.panels.elements[this.active] as HTMLElement;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get tab(): HTMLButtonElement {
|
|
56
|
+
return this.#state?.tabList.tabs[this.active] as HTMLButtonElement;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
attributeChangedCallback(name: string, _: string | null, value: string | null): void {
|
|
60
|
+
switch (name) {
|
|
61
|
+
case 'active':
|
|
62
|
+
setActive(this.#state, value);
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
default:
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
connectedCallback(): void {
|
|
71
|
+
if (this.#state == null) {
|
|
72
|
+
this.#state = initializeTabs(this);
|
|
73
|
+
} else {
|
|
74
|
+
attachTabs(this.#state);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
disconnectedCallback(): void {
|
|
79
|
+
if (this.#state != null) {
|
|
80
|
+
detachTabs(this.#state);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type OuiTabsPanels = {
|
|
86
|
+
elements: HTMLElement[];
|
|
87
|
+
hidden: Array<boolean | 'until-found'>;
|
|
88
|
+
roles: Array<string | null>;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type OuiTabsState = {
|
|
92
|
+
active: number;
|
|
93
|
+
content: HTMLDivElement;
|
|
94
|
+
host: OuiTabsElement;
|
|
95
|
+
id: string;
|
|
96
|
+
navigable?: OuiNavigable;
|
|
97
|
+
orientation: OuiNavigableOrientation;
|
|
98
|
+
panels: OuiTabsPanels;
|
|
99
|
+
tabList: OuiTabsTabList;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
type OuiTabsTabList = {
|
|
103
|
+
element: HTMLDivElement;
|
|
104
|
+
tabs: HTMLButtonElement[];
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// #endregion
|
|
108
|
+
|
|
109
|
+
// #region Functions
|
|
110
|
+
|
|
111
|
+
function attachTabs(state: OuiTabsState): void {
|
|
112
|
+
const navigable = new OuiNavigable(state.tabList.element, {
|
|
113
|
+
orientation: state.orientation,
|
|
114
|
+
selector: SELECTOR_TAB,
|
|
115
|
+
vertical: false,
|
|
116
|
+
onActivate: navigable => {
|
|
117
|
+
const index = state.tabList.tabs.indexOf(navigable.active.element as HTMLButtonElement);
|
|
118
|
+
|
|
119
|
+
if (index > -1 && index !== state.active) {
|
|
120
|
+
onActivate(state, index);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
state.navigable = navigable;
|
|
126
|
+
|
|
127
|
+
const {length} = state.panels.elements;
|
|
128
|
+
|
|
129
|
+
for (let index = 0; index < length; index += 1) {
|
|
130
|
+
const panel = state.panels.elements[index];
|
|
131
|
+
|
|
132
|
+
panel.hidden = index !== state.active;
|
|
133
|
+
panel.role = 'tabpanel';
|
|
134
|
+
|
|
135
|
+
if (index === 0) {
|
|
136
|
+
panel.insertAdjacentElement('beforebegin', state.tabList.element);
|
|
137
|
+
panel.insertAdjacentElement('beforebegin', state.content);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
state.content.append(panel);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function createContent(prefix: string, panels: HTMLElement[], active: number): OuiTabsContent {
|
|
145
|
+
const content = createElement('div', {
|
|
146
|
+
attribute: {
|
|
147
|
+
[`${TAGNAME}-content`]: '',
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const {length} = panels;
|
|
152
|
+
|
|
153
|
+
const hidden: Array<boolean | 'until-found'> = [];
|
|
154
|
+
const roles: Array<string | null> = [];
|
|
155
|
+
|
|
156
|
+
for (let index = 0; index < length; index += 1) {
|
|
157
|
+
const panel = panels[index];
|
|
158
|
+
|
|
159
|
+
hidden.push(panel.hidden);
|
|
160
|
+
roles.push(panel.role);
|
|
161
|
+
|
|
162
|
+
panel.hidden = index !== active;
|
|
163
|
+
|
|
164
|
+
if (panel.id === '') {
|
|
165
|
+
panel.id = `${prefix}_panel_${index}`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
element: content,
|
|
171
|
+
panels: {
|
|
172
|
+
hidden,
|
|
173
|
+
roles,
|
|
174
|
+
elements: panels,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function createTab(
|
|
180
|
+
prefix: string,
|
|
181
|
+
index: number,
|
|
182
|
+
panel: HTMLElement,
|
|
183
|
+
label: string,
|
|
184
|
+
selected: boolean,
|
|
185
|
+
): HTMLButtonElement {
|
|
186
|
+
return createElement('button', {
|
|
187
|
+
aria: {
|
|
188
|
+
selected,
|
|
189
|
+
controls: panel.id,
|
|
190
|
+
},
|
|
191
|
+
attribute: {
|
|
192
|
+
[`${TAGNAME}-tab`]: '',
|
|
193
|
+
},
|
|
194
|
+
property: {
|
|
195
|
+
id: `${prefix}_tab_${index}`,
|
|
196
|
+
role: 'tab',
|
|
197
|
+
tabIndex: selected ? 0 : -1,
|
|
198
|
+
textContent: label,
|
|
199
|
+
type: 'button',
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function createTabList(
|
|
205
|
+
prefix: string,
|
|
206
|
+
panels: HTMLElement[],
|
|
207
|
+
labels: string[],
|
|
208
|
+
active: number,
|
|
209
|
+
): OuiTabsTabList {
|
|
210
|
+
const element = createElement('div', {
|
|
211
|
+
attribute: {
|
|
212
|
+
[`${TAGNAME}-tablist`]: '',
|
|
213
|
+
},
|
|
214
|
+
property: {
|
|
215
|
+
role: 'tablist',
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const {length} = panels;
|
|
220
|
+
|
|
221
|
+
const tabs: HTMLButtonElement[] = [];
|
|
222
|
+
|
|
223
|
+
for (let index = 0; index < length; index += 1) {
|
|
224
|
+
const tab = createTab(prefix, index, panels[index], labels[index], index === active);
|
|
225
|
+
|
|
226
|
+
element.append(tab);
|
|
227
|
+
tabs.push(tab);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
element,
|
|
232
|
+
tabs,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function detachTabs(state: OuiTabsState): void {
|
|
237
|
+
state.navigable?.destroy();
|
|
238
|
+
|
|
239
|
+
const {length} = state.panels.elements;
|
|
240
|
+
|
|
241
|
+
for (let index = 0; index < length; index += 1) {
|
|
242
|
+
const panel = state.panels.elements[index];
|
|
243
|
+
|
|
244
|
+
panel.hidden = state.panels.hidden[index];
|
|
245
|
+
panel.role = state.panels.roles[index];
|
|
246
|
+
|
|
247
|
+
state.content.before(panel);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
state.tabList.element.remove();
|
|
251
|
+
state.content.remove();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function getActive(element: OuiTabsElement, max: number): number {
|
|
255
|
+
const attribute = getAttribute(element, 'active');
|
|
256
|
+
|
|
257
|
+
let index = 0;
|
|
258
|
+
|
|
259
|
+
if (attribute != null) {
|
|
260
|
+
const value = Number.parseInt(attribute, 10);
|
|
261
|
+
|
|
262
|
+
if (!Number.isNaN(value) && value >= 0) {
|
|
263
|
+
index = value > max ? max : value;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return index;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function getId(): string {
|
|
271
|
+
index += 1;
|
|
272
|
+
|
|
273
|
+
return `oui_tabs_${index}`;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function getLabels(panels: HTMLElement[]): string[] | undefined {
|
|
277
|
+
const labels: string[] = [];
|
|
278
|
+
|
|
279
|
+
const {length} = panels;
|
|
280
|
+
|
|
281
|
+
for (let index = 0; index < length; index += 1) {
|
|
282
|
+
const panel = panels[index];
|
|
283
|
+
|
|
284
|
+
const labelledBy = getAria(panel, 'labelledby');
|
|
285
|
+
|
|
286
|
+
if (typeof labelledBy === 'string' && labelledBy.trim().length > 0) {
|
|
287
|
+
const label: string[] = [];
|
|
288
|
+
const selectors = labelledBy.split(/\s+/);
|
|
289
|
+
|
|
290
|
+
for (const selector of selectors) {
|
|
291
|
+
const element = document.getElementById(selector);
|
|
292
|
+
|
|
293
|
+
if (element == null) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
label.push(element.textContent);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
labels.push(label.join(' '));
|
|
301
|
+
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const label = getAria(panel, 'label');
|
|
306
|
+
|
|
307
|
+
if (typeof label === 'string' && label.trim().length > 0) {
|
|
308
|
+
labels.push(label);
|
|
309
|
+
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return labels;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function initializeTabs(element: OuiTabsElement): OuiTabsState {
|
|
320
|
+
const panels = [...element.querySelectorAll(SELECTOR_PANEL)] as HTMLElement[];
|
|
321
|
+
|
|
322
|
+
if (panels.length === 0) {
|
|
323
|
+
throw new Error(MESSAGE_EMPTY);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const labels = getLabels(panels);
|
|
327
|
+
|
|
328
|
+
if (labels == null) {
|
|
329
|
+
throw new Error(MESSAGE_INVALID);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
let id: string;
|
|
333
|
+
|
|
334
|
+
if (element.id === '') {
|
|
335
|
+
id = getId();
|
|
336
|
+
} else {
|
|
337
|
+
id = element.id;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const active = getActive(element, panels.length - 1);
|
|
341
|
+
const orientation = getNavigableOrientation(element, false, false);
|
|
342
|
+
|
|
343
|
+
const content = createContent(id, panels, active);
|
|
344
|
+
const tabList = createTabList(id, panels, labels, active);
|
|
345
|
+
|
|
346
|
+
const state: OuiTabsState = {
|
|
347
|
+
active,
|
|
348
|
+
id,
|
|
349
|
+
orientation,
|
|
350
|
+
tabList,
|
|
351
|
+
content: content.element,
|
|
352
|
+
host: element,
|
|
353
|
+
panels: content.panels,
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
attachTabs(state);
|
|
357
|
+
|
|
358
|
+
return state;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function onActivate(state: OuiTabsState, next: number): void {
|
|
362
|
+
const current = state.active;
|
|
363
|
+
|
|
364
|
+
const event = new OuiTabsEvent('oui:beforechange', current, next, true);
|
|
365
|
+
|
|
366
|
+
state.host.dispatchEvent(event);
|
|
367
|
+
|
|
368
|
+
if (event.defaultPrevented) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
state.active = next;
|
|
373
|
+
|
|
374
|
+
const {length} = state.panels.elements;
|
|
375
|
+
|
|
376
|
+
for (let index = 0; index < length; index += 1) {
|
|
377
|
+
const panel = state.panels.elements[index];
|
|
378
|
+
|
|
379
|
+
panel.hidden = index !== next;
|
|
380
|
+
|
|
381
|
+
setAria(state.tabList.tabs[index], 'selected', index === next);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
setAttribute(state.host, 'active', next);
|
|
385
|
+
|
|
386
|
+
state.host.dispatchEvent(new OuiTabsEvent('oui:change', current, next, false));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function setActive(state: OuiTabsState | undefined, value: unknown): void {
|
|
390
|
+
if (state == null) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const max = state.panels.elements.length - 1;
|
|
395
|
+
|
|
396
|
+
let index: number | undefined;
|
|
397
|
+
|
|
398
|
+
if (typeof value === 'number' && !Number.isNaN(value) && value >= 0) {
|
|
399
|
+
index = value > max ? max : value;
|
|
400
|
+
} else if (typeof value === 'string') {
|
|
401
|
+
const parsed = Number.parseInt(value, 10);
|
|
402
|
+
|
|
403
|
+
if (!Number.isNaN(parsed) && parsed >= 0) {
|
|
404
|
+
index = parsed > max ? max : parsed;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (index == null) {
|
|
409
|
+
setAttribute(state.host, 'active', state.active);
|
|
410
|
+
} else if (index !== state.active) {
|
|
411
|
+
state.navigable?.navigate(index, false);
|
|
412
|
+
|
|
413
|
+
onActivate(state, index);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// #endregion
|
|
418
|
+
|
|
419
|
+
// #region Variables
|
|
420
|
+
|
|
421
|
+
const TAGNAME = 'oui-tabs';
|
|
422
|
+
|
|
423
|
+
const ATTRIBUTE_PANEL = `${TAGNAME}-panel`;
|
|
424
|
+
|
|
425
|
+
const MESSAGE_EMPTY = `<${TAGNAME}> must contain at least one [${ATTRIBUTE_PANEL}] child element`;
|
|
426
|
+
|
|
427
|
+
const MESSAGE_INVALID = `A [${ATTRIBUTE_PANEL}] child element of <${TAGNAME}> must have a valid 'aria-label' or 'aria-labelledby' attribute`;
|
|
428
|
+
|
|
429
|
+
const SELECTOR_PANEL = `:scope > [${ATTRIBUTE_PANEL}]`;
|
|
430
|
+
|
|
431
|
+
const SELECTOR_TAB = `[${TAGNAME}-tab]`;
|
|
432
|
+
|
|
433
|
+
let index = 0;
|
|
434
|
+
|
|
435
|
+
// #endregion
|
|
436
|
+
|
|
437
|
+
// #region Initialization
|
|
438
|
+
|
|
439
|
+
customElements.define(TAGNAME, OuiTabsElement);
|
|
440
|
+
|
|
441
|
+
// #endregion
|
package/src/js/tooltip.ts
CHANGED
|
@@ -182,15 +182,16 @@ function findElements(attribute?: string): HTMLElement[] | undefined {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function getContent(): HTMLElement {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
return createElement('div', {
|
|
186
|
+
attribute: {
|
|
187
|
+
[ATTRIBUTE_CONTENT]: '',
|
|
188
|
+
popover: 'hint',
|
|
189
|
+
},
|
|
190
|
+
property: {
|
|
191
|
+
role: 'tooltip',
|
|
192
|
+
tabIndex: -1,
|
|
193
|
+
},
|
|
189
194
|
});
|
|
190
|
-
|
|
191
|
-
setAttribute(content, ATTRIBUTE_CONTENT, '');
|
|
192
|
-
|
|
193
|
-
return content;
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
function getElements(anchor: HTMLElement): HTMLElement[] | undefined {
|
|
@@ -204,21 +205,23 @@ function getElements(anchor: HTMLElement): HTMLElement[] | undefined {
|
|
|
204
205
|
return elements as HTMLElement[];
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
let
|
|
208
|
+
let textContent = getAria(anchor, 'label');
|
|
208
209
|
|
|
209
|
-
if (isNullableOrWhitespace(
|
|
210
|
-
|
|
210
|
+
if (isNullableOrWhitespace(textContent)) {
|
|
211
|
+
textContent = getAria(anchor, 'description');
|
|
211
212
|
}
|
|
212
213
|
|
|
213
|
-
if (isNullableOrWhitespace(
|
|
214
|
+
if (isNullableOrWhitespace(textContent)) {
|
|
214
215
|
return;
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
218
|
+
return [
|
|
219
|
+
createElement('p', {
|
|
220
|
+
property: {
|
|
221
|
+
textContent,
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
224
|
+
];
|
|
222
225
|
}
|
|
223
226
|
|
|
224
227
|
function getState(anchor: HTMLElement, elements: HTMLElement[]): OuiTooltipState {
|
package/src/css/mixins.scss
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
@mixin badge() {
|
|
2
|
-
--oui-shadow-mixed: color-mix(in oklab, var(--oui-shadow, var(--oui-gray-6)), transparent 92.5%);
|
|
3
|
-
|
|
4
|
-
@include shadow(var(--oui-shadow-mixed));
|
|
5
|
-
|
|
6
|
-
display: inline-flex;
|
|
7
|
-
flex-flow: row nowrap;
|
|
8
|
-
gap: 0.5em;
|
|
9
|
-
background-color: color-mix(in oklab, var(--oui-background, var(--oui-gray-0)), transparent 25%);
|
|
10
|
-
color: var(--oui-foreground, var(--oui-gray-8));
|
|
11
|
-
line-height: 1.25;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
@mixin button() {
|
|
15
|
-
--oui-background-percentage: 25%;
|
|
16
|
-
--oui-foreground-percentage: 0%;
|
|
17
|
-
--oui-outline-percentage: 100%;
|
|
18
|
-
--oui-shadow-inset: color-mix(in oklab, white, transparent 75%);
|
|
19
|
-
--oui-shadow-percentage: 82.5%;
|
|
20
|
-
|
|
21
|
-
--oui-shadow-value: color-mix(
|
|
22
|
-
in oklab,
|
|
23
|
-
var(--oui-outline-value, var(--oui-gray-6)),
|
|
24
|
-
transparent var(--oui-shadow-percentage)
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
@include shadow(var(--oui-shadow-value), var(--oui-shadow-inset));
|
|
28
|
-
|
|
29
|
-
padding: 0.5em 0.75em;
|
|
30
|
-
display: inline-flex;
|
|
31
|
-
flex-flow: row wrap;
|
|
32
|
-
gap: 0.75em;
|
|
33
|
-
align-items: center;
|
|
34
|
-
border-radius: 0.25em;
|
|
35
|
-
background-color: color-mix(
|
|
36
|
-
in oklab,
|
|
37
|
-
var(--oui-background-value, var(--oui-gray-2)),
|
|
38
|
-
transparent var(--oui-background-percentage)
|
|
39
|
-
);
|
|
40
|
-
outline: 4px solid
|
|
41
|
-
color-mix(
|
|
42
|
-
in oklab,
|
|
43
|
-
var(--oui-outline-value, var(--oui-gray-6)),
|
|
44
|
-
transparent var(--oui-outline-percentage)
|
|
45
|
-
);
|
|
46
|
-
border: none;
|
|
47
|
-
color: color-mix(
|
|
48
|
-
in oklab,
|
|
49
|
-
var(--oui-foreground-value, var(--oui-gray-8)),
|
|
50
|
-
transparent var(--oui-foreground-percentage)
|
|
51
|
-
);
|
|
52
|
-
line-height: 1.25;
|
|
53
|
-
transition: 0.125s ease-in-out;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@mixin card(
|
|
57
|
-
$backgroundColor: var(--oui-absolute),
|
|
58
|
-
$boxShadowColor: color-mix(in oklab, var(--oui-gray-6), transparent 92.5%)
|
|
59
|
-
) {
|
|
60
|
-
@include shadow($boxShadowColor);
|
|
61
|
-
|
|
62
|
-
padding: 1em 1.25em;
|
|
63
|
-
background-color: $backgroundColor;
|
|
64
|
-
border-radius: 0.5em;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
@mixin floatable() {
|
|
68
|
-
--margin-bottom: 0.5em;
|
|
69
|
-
--margin-left: 0.5em;
|
|
70
|
-
--margin-right: 0.5em;
|
|
71
|
-
--margin-top: 0.5em;
|
|
72
|
-
|
|
73
|
-
inset-block: var(--margin-top) var(--margin-bottom);
|
|
74
|
-
inset-inline: var(--margin-left) var(--margin-right);
|
|
75
|
-
|
|
76
|
-
&[oui-position$='bottom'] {
|
|
77
|
-
--margin-bottom: 0;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
&[oui-position$='end'] {
|
|
81
|
-
--margin-right: 0;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
&[oui-position$='start'] {
|
|
85
|
-
--margin-left: 0;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
&[oui-position$='top'] {
|
|
89
|
-
--margin-top: 0;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
@mixin input {
|
|
94
|
-
--oui-background-percentage: 0%;
|
|
95
|
-
--oui-foreground-percentage: 0%;
|
|
96
|
-
|
|
97
|
-
@include input-outlined;
|
|
98
|
-
|
|
99
|
-
align-content: center;
|
|
100
|
-
background-color: color-mix(
|
|
101
|
-
in oklab,
|
|
102
|
-
var(--oui-background-value),
|
|
103
|
-
transparent var(--oui-background-percentage)
|
|
104
|
-
);
|
|
105
|
-
border: 1px solid var(--oui-border-value, var(--oui-gray-3));
|
|
106
|
-
box-shadow: inset 0 2px 4px -1px var(--oui-gray-3);
|
|
107
|
-
color: color-mix(
|
|
108
|
-
in oklab,
|
|
109
|
-
var(--oui-foreground-value, inherit),
|
|
110
|
-
transparent var(--oui-foreground-percentage)
|
|
111
|
-
);
|
|
112
|
-
-webkit-text-fill-color: color-mix(
|
|
113
|
-
in oklab,
|
|
114
|
-
var(--oui-foreground-value, inherit),
|
|
115
|
-
transparent var(--oui-foreground-percentage)
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@mixin input-focus() {
|
|
120
|
-
--oui-border-value: var(--oui-blue-5);
|
|
121
|
-
--oui-foreground-value: inherit;
|
|
122
|
-
--oui-outline-percentage: 75%;
|
|
123
|
-
--oui-outline-value: var(--oui-blue-6);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
@mixin input-hover() {
|
|
127
|
-
--oui-border-value: var(--oui-blue-4);
|
|
128
|
-
--oui-foreground-percentage: 0%;
|
|
129
|
-
--oui-foreground-value: inherit;
|
|
130
|
-
--oui-outline-percentage: 90%;
|
|
131
|
-
--oui-outline-value: var(--oui-blue-6);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@mixin input-invalid() {
|
|
135
|
-
--oui-border-value: var(--oui-red-5);
|
|
136
|
-
--oui-foreground-value: var(--oui-red-9);
|
|
137
|
-
--oui-outline-percentage: 82.5%;
|
|
138
|
-
--oui-outline-value: var(--oui-red-6);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
@mixin input-outlined {
|
|
142
|
-
--oui-outline-percentage: 100%;
|
|
143
|
-
--oui-outline-value: var(--oui-blue-6);
|
|
144
|
-
|
|
145
|
-
outline: 4px solid
|
|
146
|
-
color-mix(in oklab, var(--oui-outline-value), transparent var(--oui-outline-percentage));
|
|
147
|
-
outline-offset: 0;
|
|
148
|
-
transition: 0.125s ease-in-out;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
@mixin input-valid() {
|
|
152
|
-
--oui-border-value: var(--oui-green-5);
|
|
153
|
-
--oui-foreground-value: var(--oui-green-9);
|
|
154
|
-
--oui-outline-percentage: 82.5%;
|
|
155
|
-
--oui-outline-value: var(--oui-green-6);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
@mixin shadow($color: rgb(0 0 0 / 5%), $inset: transparent) {
|
|
159
|
-
box-shadow:
|
|
160
|
-
inset 0 1px 0 0 $inset,
|
|
161
|
-
0 0 0 1px $color,
|
|
162
|
-
0 1px 2px -0.5px $color,
|
|
163
|
-
0 2px 4px -1px $color;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
@mixin shadow-overlay($color: rgb(0 0 0 / 5%), $inset: transparent) {
|
|
167
|
-
box-shadow:
|
|
168
|
-
inset 0 1px 0 0 $inset,
|
|
169
|
-
0 0 0 1px $color,
|
|
170
|
-
0 1px 2px -0.5px $color,
|
|
171
|
-
0 2px 4px -1px $color,
|
|
172
|
-
0 4px 8px -2px $color,
|
|
173
|
-
0 8px 16px -4px $color,
|
|
174
|
-
0 16px 32px -8px $color,
|
|
175
|
-
0 32px 64px -16px $color,
|
|
176
|
-
0 64px 128px -32px $color;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
@mixin shadow-small($color: rgb(0 0 0 / 5%), $inset: transparent) {
|
|
180
|
-
box-shadow:
|
|
181
|
-
inset 0 1px 0 0 $inset,
|
|
182
|
-
0 0 0 1px $color,
|
|
183
|
-
0 1px 2px -0.5px $color;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
@mixin visually-hidden() {
|
|
187
|
-
width: 1px !important;
|
|
188
|
-
height: 1px !important;
|
|
189
|
-
padding: 0 !important;
|
|
190
|
-
clip-path: inset(50%) !important;
|
|
191
|
-
overflow: hidden !important;
|
|
192
|
-
border: 0 !important;
|
|
193
|
-
white-space: nowrap !important;
|
|
194
|
-
}
|
|
File without changes
|