drab 6.0.0 → 6.1.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/define.d.ts +1 -0
- package/dist/announcer/define.js +3 -0
- package/dist/announcer/index.d.ts +49 -0
- package/dist/announcer/index.js +80 -0
- package/dist/base/copy/index.js +1 -0
- package/dist/base/define.js +2 -1
- package/dist/base/index.d.ts +8 -8
- package/dist/base/index.js +15 -9
- package/dist/contextmenu/define.js +2 -1
- package/dist/copy/define.js +2 -1
- package/dist/define.js +3 -2
- package/dist/dialog/define.js +2 -1
- package/dist/editor/define.js +2 -1
- package/dist/editor/index.d.ts +6 -1
- package/dist/editor/index.js +181 -310
- package/dist/fullscreen/define.js +2 -1
- package/dist/index.d.ts +13 -12
- package/dist/index.js +13 -12
- package/dist/intersect/define.js +2 -1
- package/dist/intersect/index.js +1 -3
- package/dist/prefetch/define.js +2 -1
- package/dist/prefetch/index.js +1 -6
- package/dist/share/define.js +2 -1
- package/dist/tablesort/define.js +2 -1
- package/dist/tablesort/index.d.ts +4 -0
- package/dist/tablesort/index.js +32 -20
- package/dist/util/define.d.ts +8 -0
- package/dist/util/define.js +11 -0
- package/dist/wakelock/define.js +2 -1
- package/dist/wakelock/index.js +2 -0
- package/dist/youtube/define.js +2 -1
- package/package.json +9 -1
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,49 @@
|
|
1
|
+
/**
|
2
|
+
* Use the `Announcer` element to create a visually hidden ARIA live region
|
3
|
+
* that announces content changes to screen readers. Use this element when you
|
4
|
+
* need to announce changes to screen readers that something has changed. If changed
|
5
|
+
* element is visible on the page, add the appropriate ARIA live attribute to the
|
6
|
+
* visible element instead of using this announcer.
|
7
|
+
*
|
8
|
+
* It's recommended to create this element with JavaScript using the `Announcer.init` method,
|
9
|
+
* then you can reuse the same announcer throughout the application to
|
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
|
+
* (see below).
|
12
|
+
*
|
13
|
+
* `aria-live`
|
14
|
+
*
|
15
|
+
* By default, the announcer is created with the
|
16
|
+
* [`polite` ARIA live attribute](https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-1/#1.-using-the-aria-live-attribute).
|
17
|
+
*
|
18
|
+
* @example
|
19
|
+
*
|
20
|
+
* ```ts
|
21
|
+
* import { Announcer } from "drab/announcer";
|
22
|
+
*
|
23
|
+
* // creates and appends a new announcer to the body element
|
24
|
+
* const announcer = Announcer.init();
|
25
|
+
*
|
26
|
+
* // create announcement
|
27
|
+
* announcer.announce("message");
|
28
|
+
* ```
|
29
|
+
*
|
30
|
+
* > The `Base` element creates a single `Announcer` to share between all elements
|
31
|
+
* > that can be accessed through `this.announce`. If you are using one of drab's other
|
32
|
+
* > elements you can call `announce` directly on the element to announce changes.
|
33
|
+
*/
|
34
|
+
export declare class Announcer extends HTMLElement {
|
35
|
+
constructor();
|
36
|
+
connectedCallback(): void;
|
37
|
+
/**
|
38
|
+
* @param message message to announce to screen readers
|
39
|
+
*/
|
40
|
+
announce(message: string): void;
|
41
|
+
/**
|
42
|
+
* Helper method to create a new `Announcer` element named `drab-announcer`
|
43
|
+
* and append the element to the `<body>` tag. If an announcer already exists
|
44
|
+
* on the page it will return the existing element.
|
45
|
+
*
|
46
|
+
* @returns the created or existing `Announcer` element
|
47
|
+
*/
|
48
|
+
static init(): Announcer;
|
49
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import { define } from "../util/define.js";
|
2
|
+
/**
|
3
|
+
* Use the `Announcer` element to create a visually hidden ARIA live region
|
4
|
+
* that announces content changes to screen readers. Use this element when you
|
5
|
+
* need to announce changes to screen readers that something has changed. If changed
|
6
|
+
* element is visible on the page, add the appropriate ARIA live attribute to the
|
7
|
+
* visible element instead of using this announcer.
|
8
|
+
*
|
9
|
+
* It's recommended to create this element with JavaScript using the `Announcer.init` method,
|
10
|
+
* then you can reuse the same announcer throughout the application to
|
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
|
+
* (see below).
|
13
|
+
*
|
14
|
+
* `aria-live`
|
15
|
+
*
|
16
|
+
* By default, the announcer is created with the
|
17
|
+
* [`polite` ARIA live attribute](https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-1/#1.-using-the-aria-live-attribute).
|
18
|
+
*
|
19
|
+
* @example
|
20
|
+
*
|
21
|
+
* ```ts
|
22
|
+
* import { Announcer } from "drab/announcer";
|
23
|
+
*
|
24
|
+
* // creates and appends a new announcer to the body element
|
25
|
+
* const announcer = Announcer.init();
|
26
|
+
*
|
27
|
+
* // create announcement
|
28
|
+
* announcer.announce("message");
|
29
|
+
* ```
|
30
|
+
*
|
31
|
+
* > The `Base` element creates a single `Announcer` to share between all elements
|
32
|
+
* > that can be accessed through `this.announce`. If you are using one of drab's other
|
33
|
+
* > elements you can call `announce` directly on the element to announce changes.
|
34
|
+
*/
|
35
|
+
export class Announcer extends HTMLElement {
|
36
|
+
constructor() {
|
37
|
+
super();
|
38
|
+
}
|
39
|
+
connectedCallback() {
|
40
|
+
this.style.position = "absolute";
|
41
|
+
this.style.width = "1px";
|
42
|
+
this.style.height = "1px";
|
43
|
+
this.style.padding = "0";
|
44
|
+
this.style.margin = "-1px";
|
45
|
+
this.style.overflow = "hidden";
|
46
|
+
this.style.clipPath = "rect(0, 0, 0, 0)";
|
47
|
+
this.style.whiteSpace = "nowrap";
|
48
|
+
this.style.borderWidth = "0";
|
49
|
+
if (!this.ariaLive)
|
50
|
+
this.ariaLive = "polite";
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* @param message message to announce to screen readers
|
54
|
+
*/
|
55
|
+
announce(message) {
|
56
|
+
// this ensures multiple messages will be read in succession
|
57
|
+
const span = document.createElement("span");
|
58
|
+
span.textContent = message;
|
59
|
+
this.append(span);
|
60
|
+
// https://www.sarasoueidan.com/blog/accessible-notifications-with-aria-live-regions-part-2/#empty-the-live-region-and-wait-a-bit-in-between-updates
|
61
|
+
setTimeout(() => span.remove(), 10000);
|
62
|
+
}
|
63
|
+
/**
|
64
|
+
* Helper method to create a new `Announcer` element named `drab-announcer`
|
65
|
+
* and append the element to the `<body>` tag. If an announcer already exists
|
66
|
+
* on the page it will return the existing element.
|
67
|
+
*
|
68
|
+
* @returns the created or existing `Announcer` element
|
69
|
+
*/
|
70
|
+
static init() {
|
71
|
+
define("drab-announcer", this);
|
72
|
+
const name = "drab-announcer";
|
73
|
+
let announcer = document.querySelector(name);
|
74
|
+
if (!announcer) {
|
75
|
+
announcer = document.createElement(name);
|
76
|
+
document.body.append(announcer);
|
77
|
+
}
|
78
|
+
return announcer;
|
79
|
+
}
|
80
|
+
}
|
package/dist/base/copy/index.js
CHANGED
package/dist/base/define.js
CHANGED
package/dist/base/index.d.ts
CHANGED
@@ -27,14 +27,18 @@ export declare class Base extends HTMLElement {
|
|
27
27
|
*/
|
28
28
|
get event(): keyof HTMLElementEventMap;
|
29
29
|
set event(value: keyof HTMLElementEventMap);
|
30
|
+
/**
|
31
|
+
* @param message message to announce to screen readers
|
32
|
+
*/
|
33
|
+
announce(message: string): void;
|
30
34
|
/**
|
31
35
|
* @returns All of the elements that match the `trigger` selector.
|
32
36
|
* @default this.querySelectorAll("[data-trigger]")
|
33
37
|
*/
|
34
38
|
getTrigger<T extends HTMLElement = HTMLElement>(): NodeListOf<T>;
|
35
39
|
/**
|
36
|
-
* @param instance The instance of the desired element
|
37
|
-
* Defaults to `HTMLElement`.
|
40
|
+
* @param instance The instance of the desired element to validate against,
|
41
|
+
* ex: `HTMLDialogElement`. Defaults to `HTMLElement`.
|
38
42
|
* @returns The element that matches the `content` selector.
|
39
43
|
* @default this.querySelector("[data-content]")
|
40
44
|
*/
|
@@ -67,16 +71,12 @@ export declare class Base extends HTMLElement {
|
|
67
71
|
* The reason for this is to make these elements work better with frameworks like Svelte. For SSR this isn't necessary, but when client side rendering, the HTML within the custom element isn't available before `connectedCallback` is called. By waiting until the next microtask, the HTML content is available---then for example, listeners can be attached to elements inside.
|
68
72
|
*/
|
69
73
|
mount(): void;
|
70
|
-
/**
|
71
|
-
* Called when custom element is added to the page.
|
72
|
-
*/
|
74
|
+
/** Called when custom element is added to the page. */
|
73
75
|
connectedCallback(): void;
|
74
76
|
/**
|
75
77
|
* Passed into `disconnectedCallback`, since `Base` needs to run `disconnectedCallback` as well. It is overridden in each element that needs to run `disconnectedCallback`.
|
76
78
|
*/
|
77
79
|
destroy(): void;
|
78
|
-
/**
|
79
|
-
* Called when custom element is removed from the page.
|
80
|
-
*/
|
80
|
+
/** Called when custom element is removed from the page. */
|
81
81
|
disconnectedCallback(): void;
|
82
82
|
}
|
package/dist/base/index.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { Announcer } from "../announcer/index.js";
|
1
2
|
/**
|
2
3
|
* Each element in the library extends the `Base` class. It provides methods
|
3
4
|
* for selecting elements via HTML attributes along with other helpers.
|
@@ -12,8 +13,11 @@
|
|
12
13
|
*/
|
13
14
|
export class Base extends HTMLElement {
|
14
15
|
/**
|
15
|
-
*
|
16
|
+
* A single `Announcer` element to share between all drab elements to announce
|
17
|
+
* interactive changes.
|
16
18
|
*/
|
19
|
+
static #announcer = Announcer.init();
|
20
|
+
/** To clean up event listeners added to `document` when the element is removed. */
|
17
21
|
#listenerController = new AbortController();
|
18
22
|
constructor() {
|
19
23
|
super();
|
@@ -31,6 +35,12 @@ export class Base extends HTMLElement {
|
|
31
35
|
set event(value) {
|
32
36
|
this.setAttribute("event", value);
|
33
37
|
}
|
38
|
+
/**
|
39
|
+
* @param message message to announce to screen readers
|
40
|
+
*/
|
41
|
+
announce(message) {
|
42
|
+
Base.#announcer.announce(message);
|
43
|
+
}
|
34
44
|
/**
|
35
45
|
* @returns All of the elements that match the `trigger` selector.
|
36
46
|
* @default this.querySelectorAll("[data-trigger]")
|
@@ -40,8 +50,8 @@ export class Base extends HTMLElement {
|
|
40
50
|
return triggers;
|
41
51
|
}
|
42
52
|
/**
|
43
|
-
* @param instance The instance of the desired element
|
44
|
-
* Defaults to `HTMLElement`.
|
53
|
+
* @param instance The instance of the desired element to validate against,
|
54
|
+
* ex: `HTMLDialogElement`. Defaults to `HTMLElement`.
|
45
55
|
* @returns The element that matches the `content` selector.
|
46
56
|
* @default this.querySelector("[data-content]")
|
47
57
|
*/
|
@@ -115,9 +125,7 @@ export class Base extends HTMLElement {
|
|
115
125
|
* The reason for this is to make these elements work better with frameworks like Svelte. For SSR this isn't necessary, but when client side rendering, the HTML within the custom element isn't available before `connectedCallback` is called. By waiting until the next microtask, the HTML content is available---then for example, listeners can be attached to elements inside.
|
116
126
|
*/
|
117
127
|
mount() { }
|
118
|
-
/**
|
119
|
-
* Called when custom element is added to the page.
|
120
|
-
*/
|
128
|
+
/** Called when custom element is added to the page. */
|
121
129
|
connectedCallback() {
|
122
130
|
queueMicrotask(() => this.mount());
|
123
131
|
}
|
@@ -125,9 +133,7 @@ export class Base extends HTMLElement {
|
|
125
133
|
* Passed into `disconnectedCallback`, since `Base` needs to run `disconnectedCallback` as well. It is overridden in each element that needs to run `disconnectedCallback`.
|
126
134
|
*/
|
127
135
|
destroy() { }
|
128
|
-
/**
|
129
|
-
* Called when custom element is removed from the page.
|
130
|
-
*/
|
136
|
+
/** Called when custom element is removed from the page. */
|
131
137
|
disconnectedCallback() {
|
132
138
|
this.destroy();
|
133
139
|
this.#listenerController.abort();
|
package/dist/copy/define.js
CHANGED
package/dist/define.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import * as elements from "./index.js";
|
2
|
-
|
3
|
-
|
2
|
+
import { define } from "./util/define.js";
|
3
|
+
for (const [name, Constructor] of Object.entries(elements)) {
|
4
|
+
define(`drab-${name.toLowerCase()}`, Constructor);
|
4
5
|
}
|
package/dist/dialog/define.js
CHANGED
package/dist/editor/define.js
CHANGED
package/dist/editor/index.d.ts
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
import { Base, type BaseAttributes } from "../base/index.js";
|
2
2
|
export type EditorAttributes = BaseAttributes;
|
3
|
+
export type EditorTriggerAttributes = {
|
4
|
+
"data-value": string;
|
5
|
+
"data-key": string;
|
6
|
+
"data-type": "block" | "wrap" | "inline";
|
7
|
+
};
|
3
8
|
/**
|
4
9
|
* A piece of content to insert into the `textarea`.
|
5
10
|
*/
|
@@ -42,7 +47,7 @@ export type ContentElement = {
|
|
42
47
|
*/
|
43
48
|
export declare class Editor extends Base {
|
44
49
|
#private;
|
45
|
-
/**
|
50
|
+
/** Characters that will be automatically closed when typed. */
|
46
51
|
keyPairs: {
|
47
52
|
[key: string]: string;
|
48
53
|
};
|
package/dist/editor/index.js
CHANGED
@@ -29,9 +29,11 @@ import { Base } from "../base/index.js";
|
|
29
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
30
|
*/
|
31
31
|
export class Editor extends Base {
|
32
|
-
/** Array of keyPair characters that have been opened. */
|
32
|
+
/** Array of `keyPair` characters that have been opened. */
|
33
33
|
#openChars = [];
|
34
|
-
/**
|
34
|
+
/** Keys that will reset the type over for keyPairs */
|
35
|
+
#resetKeys = new Set(["ArrowUp", "ArrowDown", "Delete"]);
|
36
|
+
/** Characters that will be automatically closed when typed. */
|
35
37
|
keyPairs = {
|
36
38
|
"(": ")",
|
37
39
|
"{": "}",
|
@@ -44,9 +46,8 @@ export class Editor extends Base {
|
|
44
46
|
super();
|
45
47
|
// add any `type: "wrap"` values from `contentElements` to `keyPairs`
|
46
48
|
for (const element of this.#contentElements) {
|
47
|
-
if (element.type === "wrap")
|
49
|
+
if (element.type === "wrap")
|
48
50
|
this.keyPairs[element.value] = element.value;
|
49
|
-
}
|
50
51
|
}
|
51
52
|
}
|
52
53
|
/** The `content`, expects an `HTMLTextAreaElement`. */
|
@@ -60,221 +61,150 @@ export class Editor extends Base {
|
|
60
61
|
set text(value) {
|
61
62
|
this.textArea.value = value;
|
62
63
|
}
|
63
|
-
/**
|
64
|
+
/** Array of `ContentElement`s derived from each `trigger`'s data attributes. */
|
64
65
|
get #contentElements() {
|
65
66
|
const contentElements = [];
|
66
67
|
for (const trigger of this.getTrigger()) {
|
67
|
-
contentElements.push(
|
68
|
+
contentElements.push(trigger.dataset);
|
68
69
|
}
|
69
70
|
return contentElements;
|
70
71
|
}
|
71
|
-
/**
|
72
|
-
* - splits the content by "```" and finds the current index
|
73
|
-
* of the selectionStart
|
74
|
-
*
|
75
|
-
* @returns current codeblock (index) of selectionStart
|
76
|
-
*/
|
77
|
-
get #currentBlock() {
|
78
|
-
const blocks = this.text.split("```");
|
79
|
-
let totalChars = 0;
|
80
|
-
for (const [i, block] of blocks.entries()) {
|
81
|
-
totalChars += block.length + 3;
|
82
|
-
if (this.#selectionStart < totalChars) {
|
83
|
-
return i;
|
84
|
-
}
|
85
|
-
}
|
86
|
-
return 0;
|
87
|
-
}
|
88
72
|
/** Gets the end position of the selection */
|
89
|
-
get #
|
73
|
+
get #selEnd() {
|
90
74
|
return this.textArea.selectionEnd;
|
91
75
|
}
|
92
76
|
/** Gets the start position of the selection. */
|
93
|
-
get #
|
77
|
+
get #selStart() {
|
94
78
|
return this.textArea.selectionStart;
|
95
79
|
}
|
96
|
-
/**
|
97
|
-
|
98
|
-
|
80
|
+
/**
|
81
|
+
* @param str string to insert into `text`
|
82
|
+
* @param index where to insert the string
|
83
|
+
*/
|
84
|
+
#insertStr(str, index) {
|
85
|
+
this.text = this.text.slice(0, index) + str + this.text.slice(index);
|
99
86
|
}
|
100
87
|
/**
|
101
|
-
* @param
|
102
|
-
* @
|
88
|
+
* @param start Starting index for removal.
|
89
|
+
* @param end Optional ending index - defaults to start + 1 to remove 1 character.
|
103
90
|
*/
|
104
|
-
#
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
91
|
+
#removeStr(start, end = start + 1) {
|
92
|
+
this.text = this.text.slice(0, start) + this.text.slice(end);
|
93
|
+
}
|
94
|
+
/** Sets the current cursor selection in the `textarea` */
|
95
|
+
#setSelection(start, end = start) {
|
96
|
+
this.textArea.setSelectionRange(start, end);
|
97
|
+
this.textArea.focus();
|
109
98
|
}
|
110
99
|
/**
|
111
|
-
*
|
112
|
-
* the `ContentElement`.
|
100
|
+
* Inserts text and sets selection based on the `ContentElement` selected.
|
113
101
|
*
|
114
|
-
* @param
|
115
|
-
* @param selectionStart current start position the selection
|
116
|
-
* @param selectionEnd current end position of the selection
|
102
|
+
* @param content
|
117
103
|
*/
|
118
|
-
|
119
|
-
|
104
|
+
#addContent({ value, type }) {
|
105
|
+
let start = this.#selStart;
|
106
|
+
if (type === "inline") {
|
120
107
|
// insert at current position
|
121
|
-
this
|
108
|
+
this.#insertStr(value, start);
|
109
|
+
const match = /[a-z]+/i.exec(value);
|
110
|
+
if (match?.index != null) {
|
111
|
+
start += match.index;
|
112
|
+
this.#setSelection(start, start + match[0].length);
|
113
|
+
}
|
114
|
+
else {
|
115
|
+
this.#setSelection(start + value.length);
|
116
|
+
}
|
122
117
|
}
|
123
|
-
else if (
|
124
|
-
|
125
|
-
this
|
118
|
+
else if (type === "wrap") {
|
119
|
+
const end = this.#selEnd + value.length;
|
120
|
+
this.#insertStr(value, start);
|
121
|
+
this.#insertStr(this.keyPairs[value], end);
|
122
|
+
this.#setSelection(start + value.length, end);
|
126
123
|
// if single char, add to opened
|
127
|
-
if (
|
128
|
-
this.#openChars.push(
|
124
|
+
if (value.length === 1)
|
125
|
+
this.#openChars.push(value);
|
129
126
|
}
|
130
|
-
else
|
131
|
-
|
132
|
-
const
|
133
|
-
//
|
127
|
+
else {
|
128
|
+
// "block"
|
129
|
+
const { lines, lineNumber } = this.#lineMeta();
|
130
|
+
// avoids `# # # `, instead adds trimmed => `### `
|
131
|
+
const firstChar = value[0];
|
134
132
|
if (firstChar && lines[lineNumber]?.startsWith(firstChar)) {
|
135
|
-
|
136
|
-
lines[lineNumber] = el.value.trim() + lines[lineNumber];
|
137
|
-
}
|
138
|
-
else {
|
139
|
-
lines[lineNumber] = el.value + lines[lineNumber];
|
133
|
+
value = value.trim();
|
140
134
|
}
|
135
|
+
// add the string to the beginning of the line
|
136
|
+
lines[lineNumber] = value + lines[lineNumber];
|
141
137
|
this.text = lines.join("\n");
|
138
|
+
this.#setSelection(start + value.length);
|
142
139
|
}
|
143
140
|
}
|
144
141
|
/**
|
145
|
-
*
|
146
|
-
* the length of the text.
|
147
|
-
* - Highlights text if the content contains any letters.
|
142
|
+
* Checks if there is a block element at the beginning of the string.
|
148
143
|
*
|
149
|
-
* @param
|
150
|
-
* @
|
151
|
-
* @param selectionEnd current end position of the selection
|
144
|
+
* @param line
|
145
|
+
* @returns Whatever is found, otherwise null
|
152
146
|
*/
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
if (this.text[i]?.match(/[a-z]/i)) {
|
160
|
-
if (!startPos) {
|
161
|
-
startPos = i;
|
162
|
-
}
|
163
|
-
else {
|
164
|
-
endPos = i + 1;
|
165
|
-
}
|
166
|
-
}
|
167
|
-
else if (startPos) {
|
168
|
-
break;
|
169
|
-
}
|
170
|
-
}
|
171
|
-
}
|
172
|
-
else {
|
173
|
-
// leave the cursor in place
|
174
|
-
startPos = selectionStart + text.length;
|
175
|
-
endPos = selectionEnd + text.length;
|
147
|
+
#startsWithBlock(line) {
|
148
|
+
for (const blockString of this.#contentElements
|
149
|
+
.filter((el) => el.type === "block")
|
150
|
+
.map((el) => el.value)) {
|
151
|
+
if (line.startsWith(blockString.trim()))
|
152
|
+
return blockString;
|
176
153
|
}
|
177
|
-
|
178
|
-
this.textArea.focus();
|
179
|
-
}
|
180
|
-
/**
|
181
|
-
* - Inserts the text and then sets the caret position
|
182
|
-
* based on the `ContentElement` selected.
|
183
|
-
*
|
184
|
-
* @param el selected content element
|
185
|
-
*/
|
186
|
-
async #addContent(el) {
|
187
|
-
const selectionEnd = this.#selectionEnd;
|
188
|
-
const selectionStart = this.#selectionStart;
|
189
|
-
await this.#insertText(el, selectionStart, selectionEnd);
|
190
|
-
this.#setCaretPosition(el.value, selectionStart, selectionEnd);
|
154
|
+
return null;
|
191
155
|
}
|
192
156
|
/**
|
193
|
-
*
|
194
|
-
*
|
195
|
-
*
|
196
|
-
* @param str
|
197
|
-
* @returns what is found, or the empty string
|
157
|
+
* @param line
|
158
|
+
* @returns The number, if the line starts with a number and a period.
|
198
159
|
*/
|
199
|
-
#
|
200
|
-
|
201
|
-
|
202
|
-
this.#contentElements.forEach((el) => {
|
203
|
-
if (el.type === "block")
|
204
|
-
blockStrings.push(el.value);
|
205
|
-
});
|
206
|
-
for (let i = 0; i < blockStrings.length; i++) {
|
207
|
-
const repeatString = blockStrings[i];
|
208
|
-
if (repeatString && str.startsWith(repeatString)) {
|
209
|
-
return repeatString;
|
210
|
-
}
|
211
|
-
}
|
212
|
-
const repeatNum = startsWithNumberAndPeriod(str);
|
213
|
-
if (repeatNum)
|
214
|
-
return `${repeatNum}. `;
|
215
|
-
}
|
216
|
-
return "";
|
160
|
+
#startsWithNumberAndPeriod(line) {
|
161
|
+
const match = line.match(/^(\d+)\./);
|
162
|
+
return match ? Number(match[1]) : null;
|
217
163
|
}
|
218
164
|
/**
|
219
|
-
* @returns
|
220
|
-
*
|
221
|
-
* @example
|
222
|
-
*
|
223
|
-
* ```js
|
224
|
-
* const { lines, lineNumber, columnNumber } = getLineInfo();
|
225
|
-
* ```
|
165
|
+
* @returns Metadata describing the current position of the selection.
|
226
166
|
*/
|
227
|
-
#
|
167
|
+
#lineMeta() {
|
228
168
|
const lines = this.text.split("\n");
|
229
|
-
let
|
230
|
-
for (let
|
231
|
-
const
|
232
|
-
// for
|
233
|
-
|
234
|
-
characterCount += lineLength;
|
169
|
+
let charCount = 0;
|
170
|
+
for (let lineNumber = 0; lineNumber < lines.length; lineNumber++) {
|
171
|
+
const line = lines[lineNumber];
|
172
|
+
const len = line.length + 1; // account for removed "\n" due to .split()
|
173
|
+
charCount += len;
|
235
174
|
// find the line that the cursor is on
|
236
|
-
if (
|
175
|
+
if (charCount > this.#selEnd) {
|
237
176
|
return {
|
177
|
+
line,
|
238
178
|
lines,
|
239
|
-
lineNumber
|
240
|
-
columnNumber: this.#
|
179
|
+
lineNumber,
|
180
|
+
columnNumber: this.#selEnd - (charCount - len),
|
241
181
|
};
|
242
182
|
}
|
243
183
|
}
|
244
|
-
return { lines, lineNumber: 0, columnNumber: 0 };
|
184
|
+
return { line: lines[0], lines, lineNumber: 0, columnNumber: 0 };
|
245
185
|
}
|
246
186
|
/**
|
247
|
-
*
|
187
|
+
* Increments/decrements the start of following lines if they are numbers.
|
248
188
|
*
|
249
|
-
*
|
189
|
+
* @param decrement if following lines should be decremented instead of incremented
|
250
190
|
*
|
251
|
-
*
|
252
|
-
* 1. presses enter here when two items in list
|
253
|
-
* 2.
|
254
|
-
* 2.
|
255
|
-
* ```
|
191
|
+
* @example
|
256
192
|
*
|
257
|
-
*
|
193
|
+
* ```md
|
194
|
+
* Prevents this, instead fixes the following lines.
|
258
195
|
*
|
259
|
-
*
|
260
|
-
* 1.
|
196
|
+
* 1. presses enter here when two items in list
|
261
197
|
* 2.
|
262
|
-
*
|
198
|
+
* 2. (repeat of 2)
|
263
199
|
* ```
|
264
|
-
*
|
265
|
-
* @param currentLineNumber
|
266
|
-
* @param decrement if following lines should be decremented instead of incremented
|
267
200
|
*/
|
268
|
-
#correctFollowing(
|
269
|
-
|
270
|
-
for (
|
271
|
-
|
201
|
+
#correctFollowing(decrement = false) {
|
202
|
+
let { lines, lineNumber } = this.#lineMeta();
|
203
|
+
for (; ++lineNumber < lines.length;) {
|
204
|
+
let line = lines[lineNumber];
|
272
205
|
if (line) {
|
273
|
-
const num = startsWithNumberAndPeriod(line);
|
274
|
-
if (
|
275
|
-
break;
|
276
|
-
}
|
277
|
-
else {
|
206
|
+
const num = this.#startsWithNumberAndPeriod(line);
|
207
|
+
if (num) {
|
278
208
|
let newNum;
|
279
209
|
if (decrement) {
|
280
210
|
if (num > 1) {
|
@@ -287,194 +217,135 @@ export class Editor extends Base {
|
|
287
217
|
else {
|
288
218
|
newNum = num + 1;
|
289
219
|
}
|
290
|
-
lines[
|
291
|
-
|
220
|
+
lines[lineNumber] = String(newNum) + line.slice(String(num).length);
|
221
|
+
}
|
222
|
+
else {
|
223
|
+
break;
|
292
224
|
}
|
293
225
|
}
|
294
226
|
}
|
227
|
+
const start = this.#selStart;
|
295
228
|
this.text = lines.join("\n");
|
229
|
+
this.#setSelection(start);
|
296
230
|
}
|
297
231
|
mount() {
|
298
|
-
this.textArea.addEventListener("keydown",
|
299
|
-
|
300
|
-
const
|
301
|
-
|
302
|
-
if (resetKeys.includes(e.key)) {
|
303
|
-
// reset
|
232
|
+
this.textArea.addEventListener("keydown", (e) => {
|
233
|
+
const nextChar = this.text[this.#selEnd] ?? "";
|
234
|
+
const notHighlighted = this.#selStart === this.#selEnd;
|
235
|
+
if (this.#resetKeys.has(e.key)) {
|
304
236
|
this.#openChars = [];
|
305
237
|
}
|
306
238
|
else if (e.key === "Backspace") {
|
307
|
-
const prevChar = this.text[this.#
|
239
|
+
const prevChar = this.text[this.#selStart - 1];
|
308
240
|
if (prevChar &&
|
309
241
|
prevChar in this.keyPairs &&
|
310
242
|
nextChar === this.keyPairs[prevChar]) {
|
311
243
|
// remove both characters if the next one is the match of the prev
|
312
244
|
e.preventDefault();
|
313
|
-
const start = this.#
|
314
|
-
const end = this.#
|
315
|
-
this
|
316
|
-
this
|
317
|
-
|
318
|
-
this.#setSelectionRange(start, end);
|
319
|
-
}, 0);
|
245
|
+
const start = this.#selStart - 1;
|
246
|
+
const end = this.#selEnd - 1;
|
247
|
+
this.#removeStr(start);
|
248
|
+
this.#removeStr(end);
|
249
|
+
this.#setSelection(start, end);
|
320
250
|
this.#openChars.pop();
|
321
251
|
}
|
322
|
-
if (prevChar === "\n" && this.#
|
323
|
-
// see `correctFollowing`
|
252
|
+
else if (prevChar === "\n" && this.#selStart === this.#selEnd) {
|
324
253
|
e.preventDefault();
|
325
|
-
const newPos = this.#
|
326
|
-
|
327
|
-
this.#
|
328
|
-
this
|
329
|
-
setTimeout(async () => {
|
330
|
-
this.#setSelectionRange(newPos, newPos);
|
331
|
-
}, 0);
|
254
|
+
const newPos = this.#selStart - 1;
|
255
|
+
this.#correctFollowing(true);
|
256
|
+
this.#removeStr(newPos);
|
257
|
+
this.#setSelection(newPos, newPos);
|
332
258
|
}
|
333
259
|
}
|
334
260
|
else if (e.key === "Tab") {
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
261
|
+
const blocks = this.text.split("```");
|
262
|
+
let totalChars = 0;
|
263
|
+
for (const [i, block] of blocks.entries()) {
|
264
|
+
totalChars += block.length + 3;
|
265
|
+
if (totalChars > this.#selStart) {
|
266
|
+
// found
|
267
|
+
if (i % 2) {
|
268
|
+
// if caret is inside of a codeblock, indent
|
269
|
+
e.preventDefault();
|
270
|
+
this.#addContent({ type: "inline", value: "\t" });
|
271
|
+
}
|
272
|
+
break;
|
273
|
+
}
|
342
274
|
}
|
275
|
+
// TODO add shift tab backwards
|
343
276
|
}
|
344
|
-
else if (e.key === "Enter") {
|
277
|
+
else if (e.key === "Enter" && notHighlighted) {
|
345
278
|
// autocomplete start of next line if block or number
|
346
|
-
const {
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
const num = startsWithNumberAndPeriod(repeat);
|
351
|
-
// line starts with number and period? - increment
|
352
|
-
if (num)
|
353
|
-
repeat = `${num + 1}. `;
|
354
|
-
if (repeat && original.length < columnNumber) {
|
355
|
-
e.preventDefault();
|
279
|
+
const { line, columnNumber } = this.#lineMeta();
|
280
|
+
let repeat = this.#startsWithBlock(line);
|
281
|
+
if (!repeat) {
|
282
|
+
const num = this.#startsWithNumberAndPeriod(line);
|
356
283
|
if (num)
|
357
|
-
|
358
|
-
await this.#addContent({
|
359
|
-
type: "inline",
|
360
|
-
value: `\n${repeat}`,
|
361
|
-
});
|
284
|
+
repeat = `${num + 1}. `;
|
362
285
|
}
|
363
|
-
|
364
|
-
// remove if the repeat and caret at the end of the original
|
286
|
+
if (repeat) {
|
365
287
|
e.preventDefault();
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
const newPos = originalSelectionEnd - original.length;
|
371
|
-
// for each character in the original
|
372
|
-
for (let i = 0; i < original.length; i++) {
|
373
|
-
this.text = removeChar(this.text, originalSelectionEnd - (i + 1));
|
288
|
+
if (repeat.length < columnNumber) {
|
289
|
+
// repeat same on next line
|
290
|
+
this.#addContent({ type: "inline", value: "\n" + repeat });
|
291
|
+
this.#correctFollowing();
|
374
292
|
}
|
375
|
-
|
376
|
-
|
377
|
-
this
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
});
|
382
|
-
}, 0);
|
383
|
-
}
|
384
|
-
}
|
385
|
-
else {
|
386
|
-
const nextCharIsClosing = Object.values(this.keyPairs).includes(nextChar);
|
387
|
-
const highlighted = this.#selectionStart !== this.#selectionEnd;
|
388
|
-
if (e.ctrlKey || e.metaKey) {
|
389
|
-
if (this.#selectionStart === this.#selectionEnd) {
|
390
|
-
// no selection
|
391
|
-
if (e.key === "c" || e.key === "x") {
|
392
|
-
// copy or cut entire line
|
393
|
-
e.preventDefault();
|
394
|
-
const { lines, lineNumber, columnNumber } = this.#getLineInfo();
|
395
|
-
await navigator.clipboard.writeText(`${lineNumber === 0 && e.key === "x" ? "" : "\n"}${lines[lineNumber]}`);
|
396
|
-
if (e.key === "x") {
|
397
|
-
const newPos = this.#selectionStart - columnNumber;
|
398
|
-
lines.splice(lineNumber, 1);
|
399
|
-
this.text = lines.join("\n");
|
400
|
-
setTimeout(() => {
|
401
|
-
this.#setSelectionRange(newPos, newPos);
|
402
|
-
}, 0);
|
403
|
-
}
|
404
|
-
}
|
293
|
+
else {
|
294
|
+
// remove repeat from current line
|
295
|
+
const end = this.#selEnd;
|
296
|
+
const newPos = end - repeat.length;
|
297
|
+
this.#removeStr(newPos, end);
|
298
|
+
this.#setSelection(newPos);
|
405
299
|
}
|
406
300
|
}
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
this.#addContent(matchedEl);
|
412
|
-
}
|
413
|
-
else if (nextCharIsClosing &&
|
414
|
-
(nextChar === e.key || e.key === "ArrowRight") &&
|
415
|
-
this.#openChars.length &&
|
416
|
-
!highlighted) {
|
417
|
-
// type over the next character instead of inserting
|
418
|
-
e.preventDefault();
|
419
|
-
this.#setSelectionRange(this.#selectionStart + 1, this.#selectionEnd + 1);
|
420
|
-
this.#openChars.pop();
|
421
|
-
}
|
422
|
-
else if (e.key in this.keyPairs) {
|
301
|
+
}
|
302
|
+
else if ((e.ctrlKey || e.metaKey) && e.key) {
|
303
|
+
if (notHighlighted && (e.key === "c" || e.key === "x")) {
|
304
|
+
// copy or cut entire line
|
423
305
|
e.preventDefault();
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
306
|
+
const { line, lines, lineNumber, columnNumber } = this.#lineMeta();
|
307
|
+
navigator.clipboard.writeText(line);
|
308
|
+
if (e.key === "x") {
|
309
|
+
const newPos = this.#selStart - columnNumber;
|
310
|
+
lines.splice(lineNumber, 1);
|
311
|
+
this.text = lines.join("\n");
|
312
|
+
this.#setSelection(newPos, newPos);
|
313
|
+
}
|
429
314
|
}
|
315
|
+
const shortcut = this.#contentElements.find((el) => el.key === e.key);
|
316
|
+
if (shortcut)
|
317
|
+
this.#addContent(shortcut);
|
318
|
+
}
|
319
|
+
else if (this.#openChars.length &&
|
320
|
+
notHighlighted &&
|
321
|
+
(nextChar === e.key || e.key === "ArrowRight") &&
|
322
|
+
Object.values(this.keyPairs).includes(nextChar)) {
|
323
|
+
// type over the next character instead of inserting
|
324
|
+
e.preventDefault();
|
325
|
+
this.#setSelection(this.#selStart + 1, this.#selEnd + 1);
|
326
|
+
this.#openChars.pop();
|
327
|
+
}
|
328
|
+
else if (e.key in this.keyPairs) {
|
329
|
+
e.preventDefault();
|
330
|
+
this.#addContent({ type: "wrap", value: e.key });
|
331
|
+
this.#openChars.push(e.key);
|
430
332
|
}
|
431
333
|
});
|
432
334
|
// trims the selection if there is an extra space around it
|
433
335
|
this.textArea.addEventListener("dblclick", () => {
|
434
|
-
if (this.#
|
435
|
-
if (this.text[this.#
|
436
|
-
this.#
|
336
|
+
if (this.#selStart !== this.#selEnd) {
|
337
|
+
if (this.text[this.#selStart] === " ") {
|
338
|
+
this.#setSelection(this.#selStart + 1, this.#selEnd);
|
437
339
|
}
|
438
|
-
if (this.text[this.#
|
439
|
-
this.#
|
340
|
+
if (this.text[this.#selEnd - 1] === " ") {
|
341
|
+
this.#setSelection(this.#selStart, this.#selEnd - 1);
|
440
342
|
}
|
441
343
|
}
|
442
344
|
});
|
443
345
|
// reset #openChars on click since the cursor has changed position
|
444
346
|
this.textArea.addEventListener("click", () => (this.#openChars = []));
|
445
347
|
for (const trigger of this.getTrigger()) {
|
446
|
-
trigger.addEventListener(this.event, () =>
|
447
|
-
this.#addContent(this.#getContentElement(trigger));
|
448
|
-
});
|
348
|
+
trigger.addEventListener(this.event, () => this.#addContent(trigger.dataset));
|
449
349
|
}
|
450
350
|
}
|
451
351
|
}
|
452
|
-
/**
|
453
|
-
* @param str
|
454
|
-
* @returns the number, if the string starts with a number and a period
|
455
|
-
*/
|
456
|
-
const startsWithNumberAndPeriod = (str) => {
|
457
|
-
const result = str.match(/^(\d+)\./);
|
458
|
-
return result ? Number(result[1]) : null;
|
459
|
-
};
|
460
|
-
/**
|
461
|
-
* - insert character into string at index
|
462
|
-
*
|
463
|
-
* @param str string to insert into
|
464
|
-
* @param char characters to insert into `str`
|
465
|
-
* @param index where to insert the characters
|
466
|
-
* @returns the new string
|
467
|
-
*/
|
468
|
-
const insertChar = (str, char, index) => {
|
469
|
-
return str.slice(0, index) + char + str.slice(index);
|
470
|
-
};
|
471
|
-
/**
|
472
|
-
* - remove char from string at index
|
473
|
-
*
|
474
|
-
* @param str string to remove the character from
|
475
|
-
* @param index index of character to remove
|
476
|
-
* @returns the new string
|
477
|
-
*/
|
478
|
-
const removeChar = (str, index) => {
|
479
|
-
return str.slice(0, index) + str.slice(index + 1);
|
480
|
-
};
|
package/dist/index.d.ts
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
export
|
2
|
-
export
|
3
|
-
export
|
4
|
-
export
|
5
|
-
export
|
6
|
-
export
|
7
|
-
export
|
8
|
-
export
|
9
|
-
export
|
10
|
-
export
|
11
|
-
export
|
12
|
-
export
|
1
|
+
export * from "./announcer/index.js";
|
2
|
+
export * from "./base/index.js";
|
3
|
+
export * from "./contextmenu/index.js";
|
4
|
+
export * from "./copy/index.js";
|
5
|
+
export * from "./dialog/index.js";
|
6
|
+
export * from "./editor/index.js";
|
7
|
+
export * from "./fullscreen/index.js";
|
8
|
+
export * from "./intersect/index.js";
|
9
|
+
export * from "./prefetch/index.js";
|
10
|
+
export * from "./share/index.js";
|
11
|
+
export * from "./tablesort/index.js";
|
12
|
+
export * from "./wakelock/index.js";
|
13
|
+
export * from "./youtube/index.js";
|
package/dist/index.js
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
export
|
2
|
-
export
|
3
|
-
export
|
4
|
-
export
|
5
|
-
export
|
6
|
-
export
|
7
|
-
export
|
8
|
-
export
|
9
|
-
export
|
10
|
-
export
|
11
|
-
export
|
12
|
-
export
|
1
|
+
export * from "./announcer/index.js";
|
2
|
+
export * from "./base/index.js";
|
3
|
+
export * from "./contextmenu/index.js";
|
4
|
+
export * from "./copy/index.js";
|
5
|
+
export * from "./dialog/index.js";
|
6
|
+
export * from "./editor/index.js";
|
7
|
+
export * from "./fullscreen/index.js";
|
8
|
+
export * from "./intersect/index.js";
|
9
|
+
export * from "./prefetch/index.js";
|
10
|
+
export * from "./share/index.js";
|
11
|
+
export * from "./tablesort/index.js";
|
12
|
+
export * from "./wakelock/index.js";
|
13
|
+
export * from "./youtube/index.js";
|
package/dist/intersect/define.js
CHANGED
package/dist/intersect/index.js
CHANGED
package/dist/prefetch/define.js
CHANGED
package/dist/prefetch/index.js
CHANGED
@@ -61,12 +61,7 @@ export class Prefetch extends Base {
|
|
61
61
|
// Currently, adding `prefetch` is required to fallback if `prerender` fails.
|
62
62
|
// Possibly will be automatic in the future, in which case it can be removed.
|
63
63
|
// https://github.com/WICG/nav-speculation/issues/162#issuecomment-1977818473
|
64
|
-
prefetch: [
|
65
|
-
{
|
66
|
-
source: "list",
|
67
|
-
urls: [url],
|
68
|
-
},
|
69
|
-
],
|
64
|
+
prefetch: [{ source: "list", urls: [url] }],
|
70
65
|
};
|
71
66
|
if (prerender) {
|
72
67
|
rules.prerender = rules.prefetch;
|
package/dist/share/define.js
CHANGED
package/dist/tablesort/define.js
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
import { Base, type BaseAttributes } from "../base/index.js";
|
2
2
|
export type TableSortAttributes = BaseAttributes;
|
3
|
+
export type TableSortTriggerAttributes = {
|
4
|
+
"data-type": "string" | "boolean" | "number";
|
5
|
+
"data-value": string;
|
6
|
+
};
|
3
7
|
/**
|
4
8
|
* Wrap a `HTMLTableElement` in the `TableSort` element to have sortable column
|
5
9
|
* headers. Set each `th` that you want to sort to the `trigger`. Set the `tbody`
|
package/dist/tablesort/index.js
CHANGED
@@ -20,7 +20,7 @@ export class TableSort extends Base {
|
|
20
20
|
* Removes `data-asc` or `data-desc` from other triggers then sets the correct attribute on the selected trigger.
|
21
21
|
*
|
22
22
|
* @param trigger
|
23
|
-
* @returns true if ascending, false if descending
|
23
|
+
* @returns `true` if ascending, `false` if descending
|
24
24
|
*/
|
25
25
|
#setAttributes(trigger) {
|
26
26
|
const asc = "data-asc";
|
@@ -43,11 +43,24 @@ export class TableSort extends Base {
|
|
43
43
|
mount() {
|
44
44
|
const tbody = this.getContent(HTMLTableSectionElement);
|
45
45
|
for (const trigger of this.getTrigger()) {
|
46
|
-
trigger.
|
46
|
+
trigger.tabIndex = 0;
|
47
|
+
trigger.role = "button";
|
48
|
+
const listener = () => {
|
49
|
+
const asc = this.#setAttributes(trigger);
|
47
50
|
Array.from(tbody.querySelectorAll("tr"))
|
48
|
-
.sort(comparer(trigger,
|
51
|
+
.sort(comparer(trigger, asc))
|
49
52
|
.forEach((tr) => tbody.appendChild(tr));
|
50
|
-
|
53
|
+
this.announce(`sorted table by ${trigger.textContent} in ${asc ? "ascending" : "descending"} order`);
|
54
|
+
};
|
55
|
+
trigger.addEventListener(this.event, listener);
|
56
|
+
if (this.event === "click") {
|
57
|
+
trigger.addEventListener("keydown", (e) => {
|
58
|
+
if (e.key === "Enter" || e.key === " ") {
|
59
|
+
e.preventDefault();
|
60
|
+
listener();
|
61
|
+
}
|
62
|
+
});
|
63
|
+
}
|
51
64
|
}
|
52
65
|
}
|
53
66
|
}
|
@@ -65,23 +78,9 @@ const comparer = (th, ascending) => {
|
|
65
78
|
return collator.compare(aVal, bVal);
|
66
79
|
}
|
67
80
|
else if (dataType === "boolean") {
|
68
|
-
|
69
|
-
* if value is one of these and type is boolean
|
70
|
-
* it should be considered falsy
|
71
|
-
* since actually `Boolean("false") === true`
|
72
|
-
* @param val string pulled from the textContent or attr
|
73
|
-
* @returns a boolean of the provided string
|
74
|
-
*/
|
75
|
-
const convertToBoolean = (val) => {
|
76
|
-
const falsy = ["0", "false", "null", "undefined"];
|
77
|
-
if (falsy.includes(val)) {
|
78
|
-
return false;
|
79
|
-
}
|
80
|
-
return Boolean(val);
|
81
|
-
};
|
82
|
-
return convertToBoolean(aVal) === convertToBoolean(bVal)
|
81
|
+
return falsyBoolean(aVal) === falsyBoolean(bVal)
|
83
82
|
? 0
|
84
|
-
:
|
83
|
+
: falsyBoolean(aVal)
|
85
84
|
? -1
|
86
85
|
: 1;
|
87
86
|
}
|
@@ -107,3 +106,16 @@ const getValue = (tr, i) => {
|
|
107
106
|
}
|
108
107
|
return "";
|
109
108
|
};
|
109
|
+
/**
|
110
|
+
* if value is one of these and type is boolean
|
111
|
+
* it should be considered falsy
|
112
|
+
* since actually `Boolean("false") === true`
|
113
|
+
* @param val string pulled from the textContent or attr
|
114
|
+
* @returns a boolean of the provided string
|
115
|
+
*/
|
116
|
+
const falsyBoolean = (val) => {
|
117
|
+
if (["0", "false", "null", "undefined"].includes(val)) {
|
118
|
+
return false;
|
119
|
+
}
|
120
|
+
return Boolean(val);
|
121
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* Define a custom element to the registry. Checks if the element is
|
3
|
+
* defined and then names the element.
|
4
|
+
*
|
5
|
+
* @param name name of the custom element
|
6
|
+
* @param Constructor custom element constructor
|
7
|
+
*/
|
8
|
+
export declare const define: (name: string, Constructor: CustomElementConstructor) => void;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* Define a custom element to the registry. Checks if the element is
|
3
|
+
* defined and then names the element.
|
4
|
+
*
|
5
|
+
* @param name name of the custom element
|
6
|
+
* @param Constructor custom element constructor
|
7
|
+
*/
|
8
|
+
export const define = (name, Constructor) => {
|
9
|
+
if (!customElements.get(name))
|
10
|
+
customElements.define(name, Constructor);
|
11
|
+
};
|
package/dist/wakelock/define.js
CHANGED
package/dist/wakelock/index.js
CHANGED
@@ -34,9 +34,11 @@ export class WakeLock extends Base {
|
|
34
34
|
if (this.#wakeLockSupported() && document.visibilityState === "visible") {
|
35
35
|
this.wakeLock = await navigator.wakeLock.request("screen");
|
36
36
|
this.setAttribute("locked", "");
|
37
|
+
this.announce("screen wake lock activated");
|
37
38
|
this.swapContent(false);
|
38
39
|
this.wakeLock.addEventListener("release", () => {
|
39
40
|
this.removeAttribute("locked");
|
41
|
+
this.announce("screen wake lock deactivated");
|
40
42
|
this.swapContent(false);
|
41
43
|
if (!this.#autoLock) {
|
42
44
|
// set to null is required, used to determine if screen should be
|
package/dist/youtube/define.js
CHANGED
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "drab",
|
3
3
|
"description": "Interactivity for You",
|
4
|
-
"version": "6.
|
4
|
+
"version": "6.1.1",
|
5
5
|
"homepage": "https://drab.robino.dev",
|
6
6
|
"license": "MIT",
|
7
7
|
"author": {
|
@@ -42,6 +42,14 @@
|
|
42
42
|
"types": "./dist/define.d.ts",
|
43
43
|
"default": "./dist/define.js"
|
44
44
|
},
|
45
|
+
"./announcer": {
|
46
|
+
"types": "./dist/announcer/index.d.ts",
|
47
|
+
"default": "./dist/announcer/index.js"
|
48
|
+
},
|
49
|
+
"./announcer/define": {
|
50
|
+
"types": "./dist/announcer/define.d.ts",
|
51
|
+
"default": "./dist/announcer/define.js"
|
52
|
+
},
|
45
53
|
"./base": {
|
46
54
|
"types": "./dist/base/index.d.ts",
|
47
55
|
"default": "./dist/base/index.js"
|