drab 6.2.2 → 6.3.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/announcer/index.d.ts +2 -0
- package/dist/announcer/index.js +2 -0
- package/dist/base/index.d.ts +8 -4
- package/dist/base/index.js +16 -16
- package/dist/copy/index.d.ts +8 -1
- package/dist/copy/index.js +8 -1
- package/dist/dialog/index.d.ts +2 -0
- package/dist/dialog/index.js +2 -0
- package/dist/editor/index.d.ts +17 -9
- package/dist/editor/index.js +17 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/intersect/index.d.ts +2 -0
- package/dist/intersect/index.js +2 -0
- package/dist/prefetch/index.d.ts +2 -0
- package/dist/prefetch/index.js +4 -2
- package/dist/share/index.d.ts +8 -1
- package/dist/share/index.js +8 -1
- package/dist/tablesort/index.js +5 -2
- package/dist/tabs/define.d.ts +1 -0
- package/dist/tabs/define.js +3 -0
- package/dist/tabs/index.d.ts +37 -0
- package/dist/tabs/index.js +147 -0
- package/dist/wakelock/index.d.ts +13 -3
- package/dist/wakelock/index.js +13 -3
- package/package.json +1 -1
@@ -10,6 +10,8 @@
|
|
10
10
|
* [avoid duplicate regions](https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-2/#limit-the-number-of-live-regions-on-the-page)
|
11
11
|
* (see below).
|
12
12
|
*
|
13
|
+
* ### Attributes
|
14
|
+
*
|
13
15
|
* `aria-live`
|
14
16
|
*
|
15
17
|
* By default, the announcer is created with the
|
package/dist/announcer/index.js
CHANGED
@@ -11,6 +11,8 @@ import { define } from "../util/define.js";
|
|
11
11
|
* [avoid duplicate regions](https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-2/#limit-the-number-of-live-regions-on-the-page)
|
12
12
|
* (see below).
|
13
13
|
*
|
14
|
+
* ### Attributes
|
15
|
+
*
|
14
16
|
* `aria-live`
|
15
17
|
*
|
16
18
|
* By default, the announcer is created with the
|
package/dist/base/index.d.ts
CHANGED
@@ -3,6 +3,7 @@ export type BaseAttributes = {
|
|
3
3
|
content?: string;
|
4
4
|
swap?: string;
|
5
5
|
};
|
6
|
+
type Constructor<T> = new (...args: any[]) => T;
|
6
7
|
/**
|
7
8
|
* Each element in the library extends the `Base` class. It provides methods
|
8
9
|
* for selecting elements via HTML attributes along with other helpers.
|
@@ -32,19 +33,21 @@ export declare class Base extends HTMLElement {
|
|
32
33
|
*/
|
33
34
|
announce(message: string): void;
|
34
35
|
/**
|
36
|
+
* @param instance The instance of the desired element to validate against,
|
37
|
+
* ex: `HTMLButtonElement`. Defaults to `HTMLElement`.
|
35
38
|
* @returns All of the elements that match the `trigger` selector.
|
36
39
|
* @default this.querySelectorAll("[data-trigger]")
|
37
40
|
*/
|
38
|
-
getTrigger<T extends HTMLElement
|
41
|
+
getTrigger<T extends HTMLElement>(instance: Constructor<T>): NodeListOf<T>;
|
42
|
+
getTrigger(): NodeListOf<HTMLElement>;
|
39
43
|
/**
|
40
44
|
* @param instance The instance of the desired element to validate against,
|
41
45
|
* ex: `HTMLDialogElement`. Defaults to `HTMLElement`.
|
42
46
|
* @returns The element that matches the `content` selector.
|
43
47
|
* @default this.querySelector("[data-content]")
|
44
48
|
*/
|
45
|
-
getContent<T extends HTMLElement
|
46
|
-
|
47
|
-
}): T;
|
49
|
+
getContent<T extends HTMLElement>(instance: Constructor<T>): T;
|
50
|
+
getContent(): HTMLElement;
|
48
51
|
/**
|
49
52
|
* Finds the `HTMLElement | HTMLTemplateElement` via the `swap` selector and
|
50
53
|
* swaps `this.content()` with the content of the element found.
|
@@ -84,3 +87,4 @@ export declare class Base extends HTMLElement {
|
|
84
87
|
/** Called when custom element is removed from the page. */
|
85
88
|
disconnectedCallback(): void;
|
86
89
|
}
|
90
|
+
export {};
|
package/dist/base/index.js
CHANGED
@@ -41,24 +41,14 @@ export class Base extends HTMLElement {
|
|
41
41
|
announce(message) {
|
42
42
|
Base.#announcer.announce(message);
|
43
43
|
}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
return this.querySelectorAll(this.getAttribute("trigger") ?? "[data-trigger]");
|
44
|
+
getTrigger(instance = HTMLElement) {
|
45
|
+
const triggers = this.querySelectorAll(this.getAttribute("trigger") ?? "[data-trigger]");
|
46
|
+
for (const trigger of triggers)
|
47
|
+
this.#validate(trigger, instance);
|
48
|
+
return triggers;
|
50
49
|
}
|
51
|
-
/**
|
52
|
-
* @param instance The instance of the desired element to validate against,
|
53
|
-
* ex: `HTMLDialogElement`. Defaults to `HTMLElement`.
|
54
|
-
* @returns The element that matches the `content` selector.
|
55
|
-
* @default this.querySelector("[data-content]")
|
56
|
-
*/
|
57
50
|
getContent(instance = HTMLElement) {
|
58
|
-
|
59
|
-
if (content instanceof instance)
|
60
|
-
return content;
|
61
|
-
throw new Error("Content not found");
|
51
|
+
return this.#validate(this.querySelector(this.getAttribute("content") ?? "[data-content]"), instance);
|
62
52
|
}
|
63
53
|
/**
|
64
54
|
* Finds the `HTMLElement | HTMLTemplateElement` via the `swap` selector and
|
@@ -129,4 +119,14 @@ export class Base extends HTMLElement {
|
|
129
119
|
this.destroy();
|
130
120
|
this.#listenerController.abort();
|
131
121
|
}
|
122
|
+
/**
|
123
|
+
* @param actual Element to validate.
|
124
|
+
* @param expected Constructor of the expected element.
|
125
|
+
* @returns If valid returns `actual` otherwise throws `TypeError`.
|
126
|
+
*/
|
127
|
+
#validate(actual, expected) {
|
128
|
+
if (!(actual instanceof expected))
|
129
|
+
throw new TypeError(`${actual} is not an instance of ${expected.name}.`);
|
130
|
+
return actual;
|
131
|
+
}
|
132
132
|
}
|
package/dist/copy/index.d.ts
CHANGED
@@ -3,8 +3,15 @@ export type CopyAttributes = BaseAttributes & {
|
|
3
3
|
value: string;
|
4
4
|
};
|
5
5
|
/**
|
6
|
-
* Uses the
|
6
|
+
* Uses the
|
7
|
+
* [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText)
|
7
8
|
* to copy text.
|
9
|
+
*
|
10
|
+
* ### Attributes
|
11
|
+
*
|
12
|
+
* `value`
|
13
|
+
*
|
14
|
+
* Text to copy.
|
8
15
|
*/
|
9
16
|
export declare class Copy extends Base {
|
10
17
|
constructor();
|
package/dist/copy/index.js
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
import { Base } from "../base/index.js";
|
2
2
|
/**
|
3
|
-
* Uses the
|
3
|
+
* Uses the
|
4
|
+
* [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText)
|
4
5
|
* to copy text.
|
6
|
+
*
|
7
|
+
* ### Attributes
|
8
|
+
*
|
9
|
+
* `value`
|
10
|
+
*
|
11
|
+
* Text to copy.
|
5
12
|
*/
|
6
13
|
export class Copy extends Base {
|
7
14
|
constructor() {
|
package/dist/dialog/index.d.ts
CHANGED
@@ -11,6 +11,8 @@ export type DialogAttributes = BaseAttributes & {
|
|
11
11
|
* By default, the `HTMLDialogElement` doesn't close if the user clicks outside of it.
|
12
12
|
* Add a `click-outside-close` attribute to close when the user clicks outside.
|
13
13
|
*
|
14
|
+
* ### Attributes
|
15
|
+
*
|
14
16
|
* `remove-body-scroll`
|
15
17
|
*
|
16
18
|
* Add the `remove-body-scroll` attribute to remove the scroll from `document.body` when the dialog
|
package/dist/dialog/index.js
CHANGED
@@ -7,6 +7,8 @@ import { Base } from "../base/index.js";
|
|
7
7
|
* By default, the `HTMLDialogElement` doesn't close if the user clicks outside of it.
|
8
8
|
* Add a `click-outside-close` attribute to close when the user clicks outside.
|
9
9
|
*
|
10
|
+
* ### Attributes
|
11
|
+
*
|
10
12
|
* `remove-body-scroll`
|
11
13
|
*
|
12
14
|
* Add the `remove-body-scroll` attribute to remove the scroll from `document.body` when the dialog
|
package/dist/editor/index.d.ts
CHANGED
@@ -19,6 +19,23 @@ export type ContentElement = {
|
|
19
19
|
/**
|
20
20
|
* Enhances the `textarea` element with controls to add content and keyboard shortcuts. Compared to other WYSIWYG editors, the `text` value is just a `string`, so you can easily store it in a database or manipulate it without learning a separate API.
|
21
21
|
*
|
22
|
+
* - Automatically adds closing characters for `keyPairs`. For example, when
|
23
|
+
* typing `(`, `)` will be inserted and typed over when reached. All content
|
24
|
+
* with `data-type="wrap"` is also added to `keyPairs`.
|
25
|
+
* - Highlights the first word of the text inserted if it contains letters.
|
26
|
+
* - Automatically increments/decrements ordered lists.
|
27
|
+
* - Adds the starting character to the next line for `block` content.
|
28
|
+
* - On double click, highlight is corrected to only highlight the current word
|
29
|
+
* without space around it.
|
30
|
+
* - `tab` key will indent or dedent (+shift) instead of focus change if the
|
31
|
+
* selection is within a code block (three backticks).
|
32
|
+
* - When text is highlighted and a `wrap` character `keyPair` is typed, the
|
33
|
+
* highlighted text will be wrapped with the character instead of removing it.
|
34
|
+
* For example, if a word is highlighted and the `"` character is typed, the
|
35
|
+
* work will be surrounded by `"`s.
|
36
|
+
*
|
37
|
+
* ### Trigger attributes
|
38
|
+
*
|
22
39
|
* `data-value`
|
23
40
|
*
|
24
41
|
* Set the value of the text to be inserted using the `data-value` attribute on the `trigger`.
|
@@ -35,15 +52,6 @@ export type ContentElement = {
|
|
35
52
|
*
|
36
53
|
* Add a `ctrl`/`meta` keyboard shortcut for the content based on the `data-key` attribute.
|
37
54
|
*
|
38
|
-
* Other features:
|
39
|
-
*
|
40
|
-
* - Automatically adds closing characters for `keyPairs`. For example, when typing `(`, `)` will be inserted and typed over when reached. All content with `data-type="wrap"` is also added to `keyPairs`.
|
41
|
-
* - Highlights the first word of the text inserted if it contains letters.
|
42
|
-
* - Automatically increments/decrements ordered lists.
|
43
|
-
* - Adds the starting character to the next line for `block` content.
|
44
|
-
* - On double click, highlight is corrected to only highlight the current word without space around it.
|
45
|
-
* - `tab` key will indent or dedent (+shift) instead of focus change if the selection is within a code block (three backticks).
|
46
|
-
* - When text is highlighted and a `wrap` character `keyPair` is typed, the highlighted text will be wrapped with the character instead of removing it. For example, if a word is highlighted and the `"` character is typed, the work will be surrounded by `"`s.
|
47
55
|
*/
|
48
56
|
export declare class Editor extends Base {
|
49
57
|
#private;
|
package/dist/editor/index.js
CHANGED
@@ -2,6 +2,23 @@ import { Base } from "../base/index.js";
|
|
2
2
|
/**
|
3
3
|
* Enhances the `textarea` element with controls to add content and keyboard shortcuts. Compared to other WYSIWYG editors, the `text` value is just a `string`, so you can easily store it in a database or manipulate it without learning a separate API.
|
4
4
|
*
|
5
|
+
* - Automatically adds closing characters for `keyPairs`. For example, when
|
6
|
+
* typing `(`, `)` will be inserted and typed over when reached. All content
|
7
|
+
* with `data-type="wrap"` is also added to `keyPairs`.
|
8
|
+
* - Highlights the first word of the text inserted if it contains letters.
|
9
|
+
* - Automatically increments/decrements ordered lists.
|
10
|
+
* - Adds the starting character to the next line for `block` content.
|
11
|
+
* - On double click, highlight is corrected to only highlight the current word
|
12
|
+
* without space around it.
|
13
|
+
* - `tab` key will indent or dedent (+shift) instead of focus change if the
|
14
|
+
* selection is within a code block (three backticks).
|
15
|
+
* - When text is highlighted and a `wrap` character `keyPair` is typed, the
|
16
|
+
* highlighted text will be wrapped with the character instead of removing it.
|
17
|
+
* For example, if a word is highlighted and the `"` character is typed, the
|
18
|
+
* work will be surrounded by `"`s.
|
19
|
+
*
|
20
|
+
* ### Trigger attributes
|
21
|
+
*
|
5
22
|
* `data-value`
|
6
23
|
*
|
7
24
|
* Set the value of the text to be inserted using the `data-value` attribute on the `trigger`.
|
@@ -18,15 +35,6 @@ import { Base } from "../base/index.js";
|
|
18
35
|
*
|
19
36
|
* Add a `ctrl`/`meta` keyboard shortcut for the content based on the `data-key` attribute.
|
20
37
|
*
|
21
|
-
* Other features:
|
22
|
-
*
|
23
|
-
* - Automatically adds closing characters for `keyPairs`. For example, when typing `(`, `)` will be inserted and typed over when reached. All content with `data-type="wrap"` is also added to `keyPairs`.
|
24
|
-
* - Highlights the first word of the text inserted if it contains letters.
|
25
|
-
* - Automatically increments/decrements ordered lists.
|
26
|
-
* - Adds the starting character to the next line for `block` content.
|
27
|
-
* - On double click, highlight is corrected to only highlight the current word without space around it.
|
28
|
-
* - `tab` key will indent or dedent (+shift) instead of focus change if the selection is within a code block (three backticks).
|
29
|
-
* - When text is highlighted and a `wrap` character `keyPair` is typed, the highlighted text will be wrapped with the character instead of removing it. For example, if a word is highlighted and the `"` character is typed, the work will be surrounded by `"`s.
|
30
38
|
*/
|
31
39
|
export class Editor extends Base {
|
32
40
|
/** Array of `keyPair` characters that have been opened. */
|
package/dist/index.d.ts
CHANGED
@@ -9,5 +9,6 @@ export * from "./intersect/index.js";
|
|
9
9
|
export * from "./prefetch/index.js";
|
10
10
|
export * from "./share/index.js";
|
11
11
|
export * from "./tablesort/index.js";
|
12
|
+
export * from "./tabs/index.js";
|
12
13
|
export * from "./wakelock/index.js";
|
13
14
|
export * from "./youtube/index.js";
|
package/dist/index.js
CHANGED
@@ -9,5 +9,6 @@ export * from "./intersect/index.js";
|
|
9
9
|
export * from "./prefetch/index.js";
|
10
10
|
export * from "./share/index.js";
|
11
11
|
export * from "./tablesort/index.js";
|
12
|
+
export * from "./tabs/index.js";
|
12
13
|
export * from "./wakelock/index.js";
|
13
14
|
export * from "./youtube/index.js";
|
@@ -8,6 +8,8 @@ type IntersectCallback = () => any;
|
|
8
8
|
*
|
9
9
|
* Use `onIntersect` and `onExit` to customize further with JavaScript.
|
10
10
|
*
|
11
|
+
* ### Attributes
|
12
|
+
*
|
11
13
|
* `threshold`
|
12
14
|
*
|
13
15
|
* Specify a `threshold` between `0` and `1` to determine how much of the `trigger` should be visible for the intersection to occur.
|
package/dist/intersect/index.js
CHANGED
@@ -4,6 +4,8 @@ import { Base } from "../base/index.js";
|
|
4
4
|
*
|
5
5
|
* Use `onIntersect` and `onExit` to customize further with JavaScript.
|
6
6
|
*
|
7
|
+
* ### Attributes
|
8
|
+
*
|
7
9
|
* `threshold`
|
8
10
|
*
|
9
11
|
* Specify a `threshold` between `0` and `1` to determine how much of the `trigger` should be visible for the intersection to occur.
|
package/dist/prefetch/index.d.ts
CHANGED
@@ -10,6 +10,8 @@ export type PrefetchAttributes = BaseAttributes & {
|
|
10
10
|
*
|
11
11
|
* If you are using a framework that already has a prefetch feature or uses a client side router, it is best to use the framework's feature instead of this element to ensure prefetching is working in accordance with the router.
|
12
12
|
*
|
13
|
+
* ### Attributes
|
14
|
+
*
|
13
15
|
* `strategy`
|
14
16
|
*
|
15
17
|
* Set the `strategy` attribute to specify the when the prefetch will take place.
|
package/dist/prefetch/index.js
CHANGED
@@ -4,6 +4,8 @@ import { Base } from "../base/index.js";
|
|
4
4
|
*
|
5
5
|
* If you are using a framework that already has a prefetch feature or uses a client side router, it is best to use the framework's feature instead of this element to ensure prefetching is working in accordance with the router.
|
6
6
|
*
|
7
|
+
* ### Attributes
|
8
|
+
*
|
7
9
|
* `strategy`
|
8
10
|
*
|
9
11
|
* Set the `strategy` attribute to specify the when the prefetch will take place.
|
@@ -88,12 +90,12 @@ export class Prefetch extends Base {
|
|
88
90
|
* @param options Prefetch options.
|
89
91
|
*/
|
90
92
|
prefetch(options = {
|
91
|
-
anchors: this.getTrigger(),
|
93
|
+
anchors: this.getTrigger(HTMLAnchorElement),
|
92
94
|
prerender: this.#prerender,
|
93
95
|
strategy: this.#strategy,
|
94
96
|
}) {
|
95
97
|
// defaults if partially defined
|
96
|
-
const { anchors = this.getTrigger(), prerender = this.#prerender, strategy = this.#strategy, } = options;
|
98
|
+
const { anchors = this.getTrigger(HTMLAnchorElement), prerender = this.#prerender, strategy = this.#strategy, } = options;
|
97
99
|
let prefetchTimer;
|
98
100
|
/**
|
99
101
|
* @param delay ms delay - for `hover`
|
package/dist/share/index.d.ts
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
import { Copy, type CopyAttributes } from "../copy/index.js";
|
2
2
|
export type ShareAttributes = CopyAttributes;
|
3
3
|
/**
|
4
|
-
* Uses the
|
4
|
+
* Uses the
|
5
|
+
* [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
|
5
6
|
* to share a url. If `share` is not supported, falls back to copy the text instead.
|
7
|
+
*
|
8
|
+
* ### Attributes
|
9
|
+
*
|
10
|
+
* `value`
|
11
|
+
*
|
12
|
+
* Text to share.
|
6
13
|
*/
|
7
14
|
export declare class Share extends Copy {
|
8
15
|
constructor();
|
package/dist/share/index.js
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
import { Copy } from "../copy/index.js";
|
2
2
|
/**
|
3
|
-
* Uses the
|
3
|
+
* Uses the
|
4
|
+
* [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
|
4
5
|
* to share a url. If `share` is not supported, falls back to copy the text instead.
|
6
|
+
*
|
7
|
+
* ### Attributes
|
8
|
+
*
|
9
|
+
* `value`
|
10
|
+
*
|
11
|
+
* Text to share.
|
5
12
|
*/
|
6
13
|
export class Share extends Copy {
|
7
14
|
constructor() {
|
package/dist/tablesort/index.js
CHANGED
@@ -16,6 +16,9 @@ export class TableSort extends Base {
|
|
16
16
|
constructor() {
|
17
17
|
super();
|
18
18
|
}
|
19
|
+
get #th() {
|
20
|
+
return this.getTrigger(HTMLTableCellElement);
|
21
|
+
}
|
19
22
|
/**
|
20
23
|
* Removes `data-asc` or `data-desc` from other triggers then sets the correct attribute on the selected trigger.
|
21
24
|
*
|
@@ -25,7 +28,7 @@ export class TableSort extends Base {
|
|
25
28
|
#setAttributes(trigger) {
|
26
29
|
const asc = "data-asc";
|
27
30
|
const desc = "data-desc";
|
28
|
-
for (const t of this.getTrigger()) {
|
31
|
+
for (const t of this.getTrigger(HTMLTableCellElement)) {
|
29
32
|
if (t !== trigger) {
|
30
33
|
t.removeAttribute(asc);
|
31
34
|
t.removeAttribute(desc);
|
@@ -42,7 +45,7 @@ export class TableSort extends Base {
|
|
42
45
|
}
|
43
46
|
mount() {
|
44
47
|
const tbody = this.getContent(HTMLTableSectionElement);
|
45
|
-
for (const trigger of this
|
48
|
+
for (const trigger of this.#th) {
|
46
49
|
trigger.tabIndex = 0;
|
47
50
|
trigger.role = "button";
|
48
51
|
const listener = () => {
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { Base, type BaseAttributes } from "../base/index.js";
|
2
|
+
export type TabAttributes = BaseAttributes & {
|
3
|
+
orientation?: "horizontal" | "vertical";
|
4
|
+
};
|
5
|
+
/**
|
6
|
+
* Progressively enhance a list of links and content to be tabs by
|
7
|
+
* wrapping with the `Tabs` element. Each `trigger` should be an
|
8
|
+
* `HTMLAnchorElement` with the `href` attribute set to the `id` of the
|
9
|
+
* corresponding tab panel.
|
10
|
+
*
|
11
|
+
* > Tip: Set the `height` of the element the panels are contained in with
|
12
|
+
* > CSS to prevent layout shift when JS is loaded.
|
13
|
+
*
|
14
|
+
* This element is based on
|
15
|
+
* [Chris Ferdinandi's Toggle Tabs](https://gomakethings.com/a-web-component-ui-library-for-people-who-love-html/#toggle-tabs)
|
16
|
+
* design.
|
17
|
+
*
|
18
|
+
* [ARIA Reference](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/)
|
19
|
+
*
|
20
|
+
* - Sets the correct ARIA attributes on each element.
|
21
|
+
* - Supports keyboard navigation based on the `orientation` attribute.
|
22
|
+
* - First tab is selected by default if no `aria-selected="true"` attribute is
|
23
|
+
* found on another tab.
|
24
|
+
* - `tablist` is calculated based on the deepest common parent of the tabs,
|
25
|
+
* throws an error if not found.
|
26
|
+
*
|
27
|
+
* ### Attributes
|
28
|
+
*
|
29
|
+
* `orientation`
|
30
|
+
*
|
31
|
+
* Set `orientation="vertical"` if the `tablist` element is displayed vertically.
|
32
|
+
*/
|
33
|
+
export declare class Tabs extends Base {
|
34
|
+
#private;
|
35
|
+
constructor();
|
36
|
+
mount(): void;
|
37
|
+
}
|
@@ -0,0 +1,147 @@
|
|
1
|
+
import { Base } from "../base/index.js";
|
2
|
+
/**
|
3
|
+
* Progressively enhance a list of links and content to be tabs by
|
4
|
+
* wrapping with the `Tabs` element. Each `trigger` should be an
|
5
|
+
* `HTMLAnchorElement` with the `href` attribute set to the `id` of the
|
6
|
+
* corresponding tab panel.
|
7
|
+
*
|
8
|
+
* > Tip: Set the `height` of the element the panels are contained in with
|
9
|
+
* > CSS to prevent layout shift when JS is loaded.
|
10
|
+
*
|
11
|
+
* This element is based on
|
12
|
+
* [Chris Ferdinandi's Toggle Tabs](https://gomakethings.com/a-web-component-ui-library-for-people-who-love-html/#toggle-tabs)
|
13
|
+
* design.
|
14
|
+
*
|
15
|
+
* [ARIA Reference](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/)
|
16
|
+
*
|
17
|
+
* - Sets the correct ARIA attributes on each element.
|
18
|
+
* - Supports keyboard navigation based on the `orientation` attribute.
|
19
|
+
* - First tab is selected by default if no `aria-selected="true"` attribute is
|
20
|
+
* found on another tab.
|
21
|
+
* - `tablist` is calculated based on the deepest common parent of the tabs,
|
22
|
+
* throws an error if not found.
|
23
|
+
*
|
24
|
+
* ### Attributes
|
25
|
+
*
|
26
|
+
* `orientation`
|
27
|
+
*
|
28
|
+
* Set `orientation="vertical"` if the `tablist` element is displayed vertically.
|
29
|
+
*/
|
30
|
+
export class Tabs extends Base {
|
31
|
+
/** Supported keys for keyboard navigation. */
|
32
|
+
#keys = ["ArrowRight", "ArrowDown", "ArrowLeft", "ArrowUp", "Home", "End"];
|
33
|
+
/** Currently selected tab. */
|
34
|
+
#selected = { index: 0 };
|
35
|
+
constructor() {
|
36
|
+
super();
|
37
|
+
}
|
38
|
+
/** User provided orientation of the `tablist`. */
|
39
|
+
get #orientation() {
|
40
|
+
return this.getAttribute("orientation") ?? "horizontal";
|
41
|
+
}
|
42
|
+
get #tabs() {
|
43
|
+
return this.getTrigger(HTMLAnchorElement);
|
44
|
+
}
|
45
|
+
/**
|
46
|
+
* @param tab
|
47
|
+
* @returns The ancestors of the tab up to `this`.
|
48
|
+
*/
|
49
|
+
#ancestors(tab) {
|
50
|
+
const ancestors = new Set();
|
51
|
+
let current = tab;
|
52
|
+
while ((current = current?.parentElement) && current !== this) {
|
53
|
+
ancestors.add(current);
|
54
|
+
}
|
55
|
+
return ancestors;
|
56
|
+
}
|
57
|
+
/** A map of each `tab` and its corresponding `panel`. */
|
58
|
+
get #map() {
|
59
|
+
const map = new Map();
|
60
|
+
for (const tab of this.#tabs) {
|
61
|
+
const panel = this.querySelector(tab.hash);
|
62
|
+
if (!(panel instanceof HTMLElement))
|
63
|
+
throw new Error(`Tabs: No HTMLElement with ID of ${tab.hash} found.`);
|
64
|
+
map.set(tab, panel);
|
65
|
+
}
|
66
|
+
return map;
|
67
|
+
}
|
68
|
+
mount() {
|
69
|
+
// create tablist
|
70
|
+
const [first, ...rest] = this.#tabs;
|
71
|
+
let common = this.#ancestors(first);
|
72
|
+
for (let i = 0; i < rest.length; i++) {
|
73
|
+
common = common.intersection(this.#ancestors(rest[i]));
|
74
|
+
}
|
75
|
+
const [tablist] = common;
|
76
|
+
if (!tablist)
|
77
|
+
throw new Error("Tabs: No common parent element found for triggers.");
|
78
|
+
tablist.role = "tablist";
|
79
|
+
tablist.ariaOrientation = this.#orientation;
|
80
|
+
// enhance tabs/panels
|
81
|
+
let index = 0;
|
82
|
+
for (const [tab, panel] of this.#map) {
|
83
|
+
tab.role = "tab";
|
84
|
+
tab.id = `tab-${panel.id}`;
|
85
|
+
tab.setAttribute("aria-controls", panel.id);
|
86
|
+
if (tab.ariaSelected)
|
87
|
+
this.#selected = { tab, index };
|
88
|
+
panel.role = "tabpanel";
|
89
|
+
panel.setAttribute("aria-labelledby", tab.id);
|
90
|
+
tab.addEventListener(this.event, (e) => {
|
91
|
+
e.preventDefault();
|
92
|
+
for (const [t, p] of this.#map) {
|
93
|
+
if (t === tab) {
|
94
|
+
// show current
|
95
|
+
t.ariaSelected = "true";
|
96
|
+
t.tabIndex = 0;
|
97
|
+
p.hidden = false;
|
98
|
+
}
|
99
|
+
else {
|
100
|
+
// hide others
|
101
|
+
t.ariaSelected = "false";
|
102
|
+
t.tabIndex = -1;
|
103
|
+
p.hidden = true;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
});
|
107
|
+
index++;
|
108
|
+
}
|
109
|
+
// fallback to first
|
110
|
+
if (!this.#selected.tab)
|
111
|
+
this.#selected.tab = this.#tabs[0];
|
112
|
+
// select the current tab
|
113
|
+
this.#selected.tab?.click();
|
114
|
+
// handle keyboard navigation
|
115
|
+
this.addEventListener("keydown", (e) => {
|
116
|
+
const i = this.#keys.indexOf(e.key);
|
117
|
+
if (i === -1)
|
118
|
+
return;
|
119
|
+
const previousIndex = this.#selected.index;
|
120
|
+
const vertical = this.#orientation === "vertical";
|
121
|
+
if (((!vertical && i === 0) || (vertical && i === 1)) &&
|
122
|
+
this.#tabs[this.#selected.index + 1]) {
|
123
|
+
// next
|
124
|
+
this.#selected.tab = this.#tabs[++this.#selected.index];
|
125
|
+
}
|
126
|
+
else if (((!vertical && i === 2) || (vertical && i === 3)) &&
|
127
|
+
this.#tabs[this.#selected.index - 1]) {
|
128
|
+
// previous
|
129
|
+
this.#selected.tab = this.#tabs[--this.#selected.index];
|
130
|
+
}
|
131
|
+
else if (i === 4) {
|
132
|
+
// home
|
133
|
+
this.#selected = { tab: this.#tabs[0], index: 0 };
|
134
|
+
}
|
135
|
+
else if (i === 5) {
|
136
|
+
// end
|
137
|
+
const index = this.#tabs.length - 1;
|
138
|
+
this.#selected = { tab: this.#tabs[index], index };
|
139
|
+
}
|
140
|
+
if (this.#selected.index === previousIndex)
|
141
|
+
return;
|
142
|
+
e.preventDefault();
|
143
|
+
this.#selected.tab?.click();
|
144
|
+
this.#selected.tab?.focus();
|
145
|
+
});
|
146
|
+
}
|
147
|
+
}
|
package/dist/wakelock/index.d.ts
CHANGED
@@ -4,19 +4,29 @@ export type WakeLockAttributes = BaseAttributes & {
|
|
4
4
|
locked?: boolean;
|
5
5
|
};
|
6
6
|
/**
|
7
|
-
* `WakeLock` uses the
|
7
|
+
* `WakeLock` uses the
|
8
|
+
* [WakeLock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API)
|
9
|
+
* to ensure the screen does not turn off when viewing the page on supported devices.
|
10
|
+
* Use your best judgement for when this is necessary, for example, if you have a timer
|
11
|
+
* that needs to stay on, or you are displaying a QR code.
|
8
12
|
*
|
9
|
-
* - WakeLock can be toggled with a `trigger`, or will be requested if the element has a `locked` attribute when connected.
|
10
13
|
* - Use `content` and `swap` elements to adjust the UI based on the current state.
|
11
14
|
* - `request` and `release` methods are provided to set the WakeLock with JavaScript.
|
12
15
|
* - `trigger` is disabled if not supported.
|
13
16
|
* - WakeLock is released when the element is removed from the DOM.
|
14
17
|
*
|
18
|
+
* ### Attributes
|
19
|
+
*
|
15
20
|
* `auto-lock`
|
16
21
|
*
|
17
|
-
*
|
22
|
+
* By default, the WakeLock will be released when the tab is not active. Use the
|
23
|
+
* `auto-lock` attribute to automatically request the WakeLock when the user views
|
24
|
+
* the tab again.
|
18
25
|
*
|
26
|
+
* `locked`
|
19
27
|
*
|
28
|
+
* WakeLock can be toggled with a `trigger`, or will be requested if the element has
|
29
|
+
* a `locked` attribute when connected.
|
20
30
|
*/
|
21
31
|
export declare class WakeLock extends Base {
|
22
32
|
#private;
|
package/dist/wakelock/index.js
CHANGED
@@ -1,18 +1,28 @@
|
|
1
1
|
import { Base } from "../base/index.js";
|
2
2
|
/**
|
3
|
-
* `WakeLock` uses the
|
3
|
+
* `WakeLock` uses the
|
4
|
+
* [WakeLock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API)
|
5
|
+
* to ensure the screen does not turn off when viewing the page on supported devices.
|
6
|
+
* Use your best judgement for when this is necessary, for example, if you have a timer
|
7
|
+
* that needs to stay on, or you are displaying a QR code.
|
4
8
|
*
|
5
|
-
* - WakeLock can be toggled with a `trigger`, or will be requested if the element has a `locked` attribute when connected.
|
6
9
|
* - Use `content` and `swap` elements to adjust the UI based on the current state.
|
7
10
|
* - `request` and `release` methods are provided to set the WakeLock with JavaScript.
|
8
11
|
* - `trigger` is disabled if not supported.
|
9
12
|
* - WakeLock is released when the element is removed from the DOM.
|
10
13
|
*
|
14
|
+
* ### Attributes
|
15
|
+
*
|
11
16
|
* `auto-lock`
|
12
17
|
*
|
13
|
-
*
|
18
|
+
* By default, the WakeLock will be released when the tab is not active. Use the
|
19
|
+
* `auto-lock` attribute to automatically request the WakeLock when the user views
|
20
|
+
* the tab again.
|
14
21
|
*
|
22
|
+
* `locked`
|
15
23
|
*
|
24
|
+
* WakeLock can be toggled with a `trigger`, or will be requested if the element has
|
25
|
+
* a `locked` attribute when connected.
|
16
26
|
*/
|
17
27
|
export class WakeLock extends Base {
|
18
28
|
wakeLock = null;
|