@lmfaole/basics 0.4.0 → 0.5.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/LICENSE +21 -0
- package/README.md +78 -499
- package/basic-components/basic-accordion/README.md +53 -0
- package/{components → basic-components}/basic-accordion/index.js +59 -37
- package/basic-components/basic-alert/README.md +48 -0
- package/basic-components/basic-carousel/README.md +108 -0
- package/basic-components/basic-carousel/index.d.ts +73 -0
- package/basic-components/basic-carousel/index.js +255 -0
- package/basic-components/basic-carousel/register.js +3 -0
- package/basic-components/basic-dialog/README.md +57 -0
- package/basic-components/basic-popover/README.md +56 -0
- package/basic-components/basic-summary-table/README.md +93 -0
- package/basic-components/basic-table/README.md +89 -0
- package/basic-components/basic-tabs/README.md +63 -0
- package/basic-components/basic-toast/README.md +62 -0
- package/{components → basic-components}/basic-toast/index.d.ts +3 -0
- package/{components → basic-components}/basic-toast/index.js +264 -3
- package/basic-components/basic-toc/README.md +43 -0
- package/basic-components/basic-toc/register.d.ts +1 -0
- package/basic-styling/components/basic-accordion.css +38 -4
- package/basic-styling/components/basic-carousel.css +183 -0
- package/basic-styling/components/basic-popover.css +2 -4
- package/basic-styling/components/basic-summary-table.css +27 -5
- package/basic-styling/components/basic-table.css +22 -4
- package/basic-styling/components/basic-tabs.css +26 -10
- package/basic-styling/components.css +2 -0
- package/basic-styling/forms.css +55 -0
- package/basic-styling/global.css +1 -0
- package/basic-styling/interaction.css +90 -0
- package/basic-styling/tokens/palette.css +112 -0
- package/basic-styling/tokens/palette.tokens.json +768 -0
- package/index.d.ts +10 -9
- package/index.js +10 -9
- package/package.json +49 -29
- package/readme.mdx +0 -6
- /package/{components → basic-components}/basic-accordion/index.d.ts +0 -0
- /package/{components → basic-components}/basic-accordion/register.d.ts +0 -0
- /package/{components → basic-components}/basic-accordion/register.js +0 -0
- /package/{components → basic-components}/basic-alert/index.d.ts +0 -0
- /package/{components → basic-components}/basic-alert/index.js +0 -0
- /package/{components → basic-components}/basic-alert/register.d.ts +0 -0
- /package/{components → basic-components}/basic-alert/register.js +0 -0
- /package/{components/basic-dialog → basic-components/basic-carousel}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-dialog/index.d.ts +0 -0
- /package/{components → basic-components}/basic-dialog/index.js +0 -0
- /package/{components/basic-popover → basic-components/basic-dialog}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-dialog/register.js +0 -0
- /package/{components → basic-components}/basic-popover/index.d.ts +0 -0
- /package/{components → basic-components}/basic-popover/index.js +0 -0
- /package/{components/basic-summary-table → basic-components/basic-popover}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-popover/register.js +0 -0
- /package/{components → basic-components}/basic-summary-table/index.d.ts +0 -0
- /package/{components → basic-components}/basic-summary-table/index.js +0 -0
- /package/{components/basic-table → basic-components/basic-summary-table}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-summary-table/register.js +0 -0
- /package/{components → basic-components}/basic-table/index.d.ts +0 -0
- /package/{components → basic-components}/basic-table/index.js +0 -0
- /package/{components/basic-tabs → basic-components/basic-table}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-table/register.js +0 -0
- /package/{components → basic-components}/basic-tabs/index.d.ts +0 -0
- /package/{components → basic-components}/basic-tabs/index.js +0 -0
- /package/{components/basic-toast → basic-components/basic-tabs}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-tabs/register.js +0 -0
- /package/{components/basic-toc → basic-components/basic-toast}/register.d.ts +0 -0
- /package/{components → basic-components}/basic-toast/register.js +0 -0
- /package/{components → basic-components}/basic-toc/index.d.ts +0 -0
- /package/{components → basic-components}/basic-toc/index.js +0 -0
- /package/{components → basic-components}/basic-toc/register.js +0 -0
|
@@ -11,9 +11,36 @@ const PANEL_SELECTOR = "[data-toast-panel]";
|
|
|
11
11
|
const TITLE_SELECTOR = "[data-toast-title]";
|
|
12
12
|
const OPEN_SELECTOR = "[data-toast-open]";
|
|
13
13
|
const CLOSE_SELECTOR = "[data-toast-close]";
|
|
14
|
+
const ANNOUNCER_ATTRIBUTE = "data-basic-toast-announcer";
|
|
14
15
|
const MANAGED_LABEL_ATTRIBUTE = "data-basic-toast-managed-label";
|
|
15
16
|
const MANAGED_LABELLEDBY_ATTRIBUTE = "data-basic-toast-managed-labelledby";
|
|
16
17
|
const MANAGED_POPOVER_ATTRIBUTE = "data-basic-toast-managed-popover";
|
|
18
|
+
const INTERACTIVE_PANEL_SELECTOR = [
|
|
19
|
+
"a[href]",
|
|
20
|
+
"area[href]",
|
|
21
|
+
"button",
|
|
22
|
+
"input",
|
|
23
|
+
"select",
|
|
24
|
+
"textarea",
|
|
25
|
+
"summary",
|
|
26
|
+
"iframe",
|
|
27
|
+
"audio[controls]",
|
|
28
|
+
"video[controls]",
|
|
29
|
+
"[contenteditable]:not([contenteditable=\"false\"])",
|
|
30
|
+
"[tabindex]:not([tabindex=\"-1\"])",
|
|
31
|
+
].join(", ");
|
|
32
|
+
const VISUALLY_HIDDEN_ANNOUNCER_STYLE = [
|
|
33
|
+
"position:absolute",
|
|
34
|
+
"inline-size:1px",
|
|
35
|
+
"block-size:1px",
|
|
36
|
+
"margin:-1px",
|
|
37
|
+
"padding:0",
|
|
38
|
+
"overflow:hidden",
|
|
39
|
+
"clip:rect(0 0 0 0)",
|
|
40
|
+
"clip-path:inset(50%)",
|
|
41
|
+
"white-space:nowrap",
|
|
42
|
+
"border:0",
|
|
43
|
+
].join(";");
|
|
17
44
|
|
|
18
45
|
let nextToastInstanceId = 1;
|
|
19
46
|
|
|
@@ -41,6 +68,98 @@ function isToastPanelOpen(panel) {
|
|
|
41
68
|
}
|
|
42
69
|
}
|
|
43
70
|
|
|
71
|
+
function normalizeToastText(value) {
|
|
72
|
+
return value?.replace(/\s+/g, " ").trim() || "";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getToastTextFromIdRefs(ownerDocument, value) {
|
|
76
|
+
if (!ownerDocument || !value) {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return value
|
|
81
|
+
.split(/\s+/)
|
|
82
|
+
.map((id) => normalizeToastText(ownerDocument.getElementById(id)?.textContent))
|
|
83
|
+
.filter(Boolean)
|
|
84
|
+
.join(" ");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getToastAccessibleName(panel, title) {
|
|
88
|
+
if (!(panel instanceof HTMLElementBase)) {
|
|
89
|
+
return { includesTitle: false, text: "" };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const labelledBy = panel.getAttribute("aria-labelledby");
|
|
93
|
+
|
|
94
|
+
if (labelledBy) {
|
|
95
|
+
const ids = labelledBy.split(/\s+/).filter(Boolean);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
includesTitle: title instanceof HTMLElementBase && !!title.id && ids.includes(title.id),
|
|
99
|
+
text: getToastTextFromIdRefs(panel.ownerDocument, labelledBy),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const label = normalizeToastText(panel.getAttribute("aria-label"));
|
|
104
|
+
|
|
105
|
+
if (label) {
|
|
106
|
+
return { includesTitle: false, text: label };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (title instanceof HTMLElementBase) {
|
|
110
|
+
return { includesTitle: true, text: normalizeToastText(title.textContent) };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { includesTitle: false, text: "" };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function getToastBodyText(panel, excludeTitle = false) {
|
|
117
|
+
if (!(panel instanceof HTMLElementBase)) {
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!excludeTitle) {
|
|
122
|
+
return normalizeToastText(panel.textContent);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const panelClone = panel.cloneNode(true);
|
|
126
|
+
|
|
127
|
+
if (!(panelClone instanceof HTMLElementBase)) {
|
|
128
|
+
return normalizeToastText(panel.textContent);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const title of panelClone.querySelectorAll(TITLE_SELECTOR)) {
|
|
132
|
+
title.remove();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return normalizeToastText(panelClone.textContent);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function getToastAnnouncementText(panel, title) {
|
|
139
|
+
const { includesTitle, text: name } = getToastAccessibleName(panel, title);
|
|
140
|
+
const body = getToastBodyText(panel, includesTitle);
|
|
141
|
+
|
|
142
|
+
if (!name) {
|
|
143
|
+
return body;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!body || body === name || body.startsWith(`${name} `) || body.startsWith(`${name}.`)) {
|
|
147
|
+
return name;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return `${name}. ${body}`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function findInteractiveToastDescendants(panel) {
|
|
154
|
+
if (!(panel instanceof HTMLElementBase)) {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return Array.from(panel.querySelectorAll(INTERACTIVE_PANEL_SELECTOR)).filter(
|
|
159
|
+
(element) => element instanceof HTMLElementBase && !element.hidden,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
44
163
|
export function normalizeToastLabel(value) {
|
|
45
164
|
return value?.trim() || DEFAULT_LABEL;
|
|
46
165
|
}
|
|
@@ -88,6 +207,10 @@ export class ToastElement extends HTMLElementBase {
|
|
|
88
207
|
#closeButtons = [];
|
|
89
208
|
#restoreFocusTo = null;
|
|
90
209
|
#dismissTimer = 0;
|
|
210
|
+
#announcementTimer = 0;
|
|
211
|
+
#announcer = null;
|
|
212
|
+
#open = false;
|
|
213
|
+
#hasWarnedAboutInteractiveContent = false;
|
|
91
214
|
#eventsBound = false;
|
|
92
215
|
|
|
93
216
|
connectedCallback() {
|
|
@@ -110,6 +233,7 @@ export class ToastElement extends HTMLElementBase {
|
|
|
110
233
|
this.#eventsBound = false;
|
|
111
234
|
this.#syncPanelEvents(null);
|
|
112
235
|
this.#clearDismissTimer();
|
|
236
|
+
this.#clearAnnouncement();
|
|
113
237
|
}
|
|
114
238
|
|
|
115
239
|
attributeChangedCallback() {
|
|
@@ -223,6 +347,34 @@ export class ToastElement extends HTMLElementBase {
|
|
|
223
347
|
this.#applyState();
|
|
224
348
|
}
|
|
225
349
|
|
|
350
|
+
#ensureAnnouncer() {
|
|
351
|
+
if (this.#announcer instanceof HTMLElementBase && this.#announcer.isConnected) {
|
|
352
|
+
this.#announcer.setAttribute("style", VISUALLY_HIDDEN_ANNOUNCER_STYLE);
|
|
353
|
+
return this.#announcer;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const existingAnnouncer = Array.from(this.children).find(
|
|
357
|
+
(element) => element instanceof HTMLElementBase && element.hasAttribute(ANNOUNCER_ATTRIBUTE),
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
if (existingAnnouncer instanceof HTMLElementBase) {
|
|
361
|
+
existingAnnouncer.setAttribute("style", VISUALLY_HIDDEN_ANNOUNCER_STYLE);
|
|
362
|
+
this.#announcer = existingAnnouncer;
|
|
363
|
+
return existingAnnouncer;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (!this.ownerDocument?.createElement) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const announcer = this.ownerDocument.createElement("div");
|
|
371
|
+
announcer.setAttribute(ANNOUNCER_ATTRIBUTE, "");
|
|
372
|
+
announcer.setAttribute("style", VISUALLY_HIDDEN_ANNOUNCER_STYLE);
|
|
373
|
+
this.append(announcer);
|
|
374
|
+
this.#announcer = announcer;
|
|
375
|
+
return announcer;
|
|
376
|
+
}
|
|
377
|
+
|
|
226
378
|
#syncPanelEvents(nextPanel) {
|
|
227
379
|
if (this.#panelWithEvents === nextPanel) {
|
|
228
380
|
return;
|
|
@@ -264,6 +416,7 @@ export class ToastElement extends HTMLElementBase {
|
|
|
264
416
|
|
|
265
417
|
if (!(this.#panel instanceof HTMLElementBase)) {
|
|
266
418
|
this.#clearDismissTimer();
|
|
419
|
+
this.#clearAnnouncement();
|
|
267
420
|
return;
|
|
268
421
|
}
|
|
269
422
|
|
|
@@ -273,11 +426,13 @@ export class ToastElement extends HTMLElementBase {
|
|
|
273
426
|
this.#title.id = `${baseId}-title`;
|
|
274
427
|
}
|
|
275
428
|
|
|
276
|
-
this.#panel.setAttribute("role",
|
|
277
|
-
this.#panel.
|
|
278
|
-
this.#panel.
|
|
429
|
+
this.#panel.setAttribute("role", "group");
|
|
430
|
+
this.#panel.removeAttribute("aria-live");
|
|
431
|
+
this.#panel.removeAttribute("aria-atomic");
|
|
279
432
|
this.#syncAccessibleLabel();
|
|
280
433
|
this.#syncPopoverState();
|
|
434
|
+
this.#syncAnnouncerState();
|
|
435
|
+
this.#warnOnInteractiveContent();
|
|
281
436
|
this.#syncOpenState();
|
|
282
437
|
}
|
|
283
438
|
|
|
@@ -309,6 +464,15 @@ export class ToastElement extends HTMLElementBase {
|
|
|
309
464
|
this.#dismissTimer = 0;
|
|
310
465
|
}
|
|
311
466
|
|
|
467
|
+
#clearAnnouncementTimer() {
|
|
468
|
+
if (this.#announcementTimer === 0 || typeof window === "undefined") {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
window.clearTimeout(this.#announcementTimer);
|
|
473
|
+
this.#announcementTimer = 0;
|
|
474
|
+
}
|
|
475
|
+
|
|
312
476
|
#syncPopoverState() {
|
|
313
477
|
if (!(this.#panel instanceof HTMLElementBase) || !supportsToastPopover(this.#panel)) {
|
|
314
478
|
return;
|
|
@@ -323,6 +487,7 @@ export class ToastElement extends HTMLElementBase {
|
|
|
323
487
|
#syncOpenState() {
|
|
324
488
|
if (!(this.#panel instanceof HTMLElementBase)) {
|
|
325
489
|
this.#clearDismissTimer();
|
|
490
|
+
this.#clearAnnouncement();
|
|
326
491
|
return;
|
|
327
492
|
}
|
|
328
493
|
|
|
@@ -350,21 +515,29 @@ export class ToastElement extends HTMLElementBase {
|
|
|
350
515
|
#syncStateFromPanel() {
|
|
351
516
|
if (!(this.#panel instanceof HTMLElementBase)) {
|
|
352
517
|
this.#clearDismissTimer();
|
|
518
|
+
this.#clearAnnouncement();
|
|
353
519
|
return;
|
|
354
520
|
}
|
|
355
521
|
|
|
522
|
+
const wasOpen = this.#open;
|
|
356
523
|
const open = supportsToastPopover(this.#panel)
|
|
357
524
|
? isToastPanelOpen(this.#panel)
|
|
358
525
|
: !this.#panel.hidden;
|
|
359
526
|
|
|
527
|
+
this.#open = open;
|
|
360
528
|
this.#panel.hidden = !open;
|
|
361
529
|
this.#panel.toggleAttribute("data-open", open);
|
|
362
530
|
this.toggleAttribute("data-open", open);
|
|
363
531
|
|
|
364
532
|
if (open) {
|
|
533
|
+
this.#syncAnnouncerState();
|
|
365
534
|
this.#scheduleDismiss();
|
|
535
|
+
if (!wasOpen) {
|
|
536
|
+
this.#announce();
|
|
537
|
+
}
|
|
366
538
|
} else {
|
|
367
539
|
this.#clearDismissTimer();
|
|
540
|
+
this.#clearAnnouncement();
|
|
368
541
|
}
|
|
369
542
|
}
|
|
370
543
|
|
|
@@ -414,6 +587,94 @@ export class ToastElement extends HTMLElementBase {
|
|
|
414
587
|
this.#panel.setAttribute("aria-label", nextLabel);
|
|
415
588
|
this.#panel.setAttribute(MANAGED_LABEL_ATTRIBUTE, "");
|
|
416
589
|
}
|
|
590
|
+
|
|
591
|
+
#syncAnnouncerState() {
|
|
592
|
+
if (!this.#open) {
|
|
593
|
+
if (this.#announcer instanceof HTMLElementBase) {
|
|
594
|
+
this.#announcer.textContent = "";
|
|
595
|
+
this.#announcer.removeAttribute("role");
|
|
596
|
+
this.#announcer.removeAttribute("aria-live");
|
|
597
|
+
this.#announcer.removeAttribute("aria-atomic");
|
|
598
|
+
this.#announcer.removeAttribute("aria-relevant");
|
|
599
|
+
}
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const announcer = this.#ensureAnnouncer();
|
|
604
|
+
|
|
605
|
+
if (!(announcer instanceof HTMLElementBase)) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
announcer.setAttribute("role", getToastRoleForLive(this.getAttribute("data-live")));
|
|
610
|
+
announcer.setAttribute("aria-live", normalizeToastLive(this.getAttribute("data-live")));
|
|
611
|
+
announcer.setAttribute("aria-atomic", "true");
|
|
612
|
+
announcer.setAttribute("aria-relevant", "additions text");
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
#clearAnnouncement() {
|
|
616
|
+
this.#clearAnnouncementTimer();
|
|
617
|
+
this.#open = false;
|
|
618
|
+
|
|
619
|
+
if (!(this.#announcer instanceof HTMLElementBase)) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
this.#announcer.textContent = "";
|
|
624
|
+
this.#announcer.removeAttribute("role");
|
|
625
|
+
this.#announcer.removeAttribute("aria-live");
|
|
626
|
+
this.#announcer.removeAttribute("aria-atomic");
|
|
627
|
+
this.#announcer.removeAttribute("aria-relevant");
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
#announce() {
|
|
631
|
+
const announcement = getToastAnnouncementText(this.#panel, this.#title);
|
|
632
|
+
const announcer = this.#ensureAnnouncer();
|
|
633
|
+
|
|
634
|
+
if (!announcement || !(announcer instanceof HTMLElementBase)) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
this.#clearAnnouncementTimer();
|
|
639
|
+
this.#syncAnnouncerState();
|
|
640
|
+
announcer.textContent = "";
|
|
641
|
+
|
|
642
|
+
if (typeof window === "undefined") {
|
|
643
|
+
announcer.textContent = announcement;
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
this.#announcementTimer = window.setTimeout(() => {
|
|
648
|
+
this.#announcementTimer = 0;
|
|
649
|
+
|
|
650
|
+
if (!this.#open || !(this.#announcer instanceof HTMLElementBase)) {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
this.#announcer.textContent = announcement;
|
|
655
|
+
}, 0);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
#warnOnInteractiveContent() {
|
|
659
|
+
if (
|
|
660
|
+
this.#hasWarnedAboutInteractiveContent
|
|
661
|
+
|| !(this.#panel instanceof HTMLElementBase)
|
|
662
|
+
|| typeof globalThis.console?.warn !== "function"
|
|
663
|
+
) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (findInteractiveToastDescendants(this.#panel).length === 0) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
this.#hasWarnedAboutInteractiveContent = true;
|
|
672
|
+
globalThis.console.warn(
|
|
673
|
+
"basic-toast panels should only contain non-interactive message content. "
|
|
674
|
+
+ "Move links, buttons, and other focusable controls outside [data-toast-panel], "
|
|
675
|
+
+ "or use a more appropriate pattern such as basic-alert or basic-dialog.",
|
|
676
|
+
);
|
|
677
|
+
}
|
|
417
678
|
}
|
|
418
679
|
|
|
419
680
|
export function defineToast(registry = globalThis.customElements) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# `basic-toc`
|
|
2
|
+
|
|
3
|
+
Generated table-of-contents navigation from the nearest `<main>`.
|
|
4
|
+
|
|
5
|
+
## Register
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import "@lmfaole/basics/basic-components/basic-toc/register";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Example
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<basic-toc data-title="Innhold">
|
|
15
|
+
<nav aria-label="Innhold" data-page-toc-nav></nav>
|
|
16
|
+
</basic-toc>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Props
|
|
20
|
+
|
|
21
|
+
| Prop | Description | Type | Default | Options |
|
|
22
|
+
| --- | --- | --- | --- | --- |
|
|
23
|
+
| `data-title` | Accessible label applied to the generated nav. | string | `Innhold` | any string |
|
|
24
|
+
| `data-heading-selector` | Selector used to collect headings from the nearest `<main>`. | CSS selector | `h1, h2, h3, h4, h5, h6` | any CSS selector |
|
|
25
|
+
|
|
26
|
+
## Markup Hooks
|
|
27
|
+
|
|
28
|
+
| Hook | Description | Type | Default | Options |
|
|
29
|
+
| --- | --- | --- | --- | --- |
|
|
30
|
+
| `data-page-toc-nav` | Container where the generated outline links are rendered. | descendant element attribute | required | present on one descendant element |
|
|
31
|
+
|
|
32
|
+
## Behavior
|
|
33
|
+
|
|
34
|
+
- Generates missing heading ids automatically
|
|
35
|
+
- Gives duplicate headings unique fragment ids
|
|
36
|
+
- Ignores hidden headings
|
|
37
|
+
- Rebuilds the outline when matching headings are added or changed
|
|
38
|
+
|
|
39
|
+
## Markup Contract
|
|
40
|
+
|
|
41
|
+
- Render the element inside the same `<main>` that contains the content it should index
|
|
42
|
+
- Provide a descendant element with `data-page-toc-nav` for the generated links
|
|
43
|
+
- Keep layout and styling outside the package
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
basic-accordion {
|
|
2
2
|
--basic-accordion-padding: var(--basic-panel-padding);
|
|
3
3
|
display: grid;
|
|
4
|
+
gap: 0;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
basic-accordion > details {
|
|
7
8
|
margin: 0;
|
|
8
|
-
border: var(--basic-border-width) solid var(--basic-color-border);
|
|
9
|
-
border-radius: var(--basic-radius);
|
|
9
|
+
border-inline: var(--basic-border-width) solid var(--basic-color-border);
|
|
10
10
|
background: var(--basic-color-surface);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
basic-accordion > details > summary {
|
|
14
|
+
--basic-interaction-border-rest: transparent;
|
|
15
|
+
--basic-interaction-border-hover: transparent;
|
|
16
|
+
--basic-interaction-border-active: transparent;
|
|
17
|
+
--basic-interaction-border-selected: transparent;
|
|
14
18
|
list-style: none;
|
|
15
19
|
display: flex;
|
|
16
20
|
align-items: center;
|
|
@@ -20,6 +24,7 @@ basic-accordion > details > summary {
|
|
|
20
24
|
font-weight: 600;
|
|
21
25
|
text-align: left;
|
|
22
26
|
cursor: pointer;
|
|
27
|
+
background: transparent;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
basic-accordion > details > summary::-webkit-details-marker {
|
|
@@ -34,9 +39,34 @@ basic-accordion > details > summary::after {
|
|
|
34
39
|
line-height: 1;
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
basic-accordion > details:first-child {
|
|
43
|
+
border-block-start: var(--basic-border-width) solid var(--basic-color-border);
|
|
44
|
+
border-start-start-radius: var(--basic-radius);
|
|
45
|
+
border-start-end-radius: var(--basic-radius);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
basic-accordion > details:first-child > summary {
|
|
49
|
+
border-start-start-radius: var(--basic-radius);
|
|
50
|
+
border-start-end-radius: var(--basic-radius);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
basic-accordion > details + details {
|
|
54
|
+
border-block-start: var(--basic-border-width) solid var(--basic-color-border);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
basic-accordion > details:last-child {
|
|
58
|
+
border-block-end: var(--basic-border-width) solid var(--basic-color-border);
|
|
59
|
+
border-end-start-radius: var(--basic-radius);
|
|
60
|
+
border-end-end-radius: var(--basic-radius);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
basic-accordion > details:last-child:not([open]) > summary {
|
|
64
|
+
border-end-start-radius: var(--basic-radius);
|
|
65
|
+
border-end-end-radius: var(--basic-radius);
|
|
66
|
+
}
|
|
67
|
+
|
|
37
68
|
basic-accordion > details[open] > summary {
|
|
38
|
-
|
|
39
|
-
margin-block-end: var(--basic-flow-space);
|
|
69
|
+
border-block-end: var(--basic-border-width) solid var(--basic-color-border-selected);
|
|
40
70
|
}
|
|
41
71
|
|
|
42
72
|
basic-accordion > details[open] > summary::after {
|
|
@@ -48,6 +78,10 @@ basic-accordion > details[open] {
|
|
|
48
78
|
padding-block-end: var(--basic-accordion-padding);
|
|
49
79
|
}
|
|
50
80
|
|
|
81
|
+
basic-accordion > details[open] > summary + :where(*) {
|
|
82
|
+
margin-block-start: var(--basic-accordion-padding);
|
|
83
|
+
}
|
|
84
|
+
|
|
51
85
|
basic-accordion > details > :where(:not(summary)) {
|
|
52
86
|
margin-block: 0;
|
|
53
87
|
margin-inline: var(--basic-accordion-padding);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
basic-carousel {
|
|
2
|
+
--basic-carousel-gap: var(--basic-space-4);
|
|
3
|
+
--basic-carousel-controls-gap: var(--basic-space-3);
|
|
4
|
+
--basic-carousel-button-size: 2.75rem;
|
|
5
|
+
--basic-carousel-marker-size: 1.75rem;
|
|
6
|
+
--basic-carousel-item-width: 90%;
|
|
7
|
+
--basic-carousel-track-padding: var(--basic-space-1);
|
|
8
|
+
--basic-carousel-snap-align: center;
|
|
9
|
+
display: block;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
basic-carousel[data-basic-carousel-snapping="start"] {
|
|
13
|
+
--basic-carousel-snap-align: start;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
basic-carousel[data-basic-carousel-snapping="end"] {
|
|
17
|
+
--basic-carousel-snap-align: end;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
basic-carousel [data-carousel-track] {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: stretch;
|
|
23
|
+
gap: var(--basic-carousel-gap);
|
|
24
|
+
min-inline-size: 0;
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: var(--basic-carousel-track-padding);
|
|
27
|
+
overflow-x: auto;
|
|
28
|
+
overscroll-behavior-inline: contain;
|
|
29
|
+
scroll-behavior: smooth;
|
|
30
|
+
scroll-snap-type: x mandatory;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
basic-carousel :is(ol, ul)[data-carousel-track] {
|
|
34
|
+
list-style: none;
|
|
35
|
+
padding-inline-start: var(--basic-carousel-track-padding);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
basic-carousel [data-carousel-track] > * {
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
flex: 0 0 var(--basic-carousel-item-width);
|
|
41
|
+
inline-size: var(--basic-carousel-item-width);
|
|
42
|
+
min-inline-size: 0;
|
|
43
|
+
padding: var(--basic-panel-padding);
|
|
44
|
+
border: var(--basic-border-width) solid var(--basic-color-border);
|
|
45
|
+
border-radius: var(--basic-radius);
|
|
46
|
+
background: var(--basic-color-surface);
|
|
47
|
+
scroll-snap-align: var(--basic-carousel-snap-align);
|
|
48
|
+
scroll-snap-stop: always;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
basic-carousel [data-carousel-track] > * > :where(*) {
|
|
52
|
+
margin-block: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
basic-carousel [data-carousel-track] > * > :where(* + *) {
|
|
56
|
+
margin-block-start: var(--basic-flow-space);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
basic-carousel [data-carousel-track] > * > p:first-child {
|
|
60
|
+
color: var(--basic-color-text-muted);
|
|
61
|
+
font-size: 0.875rem;
|
|
62
|
+
font-weight: 700;
|
|
63
|
+
letter-spacing: 0.06em;
|
|
64
|
+
text-transform: uppercase;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
basic-carousel [data-carousel-track] > * > a {
|
|
68
|
+
color: inherit;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@supports (scroll-marker-group: after) {
|
|
73
|
+
basic-carousel {
|
|
74
|
+
display: grid;
|
|
75
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
76
|
+
grid-template-rows: minmax(0, auto) auto;
|
|
77
|
+
gap: var(--basic-carousel-controls-gap);
|
|
78
|
+
align-items: start;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
basic-carousel:is([data-basic-carousel-controls="markers"], [data-basic-carousel-controls="none"]) {
|
|
82
|
+
grid-template-columns: minmax(0, 1fr);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
basic-carousel [data-carousel-track] {
|
|
86
|
+
grid-column: 1 / -1;
|
|
87
|
+
grid-row: 1;
|
|
88
|
+
scroll-marker-group: after;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
basic-carousel:is([data-basic-carousel-controls="markers"], [data-basic-carousel-controls="none"]) [data-carousel-track] {
|
|
92
|
+
grid-column: 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
basic-carousel:is([data-basic-carousel-controls="arrows"], [data-basic-carousel-controls="none"]) [data-carousel-track] {
|
|
96
|
+
scroll-marker-group: none;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
basic-carousel [data-carousel-track]::scroll-button(inline-start),
|
|
100
|
+
basic-carousel [data-carousel-track]::scroll-button(inline-end) {
|
|
101
|
+
display: inline-flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
align-self: center;
|
|
104
|
+
justify-content: center;
|
|
105
|
+
inline-size: var(--basic-carousel-button-size);
|
|
106
|
+
block-size: var(--basic-carousel-button-size);
|
|
107
|
+
margin: 0;
|
|
108
|
+
padding: 0;
|
|
109
|
+
border: var(--basic-border-width) solid var(--basic-color-border);
|
|
110
|
+
border-radius: var(--basic-radius-pill);
|
|
111
|
+
background: var(--basic-color-surface);
|
|
112
|
+
color: inherit;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
grid-row: 2;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
basic-carousel:is([data-basic-carousel-controls="markers"], [data-basic-carousel-controls="none"]) [data-carousel-track]::scroll-button(inline-start),
|
|
118
|
+
basic-carousel:is([data-basic-carousel-controls="markers"], [data-basic-carousel-controls="none"]) [data-carousel-track]::scroll-button(inline-end) {
|
|
119
|
+
display: none;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
basic-carousel [data-carousel-track]::scroll-button(inline-start) {
|
|
123
|
+
content: "<" / "Previous slide";
|
|
124
|
+
grid-column: 1;
|
|
125
|
+
justify-self: end;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
basic-carousel [data-carousel-track]::scroll-button(inline-end) {
|
|
129
|
+
content: ">" / "Next slide";
|
|
130
|
+
grid-column: 3;
|
|
131
|
+
justify-self: start;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
basic-carousel [data-carousel-track]::scroll-button(*):disabled {
|
|
135
|
+
opacity: 0.45;
|
|
136
|
+
cursor: not-allowed;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
basic-carousel [data-carousel-track]::scroll-marker-group {
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-wrap: nowrap;
|
|
142
|
+
align-items: center;
|
|
143
|
+
align-self: center;
|
|
144
|
+
justify-content: center;
|
|
145
|
+
gap: var(--basic-space-2);
|
|
146
|
+
min-block-size: var(--basic-carousel-button-size);
|
|
147
|
+
grid-column: 2;
|
|
148
|
+
grid-row: 2;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
basic-carousel[data-basic-carousel-controls="markers"] [data-carousel-track]::scroll-marker-group {
|
|
152
|
+
grid-column: 1;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
basic-carousel:is([data-basic-carousel-controls="arrows"], [data-basic-carousel-controls="none"]) [data-carousel-track]::scroll-marker-group {
|
|
156
|
+
display: none;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
basic-carousel [data-carousel-track] > *::scroll-marker {
|
|
160
|
+
content: attr(data-basic-carousel-marker) / attr(data-basic-carousel-marker-label);
|
|
161
|
+
display: inline-flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
min-inline-size: var(--basic-carousel-marker-size);
|
|
165
|
+
block-size: var(--basic-carousel-marker-size);
|
|
166
|
+
padding-inline: var(--basic-space-2);
|
|
167
|
+
border: var(--basic-border-width) solid var(--basic-color-border);
|
|
168
|
+
border-radius: var(--basic-radius-pill);
|
|
169
|
+
background: var(--basic-color-surface);
|
|
170
|
+
color: inherit;
|
|
171
|
+
font-size: 0.875rem;
|
|
172
|
+
font-weight: 600;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
basic-carousel:is([data-basic-carousel-controls="arrows"], [data-basic-carousel-controls="none"]) [data-carousel-track] > *::scroll-marker {
|
|
176
|
+
content: none;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
basic-carousel [data-carousel-track] > *::scroll-marker:target-current {
|
|
180
|
+
border-color: var(--basic-color-border-selected);
|
|
181
|
+
background: var(--basic-color-surface-selected);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -7,6 +7,8 @@ basic-popover {
|
|
|
7
7
|
|
|
8
8
|
basic-popover [data-popover-open],
|
|
9
9
|
basic-popover [data-popover-close] {
|
|
10
|
+
--basic-interaction-surface-selected: var(--basic-color-surface-muted);
|
|
11
|
+
--basic-interaction-border-selected: var(--basic-color-border);
|
|
10
12
|
display: inline-flex;
|
|
11
13
|
align-items: center;
|
|
12
14
|
justify-content: center;
|
|
@@ -19,10 +21,6 @@ basic-popover [data-popover-close] {
|
|
|
19
21
|
cursor: pointer;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
basic-popover [data-popover-open][aria-expanded="true"] {
|
|
23
|
-
background: var(--basic-color-surface-muted);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
24
|
basic-popover [data-popover-panel] {
|
|
27
25
|
width: min(var(--basic-popover-width, 20rem), var(--basic-popover-max-width, calc(100vw - 2rem)));
|
|
28
26
|
max-width: var(--basic-popover-max-width, calc(100vw - 2rem));
|