drab 6.3.0 → 6.4.1
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.js +1 -1
- package/dist/base/index.d.ts +2895 -70
- package/dist/base/index.js +64 -48
- package/dist/copy/index.js +1 -1
- package/dist/dialog/index.d.ts +2 -2
- package/dist/dialog/index.js +2 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tabs/index.d.ts +1 -1
- package/dist/tabs/index.js +1 -1
- package/dist/util/validate.d.ts +7 -0
- package/dist/util/validate.js +10 -0
- package/package.json +1 -1
package/dist/base/index.js
CHANGED
@@ -1,26 +1,8 @@
|
|
1
1
|
import { Announcer } from "../announcer/index.js";
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
* By default, `trigger`s and `content` will be selected via the `data-trigger` and
|
7
|
-
* `data-content` attributes. Alternatively, you can set the `trigger` or
|
8
|
-
* `content` attribute to a CSS selector to change the default selector from
|
9
|
-
* `[data-trigger]` or `[data-content]` to a selector of your choosing.
|
10
|
-
* This can be useful if you have multiple elements within one another.
|
11
|
-
*
|
12
|
-
* Each element can have multiple `trigger`s, but will only have one `content`.
|
13
|
-
*/
|
14
|
-
export class Base extends HTMLElement {
|
15
|
-
/**
|
16
|
-
* A single `Announcer` element to share between all drab elements to announce
|
17
|
-
* interactive changes.
|
18
|
-
*/
|
19
|
-
static #announcer = Announcer.init();
|
20
|
-
/** To clean up event listeners added to `document` when the element is removed. */
|
21
|
-
#listenerController = new AbortController();
|
22
|
-
constructor() {
|
23
|
-
super();
|
2
|
+
import { validate } from "../util/validate.js";
|
3
|
+
export const Trigger = (Super) => class Trigger extends Super {
|
4
|
+
constructor(...args) {
|
5
|
+
super(args);
|
24
6
|
}
|
25
7
|
/**
|
26
8
|
* Event for the `trigger` to execute.
|
@@ -30,25 +12,32 @@ export class Base extends HTMLElement {
|
|
30
12
|
* @default "click"
|
31
13
|
*/
|
32
14
|
get event() {
|
33
|
-
return this.getAttribute("event") ?? "click";
|
15
|
+
return (this.getAttribute("event") ?? "click");
|
34
16
|
}
|
35
17
|
set event(value) {
|
36
18
|
this.setAttribute("event", value);
|
37
19
|
}
|
38
|
-
/**
|
39
|
-
* @param message message to announce to screen readers
|
40
|
-
*/
|
41
|
-
announce(message) {
|
42
|
-
Base.#announcer.announce(message);
|
43
|
-
}
|
44
20
|
getTrigger(instance = HTMLElement) {
|
45
21
|
const triggers = this.querySelectorAll(this.getAttribute("trigger") ?? "[data-trigger]");
|
46
22
|
for (const trigger of triggers)
|
47
|
-
|
23
|
+
validate(trigger, instance);
|
48
24
|
return triggers;
|
49
25
|
}
|
26
|
+
/**
|
27
|
+
* @param listener Listener to attach to all of the `trigger` elements.
|
28
|
+
*/
|
29
|
+
triggerListener(listener, type = this.event, options) {
|
30
|
+
for (const trigger of this.getTrigger()) {
|
31
|
+
trigger.addEventListener(type, listener, options);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
};
|
35
|
+
export const Content = (Super) => class Content extends Super {
|
36
|
+
constructor(...args) {
|
37
|
+
super(args);
|
38
|
+
}
|
50
39
|
getContent(instance = HTMLElement) {
|
51
|
-
return
|
40
|
+
return validate(this.querySelector(this.getAttribute("content") ?? "[data-content]"), instance);
|
52
41
|
}
|
53
42
|
/**
|
54
43
|
* Finds the `HTMLElement | HTMLTemplateElement` via the `swap` selector and
|
@@ -88,22 +77,26 @@ export class Base extends HTMLElement {
|
|
88
77
|
}
|
89
78
|
}
|
90
79
|
}
|
80
|
+
};
|
81
|
+
export const Lifecycle = (Super) => class Lifecycle extends Super {
|
82
|
+
/** To clean up event listeners added to `document` when the element is removed. */
|
83
|
+
#listenerController = new AbortController();
|
84
|
+
constructor(...args) {
|
85
|
+
super(args);
|
86
|
+
}
|
91
87
|
safeListener(type, listener, target = document.body, options = {}) {
|
92
88
|
options.signal = this.#listenerController.signal;
|
93
89
|
target.addEventListener(type, listener, options);
|
94
90
|
}
|
95
91
|
/**
|
96
|
-
*
|
97
|
-
|
98
|
-
triggerListener(listener, type = this.event, options) {
|
99
|
-
for (const trigger of this.getTrigger()) {
|
100
|
-
trigger.addEventListener(type, listener, options);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
/**
|
104
|
-
* Passed into `queueMicrotask` in `connectedCallback`. It is overridden in each component that needs to run `connectedCallback`.
|
92
|
+
* Passed into `queueMicrotask` in `connectedCallback`.
|
93
|
+
* It is overridden in each component that needs to run `connectedCallback`.
|
105
94
|
*
|
106
|
-
* The reason for this is to make these elements work better with frameworks like Svelte.
|
95
|
+
* The reason for this is to make these elements work better with frameworks like Svelte.
|
96
|
+
* For SSR this isn't necessary, but when client side rendering, the HTML within the
|
97
|
+
* custom element isn't available before `connectedCallback` is called. By waiting until
|
98
|
+
* the next microtask, the HTML content is available---then for example, listeners can
|
99
|
+
* be attached to elements inside.
|
107
100
|
*/
|
108
101
|
mount() { }
|
109
102
|
/** Called when custom element is added to the page. */
|
@@ -119,14 +112,37 @@ export class Base extends HTMLElement {
|
|
119
112
|
this.destroy();
|
120
113
|
this.#listenerController.abort();
|
121
114
|
}
|
115
|
+
};
|
116
|
+
export const Announce = (Super) => class Announce extends Super {
|
117
|
+
/**
|
118
|
+
* A single `Announcer` element to share between all drab elements to announce
|
119
|
+
* interactive changes.
|
120
|
+
*/
|
121
|
+
static #announcer = Announcer.init();
|
122
|
+
constructor(...args) {
|
123
|
+
super(args);
|
124
|
+
}
|
122
125
|
/**
|
123
|
-
* @param
|
124
|
-
* @param expected Constructor of the expected element.
|
125
|
-
* @returns If valid returns `actual` otherwise throws `TypeError`.
|
126
|
+
* @param message message to announce to screen readers
|
126
127
|
*/
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
128
|
+
announce(message) {
|
129
|
+
Announce.#announcer.announce(message);
|
130
|
+
}
|
131
|
+
};
|
132
|
+
/**
|
133
|
+
* Each element in the library extends the `Base` class. It provides methods
|
134
|
+
* for selecting elements via HTML attributes along with other helpers.
|
135
|
+
*
|
136
|
+
* By default, `trigger`s and `content` will be selected via the `data-trigger` and
|
137
|
+
* `data-content` attributes. Alternatively, you can set the `trigger` or
|
138
|
+
* `content` attribute to a CSS selector to change the default selector from
|
139
|
+
* `[data-trigger]` or `[data-content]` to a selector of your choosing.
|
140
|
+
* This can be useful if you have multiple elements within one another.
|
141
|
+
*
|
142
|
+
* Each element can have multiple `trigger`s, but will only have one `content`.
|
143
|
+
*/
|
144
|
+
export class Base extends Trigger(Content(Lifecycle(Announce(HTMLElement)))) {
|
145
|
+
constructor() {
|
146
|
+
super();
|
131
147
|
}
|
132
148
|
}
|
package/dist/copy/index.js
CHANGED
@@ -29,7 +29,7 @@ export class Copy extends Base {
|
|
29
29
|
* @param value The `value` to copy
|
30
30
|
*/
|
31
31
|
copy(value = this.value) {
|
32
|
-
this.announce(
|
32
|
+
this.announce("copied text to clipboard");
|
33
33
|
this.swapContent();
|
34
34
|
return navigator.clipboard.writeText(value);
|
35
35
|
}
|
package/dist/dialog/index.d.ts
CHANGED
@@ -23,9 +23,9 @@ export declare class Dialog extends Base {
|
|
23
23
|
constructor();
|
24
24
|
/** The `HTMLDialogElement` within the element. */
|
25
25
|
get dialog(): HTMLDialogElement;
|
26
|
-
/** `HTMLDialogElement.showModal()
|
26
|
+
/** Wraps `HTMLDialogElement.showModal()`. */
|
27
27
|
show(): void;
|
28
|
-
/** `HTMLDialogElement.close()
|
28
|
+
/** Wraps `HTMLDialogElement.close()`. */
|
29
29
|
close(): void;
|
30
30
|
/** `show` or `close` depending on the dialog's `open` attribute. */
|
31
31
|
toggle(): void;
|
package/dist/dialog/index.js
CHANGED
@@ -15,7 +15,6 @@ import { Base } from "../base/index.js";
|
|
15
15
|
* is open.
|
16
16
|
*/
|
17
17
|
export class Dialog extends Base {
|
18
|
-
/** The initial margin-right value of the body element. */
|
19
18
|
#initialBodyMarginRight = parseInt(getComputedStyle(document.body).marginRight);
|
20
19
|
constructor() {
|
21
20
|
super();
|
@@ -36,12 +35,12 @@ export class Dialog extends Base {
|
|
36
35
|
document.body.style.overflow = show ? "hidden" : "";
|
37
36
|
}
|
38
37
|
}
|
39
|
-
/** `HTMLDialogElement.showModal()
|
38
|
+
/** Wraps `HTMLDialogElement.showModal()`. */
|
40
39
|
show() {
|
41
40
|
this.dialog.showModal();
|
42
41
|
this.#toggleBodyScroll(true);
|
43
42
|
}
|
44
|
-
/** `HTMLDialogElement.close()
|
43
|
+
/** Wraps `HTMLDialogElement.close()`. */
|
45
44
|
close() {
|
46
45
|
this.#toggleBodyScroll(false);
|
47
46
|
this.dialog.close();
|
@@ -57,7 +56,6 @@ export class Dialog extends Base {
|
|
57
56
|
this.triggerListener(() => this.toggle());
|
58
57
|
this.safeListener("keydown", (e) => {
|
59
58
|
if (e.key === "Escape" && this.dialog.open) {
|
60
|
-
// to execute animation
|
61
59
|
e.preventDefault();
|
62
60
|
this.close();
|
63
61
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/tabs/index.d.ts
CHANGED
@@ -8,7 +8,7 @@ export type TabAttributes = BaseAttributes & {
|
|
8
8
|
* `HTMLAnchorElement` with the `href` attribute set to the `id` of the
|
9
9
|
* corresponding tab panel.
|
10
10
|
*
|
11
|
-
* > Tip: Set the `height` of the element the
|
11
|
+
* > Tip: Set the `height` of the element the `panel`s are contained in with
|
12
12
|
* > CSS to prevent layout shift when JS is loaded.
|
13
13
|
*
|
14
14
|
* This element is based on
|
package/dist/tabs/index.js
CHANGED
@@ -5,7 +5,7 @@ import { Base } from "../base/index.js";
|
|
5
5
|
* `HTMLAnchorElement` with the `href` attribute set to the `id` of the
|
6
6
|
* corresponding tab panel.
|
7
7
|
*
|
8
|
-
* > Tip: Set the `height` of the element the
|
8
|
+
* > Tip: Set the `height` of the element the `panel`s are contained in with
|
9
9
|
* > CSS to prevent layout shift when JS is loaded.
|
10
10
|
*
|
11
11
|
* This element is based on
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import type { Constructor } from "../base/index.js";
|
2
|
+
/**
|
3
|
+
* @param actual Element to validate.
|
4
|
+
* @param expected Constructor of the expected element.
|
5
|
+
* @returns If valid returns `actual` otherwise throws `TypeError`.
|
6
|
+
*/
|
7
|
+
export declare const validate: <T extends HTMLElement>(actual: unknown, expected: Constructor<T>) => T;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* @param actual Element to validate.
|
3
|
+
* @param expected Constructor of the expected element.
|
4
|
+
* @returns If valid returns `actual` otherwise throws `TypeError`.
|
5
|
+
*/
|
6
|
+
export const validate = (actual, expected) => {
|
7
|
+
if (!(actual instanceof expected))
|
8
|
+
throw new TypeError(`${actual} is not an instance of ${expected.name}.`);
|
9
|
+
return actual;
|
10
|
+
};
|