drab 7.0.2 → 8.0.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.
Files changed (59) hide show
  1. package/dist/base/index.d.ts +122 -48
  2. package/dist/base/index.d.ts.map +1 -1
  3. package/dist/base/index.js +10 -7
  4. package/dist/contextmenu/index.d.ts +90 -35
  5. package/dist/contextmenu/index.d.ts.map +1 -1
  6. package/dist/define.d.ts +0 -1
  7. package/dist/define.d.ts.map +1 -1
  8. package/dist/define.js +0 -1
  9. package/dist/editor/index.d.ts +90 -35
  10. package/dist/editor/index.d.ts.map +1 -1
  11. package/dist/fullscreen/index.d.ts +90 -36
  12. package/dist/fullscreen/index.d.ts.map +1 -1
  13. package/dist/fullscreen/index.js +3 -14
  14. package/dist/index.d.ts +0 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +0 -1
  17. package/dist/intersect/index.d.ts +90 -36
  18. package/dist/intersect/index.d.ts.map +1 -1
  19. package/dist/intersect/index.js +1 -11
  20. package/dist/prefetch/index.d.ts +62 -25
  21. package/dist/prefetch/index.d.ts.map +1 -1
  22. package/dist/prefetch/index.js +17 -30
  23. package/dist/share/index.d.ts +120 -47
  24. package/dist/share/index.d.ts.map +1 -1
  25. package/dist/tablesort/index.d.ts +120 -47
  26. package/dist/tablesort/index.d.ts.map +1 -1
  27. package/dist/tablesort/index.js +54 -54
  28. package/dist/tabs/index.d.ts +61 -24
  29. package/dist/tabs/index.d.ts.map +1 -1
  30. package/dist/tabs/index.js +10 -2
  31. package/dist/types/index.d.ts +0 -2
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/util/validate.d.ts.map +1 -1
  34. package/dist/util/validate.js +2 -1
  35. package/dist/wakelock/index.d.ts +120 -47
  36. package/dist/wakelock/index.d.ts.map +1 -1
  37. package/dist/wakelock/index.js +1 -2
  38. package/package.json +4 -4
  39. package/src/base/index.ts +10 -7
  40. package/src/contextmenu/index.ts +2 -3
  41. package/src/define.ts +0 -1
  42. package/src/editor/index.ts +1 -2
  43. package/src/fullscreen/index.ts +6 -18
  44. package/src/index.ts +0 -1
  45. package/src/intersect/index.ts +2 -14
  46. package/src/prefetch/index.ts +21 -36
  47. package/src/tablesort/index.ts +64 -63
  48. package/src/tabs/index.ts +16 -2
  49. package/src/types/index.ts +0 -2
  50. package/src/util/validate.ts +2 -1
  51. package/src/wakelock/index.ts +2 -5
  52. package/dist/dialog/define.d.ts +0 -2
  53. package/dist/dialog/define.d.ts.map +0 -1
  54. package/dist/dialog/define.js +0 -3
  55. package/dist/dialog/index.d.ts +0 -1079
  56. package/dist/dialog/index.d.ts.map +0 -1
  57. package/dist/dialog/index.js +0 -90
  58. package/src/dialog/define.ts +0 -4
  59. package/src/dialog/index.ts +0 -120
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wakelock/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,iBAAiB,EAGtB,KAAK,iBAAiB,EACtB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,kBAChB,SAAQ,iBAAiB,EACxB,iBAAiB;IAClB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,QAAS,SAAQ,aAAuC;;;IAoBpE,6CAA6C;IACvC,OAAO;IAqBb,2DAA2D;IACrD,OAAO;IAKJ,KAAK;IAsCL,OAAO;CAGhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wakelock/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,iBAAiB,EAGtB,KAAK,iBAAiB,EACtB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,kBAChB,SAAQ,iBAAiB,EAAE,iBAAiB;IAC5C,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,QAAS,SAAQ,aAAuC;;;IAoBpE,6CAA6C;IACvC,OAAO;IAqBb,2DAA2D;IACrD,OAAO;IAKJ,KAAK;IAoCL,OAAO;CAGhB"}
@@ -88,9 +88,8 @@ export class WakeLock extends Lifecycle(Trigger(Content(Announce()))) {
88
88
  // When the tab is not visible, the wakeLock is automatically released.
89
89
  // This requests it back if it exists, if it is `null`, that
90
90
  // means it was removed. In which case, it shouldn't be requested again.
91
- if (this.#wakeLock) {
91
+ if (this.#wakeLock)
92
92
  this.request();
93
- }
94
93
  }, document);
95
94
  }
96
95
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "drab",
3
3
  "description": "Interactivity for You",
4
- "version": "7.0.2",
4
+ "version": "8.0.0",
5
5
  "homepage": "https://drab.robino.dev",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -151,8 +151,8 @@
151
151
  "!src/**/*.test.ts"
152
152
  ],
153
153
  "scripts": {
154
- "check": "tsc --noEmit",
155
- "dev": "tsc --watch",
156
- "build": "tsc"
154
+ "check": "tsc",
155
+ "dev": "tsc --watch -p tsconfig.build.json",
156
+ "build": "tsc -p tsconfig.build.json"
157
157
  }
158
158
  }
package/src/base/index.ts CHANGED
@@ -17,7 +17,7 @@ export const Lifecycle = <T extends Constructor<HTMLElement>>(
17
17
  ) =>
18
18
  class Lifecycle extends Super {
19
19
  /** To clean up event listeners added to `document` when the element is removed. */
20
- #listenerController = new AbortController();
20
+ controller = new AbortController();
21
21
 
22
22
  constructor(...args: any[]) {
23
23
  super(...args);
@@ -56,8 +56,10 @@ export const Lifecycle = <T extends Constructor<HTMLElement>>(
56
56
  target: EventTarget = document.body,
57
57
  options: AddEventListenerOptions = {},
58
58
  ) {
59
- options.signal = this.#listenerController.signal;
60
- target.addEventListener(type, listener, options);
59
+ target.addEventListener(type, listener, {
60
+ ...options,
61
+ signal: this.controller.signal,
62
+ });
61
63
  }
62
64
 
63
65
  /**
@@ -85,7 +87,7 @@ export const Lifecycle = <T extends Constructor<HTMLElement>>(
85
87
  /** Called when custom element is removed from the page. */
86
88
  disconnectedCallback() {
87
89
  this.destroy();
88
- this.#listenerController.abort();
90
+ this.controller.abort();
89
91
  }
90
92
  };
91
93
 
@@ -113,7 +115,8 @@ export const Trigger = <T extends Constructor<HTMLElement>>(
113
115
  /**
114
116
  * Event for the `trigger` to execute.
115
117
  *
116
- * For example, set to `"mouseover"` to execute the event when the user hovers the mouse over the `trigger`, instead of when they click it.
118
+ * For example, set to `"mouseover"` to execute the event when the user
119
+ * hovers the mouse over the `trigger`, instead of when they click it.
117
120
  *
118
121
  * @default "click"
119
122
  */
@@ -275,7 +278,7 @@ export const Announce = <T extends Constructor<HTMLElement>>(
275
278
  * A single `Announcer` element to share between all drab elements to announce
276
279
  * interactive changes.
277
280
  */
278
- static #announcer = Announcer.init();
281
+ static announcer = Announcer.init();
279
282
 
280
283
  constructor(...args: any[]) {
281
284
  super(...args);
@@ -285,6 +288,6 @@ export const Announce = <T extends Constructor<HTMLElement>>(
285
288
  * @param message message to announce to screen readers
286
289
  */
287
290
  announce(message: string) {
288
- Announce.#announcer.announce(message);
291
+ Announce.announcer.announce(message);
289
292
  }
290
293
  };
@@ -7,15 +7,14 @@ import {
7
7
  } from "../base/index.js";
8
8
 
9
9
  export interface ContextMenuAttributes
10
- extends TriggerAttributes,
11
- ContentAttributes {}
10
+ extends TriggerAttributes, ContentAttributes {}
12
11
 
13
12
  /**
14
13
  * Displays content when the `trigger` element is right clicked, or long pressed on mobile.
15
14
  */
16
15
  export class ContextMenu extends Lifecycle(Trigger(Content())) {
17
16
  /** Tracks the long press duration on mobile. */
18
- #touchTimer: NodeJS.Timeout | undefined;
17
+ #touchTimer: number | undefined;
19
18
 
20
19
  constructor() {
21
20
  super();
package/src/define.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import "./announcer/define.js";
2
2
  import "./contextmenu/define.js";
3
- import "./dialog/define.js";
4
3
  import "./editor/define.js";
5
4
  import "./fullscreen/define.js";
6
5
  import "./intersect/define.js";
@@ -7,8 +7,7 @@ import {
7
7
  } from "../base/index.js";
8
8
 
9
9
  export interface EditorAttributes
10
- extends TriggerAttributes,
11
- ContentAttributes {}
10
+ extends TriggerAttributes, ContentAttributes {}
12
11
 
13
12
  export interface EditorTriggerAttributes {
14
13
  "data-value": string;
@@ -7,8 +7,7 @@ import {
7
7
  } from "../base/index.js";
8
8
 
9
9
  export interface FullscreenAttributes
10
- extends TriggerAttributes,
11
- ContentAttributes {}
10
+ extends TriggerAttributes, ContentAttributes {}
12
11
 
13
12
  /**
14
13
  * Toggles the `documentElement` or `content` element to fullscreen mode.
@@ -20,23 +19,9 @@ export class Fullscreen extends Lifecycle(Trigger(Content())) {
20
19
  super();
21
20
  }
22
21
 
23
- /**
24
- * @returns `true` if fullscreen is currently enabled.
25
- */
26
- #isFullscreen() {
27
- return document.fullscreenElement !== null;
28
- }
29
-
30
- /**
31
- * @returns `true` if fullscreen is supported.
32
- */
33
- #fullscreenSupported() {
34
- return "requestFullscreen" in document.documentElement;
35
- }
36
-
37
22
  /** Enables or disables fullscreen mode based on the current state. */
38
23
  toggle() {
39
- if (this.#isFullscreen()) {
24
+ if (document.fullscreenElement !== null) {
40
25
  document.exitFullscreen();
41
26
  } else {
42
27
  try {
@@ -51,7 +36,10 @@ export class Fullscreen extends Lifecycle(Trigger(Content())) {
51
36
  this.listener(() => this.toggle());
52
37
 
53
38
  for (const trigger of this.triggers()) {
54
- if (!this.#fullscreenSupported() && "disabled" in trigger) {
39
+ if (
40
+ !("requestFullscreen" in document.documentElement) &&
41
+ "disabled" in trigger
42
+ ) {
55
43
  trigger.disabled = true;
56
44
  }
57
45
  }
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./announcer/index.js";
2
2
  export * from "./contextmenu/index.js";
3
- export * from "./dialog/index.js";
4
3
  export * from "./editor/index.js";
5
4
  export * from "./fullscreen/index.js";
6
5
  export * from "./intersect/index.js";
@@ -7,8 +7,7 @@ import {
7
7
  } from "../base/index.js";
8
8
 
9
9
  export interface IntersectAttributes
10
- extends TriggerAttributes,
11
- ContentAttributes {
10
+ extends TriggerAttributes, ContentAttributes {
12
11
  /** Number between 0 and 1 representing the visible portion of the `trigger`. */
13
12
  threshold?: number;
14
13
  }
@@ -40,17 +39,6 @@ export class Intersect extends Lifecycle(Trigger(Content())) {
40
39
  super();
41
40
  }
42
41
 
43
- /**
44
- * How much of the `trigger` should be visible for the intersection to occur.
45
- * For example, given a threshold of `.5`, the intersection would occur when
46
- * the `trigger` is 50% visible.
47
- *
48
- * @default 0
49
- */
50
- get #threshold() {
51
- return Number(this.getAttribute("threshold") ?? 0);
52
- }
53
-
54
42
  override mount() {
55
43
  const observer = new IntersectionObserver(
56
44
  (entries) => {
@@ -71,7 +59,7 @@ export class Intersect extends Lifecycle(Trigger(Content())) {
71
59
  );
72
60
  }
73
61
  },
74
- { threshold: this.#threshold },
62
+ { threshold: Number(this.getAttribute("threshold") ?? 0) },
75
63
  );
76
64
 
77
65
  for (const trigger of this.triggers()) observer.observe(trigger);
@@ -77,28 +77,16 @@ export class Prefetch extends Lifecycle(Trigger()) {
77
77
  super();
78
78
  }
79
79
 
80
- /** When to prefetch the url. */
81
- get #strategy() {
82
- return this.getAttribute("strategy");
83
- }
84
-
85
- /** Prerender with the Speculation Rules API. */
86
- get #prerender() {
87
- return this.hasAttribute("prerender");
88
- }
89
-
90
- /** `url` to prefetch on `mount`. */
91
- get #url() {
92
- return this.getAttribute("url");
93
- }
94
-
95
80
  /**
96
81
  * Appends `<link rel="prefetch">` or `<script type="speculationrules">`
97
82
  * to the head of the document.
98
83
  *
99
84
  * @param options Configuration options.
100
85
  */
101
- prefetch(options: {
86
+ prefetch({
87
+ url,
88
+ prerender,
89
+ }: {
102
90
  /** `url` to prefetch. */
103
91
  url: string;
104
92
 
@@ -107,8 +95,6 @@ export class Prefetch extends Lifecycle(Trigger()) {
107
95
  */
108
96
  prerender?: boolean;
109
97
  }) {
110
- const { url } = options;
111
-
112
98
  // if not the current page and not already prefetched
113
99
  if (!(url === window.location.href) && !this.#prefetchedUrls.has(url)) {
114
100
  this.#prefetchedUrls.add(url);
@@ -124,7 +110,7 @@ export class Prefetch extends Lifecycle(Trigger()) {
124
110
  prefetch: [{ source: "list", urls: [url] }],
125
111
  };
126
112
 
127
- if (options.prerender) rules.prerender = rules.prefetch;
113
+ if (prerender) rules.prerender = rules.prefetch;
128
114
 
129
115
  const script = document.createElement("script");
130
116
  script.type = "speculationrules";
@@ -141,16 +127,17 @@ export class Prefetch extends Lifecycle(Trigger()) {
141
127
  }
142
128
 
143
129
  override mount() {
130
+ const prerender = this.hasAttribute("prerender");
131
+ const url = this.getAttribute("url");
132
+
144
133
  // immediately prefetch the `url` attribute if it exists
145
- if (this.#url)
146
- this.prefetch({ url: this.#url, prerender: this.#prerender });
134
+ if (url) this.prefetch({ url, prerender });
147
135
 
148
136
  // prefetch the `trigger` elements
149
137
  const anchors = this.triggers(HTMLAnchorElement);
150
- const prerender = this.#prerender;
151
- const strategy = this.#strategy;
138
+ const strategy = this.getAttribute("strategy");
152
139
 
153
- let prefetchTimer: NodeJS.Timeout;
140
+ let prefetchTimer: number;
154
141
 
155
142
  const listener =
156
143
  (delay = 200) =>
@@ -164,22 +151,20 @@ export class Prefetch extends Lifecycle(Trigger()) {
164
151
 
165
152
  const reset = () => clearTimeout(prefetchTimer);
166
153
 
167
- const observer = new IntersectionObserver((entries) => {
168
- for (const entry of entries) {
169
- if (entry.isIntersecting) {
170
- this.prefetch({
171
- url: (entry.target as HTMLAnchorElement).href,
172
- prerender,
173
- });
174
- }
175
- }
176
- });
177
-
178
154
  for (const anchor of anchors) {
179
155
  if (strategy === "load") {
180
156
  this.prefetch({ url: anchor.href, prerender });
181
157
  } else if (strategy === "visible") {
182
- observer.observe(anchor);
158
+ new IntersectionObserver((entries) => {
159
+ for (const entry of entries) {
160
+ if (entry.isIntersecting) {
161
+ this.prefetch({
162
+ url: (entry.target as HTMLAnchorElement).href,
163
+ prerender,
164
+ });
165
+ }
166
+ }
167
+ }).observe(anchor);
183
168
  } else {
184
169
  // "hover" - default
185
170
  anchor.addEventListener("mouseover", listener());
@@ -8,8 +8,7 @@ import {
8
8
  } from "../base/index.js";
9
9
 
10
10
  export interface TableSortAttributes
11
- extends TriggerAttributes,
12
- ContentAttributes {}
11
+ extends TriggerAttributes, ContentAttributes {}
13
12
 
14
13
  export interface TableSortTriggerAttributes {
15
14
  "data-type": "string" | "boolean" | "number";
@@ -78,7 +77,7 @@ export class TableSort extends Lifecycle(Trigger(Content(Announce()))) {
78
77
  const asc = this.#setAttributes(trigger);
79
78
 
80
79
  Array.from(tbody.querySelectorAll("tr"))
81
- .sort(comparer(trigger, asc))
80
+ .sort(TableSort.#comparer(trigger, asc))
82
81
  .forEach((tr) => tbody.appendChild(tr));
83
82
 
84
83
  this.announce(
@@ -98,71 +97,73 @@ export class TableSort extends Lifecycle(Trigger(Content(Announce()))) {
98
97
  }
99
98
  }
100
99
  }
101
- }
102
100
 
103
- // adapted from: https://stackoverflow.com/questions/14267781/sorting-html-table-with-javascript/49041392#49041392
104
- const comparer = (th: HTMLElement, ascending: boolean) => {
105
- // this function is returned and used by `sort`
106
- const sorter = (a: HTMLTableRowElement, b: HTMLTableRowElement) => {
107
- // find the column to sort by using the index of the `th`
108
- const columnIndex = Array.from(th.parentNode?.children ?? []).indexOf(th);
109
-
110
- const compare = (aVal: string, bVal: string) => {
111
- // default to `string` sorting
112
- const dataType = (th.dataset.type ?? "string") as
113
- | "string"
114
- | "boolean"
115
- | "number";
116
-
117
- if (dataType === "string") {
118
- const collator = new Intl.Collator();
119
- return collator.compare(aVal, bVal);
120
- } else if (dataType === "boolean") {
121
- return falsyBoolean(aVal) === falsyBoolean(bVal)
122
- ? 0
123
- : falsyBoolean(aVal)
124
- ? -1
125
- : 1;
126
- } else {
127
- // "number"
128
- return Number(aVal) - Number(bVal);
129
- }
101
+ // adapted from: https://stackoverflow.com/questions/14267781/sorting-html-table-with-javascript/49041392#49041392
102
+ static #comparer(th: HTMLElement, ascending: boolean) {
103
+ // this function is returned and used by `sort`
104
+ const sorter = (a: HTMLTableRowElement, b: HTMLTableRowElement) => {
105
+ // find the column to sort by using the index of the `th`
106
+ const columnIndex = Array.from(th.parentNode?.children ?? []).indexOf(th);
107
+
108
+ const compare = (aVal: string, bVal: string) => {
109
+ // default to `string` sorting
110
+ const dataType = (th.dataset.type ?? "string") as
111
+ | "string"
112
+ | "boolean"
113
+ | "number";
114
+
115
+ if (dataType === "string") {
116
+ const collator = new Intl.Collator();
117
+ return collator.compare(aVal, bVal);
118
+ } else if (dataType === "boolean") {
119
+ return TableSort.#falsyBoolean(aVal) === TableSort.#falsyBoolean(bVal)
120
+ ? 0
121
+ : TableSort.#falsyBoolean(aVal)
122
+ ? -1
123
+ : 1;
124
+ } else {
125
+ // "number"
126
+ return Number(aVal) - Number(bVal);
127
+ }
128
+ };
129
+
130
+ return compare(
131
+ TableSort.#getValue(ascending ? a : b, columnIndex),
132
+ TableSort.#getValue(ascending ? b : a, columnIndex),
133
+ );
130
134
  };
131
135
 
132
- return compare(
133
- getValue(ascending ? a : b, columnIndex),
134
- getValue(ascending ? b : a, columnIndex),
135
- );
136
- };
136
+ return sorter;
137
+ }
137
138
 
138
- return sorter;
139
- };
139
+ /**
140
+ * @param tr the row
141
+ * @param i index of the `td` to find
142
+ * @returns a string, the `data-value` attribute, or the `textContent`
143
+ */
144
+ static #getValue(tr: HTMLTableRowElement, i: number) {
145
+ const cell = tr.children[i];
140
146
 
141
- /**
142
- * @param tr the row
143
- * @param i index of the `td` to find
144
- * @returns a string, the `data-value` attribute, or the `textContent`
145
- */
146
- const getValue = (tr: HTMLTableRowElement, i: number) => {
147
- const cell = tr.children[i];
148
- if (cell instanceof HTMLElement) {
149
- // first look for `data-value` attribute, then use `textContent`
150
- return cell.dataset.value ?? cell.textContent ?? "";
151
- }
152
- return "";
153
- };
147
+ if (cell instanceof HTMLElement) {
148
+ // first look for `data-value` attribute, then use `textContent`
149
+ return cell.dataset.value ?? cell.textContent ?? "";
150
+ }
154
151
 
155
- /**
156
- * if value is one of these and type is boolean
157
- * it should be considered falsy
158
- * since actually `Boolean("false") === true`
159
- * @param val string pulled from the textContent or attr
160
- * @returns a boolean of the provided string
161
- */
162
- const falsyBoolean = (val: string) => {
163
- if (["0", "false", "null", "undefined"].includes(val)) {
164
- return false;
152
+ return "";
165
153
  }
166
154
 
167
- return Boolean(val);
168
- };
155
+ static #falsyStrings = new Set(["0", "false", "null", "undefined"]);
156
+
157
+ /**
158
+ * if value is one of these and type is boolean
159
+ * it should be considered falsy
160
+ * since actually `Boolean("false") === true`
161
+ * @param val string pulled from the textContent or attr
162
+ * @returns a boolean of the provided string
163
+ */
164
+ static #falsyBoolean(val: string) {
165
+ if (TableSort.#falsyStrings.has(val)) return false;
166
+
167
+ return Boolean(val);
168
+ }
169
+ }
package/src/tabs/index.ts CHANGED
@@ -35,7 +35,14 @@ export interface TabsAttributes extends TriggerAttributes {
35
35
  */
36
36
  export class Tabs extends Lifecycle(Trigger()) {
37
37
  /** Supported keys for keyboard navigation. */
38
- #keys = ["ArrowRight", "ArrowDown", "ArrowLeft", "ArrowUp", "Home", "End"];
38
+ readonly #keys = [
39
+ "ArrowRight",
40
+ "ArrowDown",
41
+ "ArrowLeft",
42
+ "ArrowUp",
43
+ "Home",
44
+ "End",
45
+ ];
39
46
 
40
47
  /** Currently selected tab. */
41
48
  #selected: { tab?: HTMLAnchorElement; index: number } = { index: 0 };
@@ -74,6 +81,7 @@ export class Tabs extends Lifecycle(Trigger()) {
74
81
 
75
82
  for (const tab of this.#tabs) {
76
83
  const panel = this.querySelector(tab.hash);
84
+
77
85
  if (!(panel instanceof HTMLElement))
78
86
  throw new Error(`Tabs: No HTMLElement with ID of ${tab.hash} found.`);
79
87
 
@@ -86,13 +94,19 @@ export class Tabs extends Lifecycle(Trigger()) {
86
94
  override mount() {
87
95
  // create tablist
88
96
  const [first, ...rest] = this.#tabs;
97
+
89
98
  let common = this.#ancestors(first);
99
+
90
100
  for (let i = 0; i < rest.length; i++) {
91
101
  common = common.intersection(this.#ancestors(rest[i]));
92
102
  }
103
+
93
104
  const [tablist] = common;
94
- if (!tablist)
105
+
106
+ if (!tablist) {
95
107
  throw new Error("Tabs: No common parent element found for triggers.");
108
+ }
109
+
96
110
  tablist.role = "tablist";
97
111
  tablist.ariaOrientation = this.#orientation;
98
112
 
@@ -1,6 +1,5 @@
1
1
  import type { AnnouncerAttributes } from "../announcer/index.js";
2
2
  import type { ContextMenuAttributes } from "../contextmenu/index.js";
3
- import type { DialogAttributes } from "../dialog/index.js";
4
3
  import type { EditorAttributes } from "../editor/index.js";
5
4
  import type { FullscreenAttributes } from "../fullscreen/index.js";
6
5
  import type { IntersectAttributes } from "../intersect/index.js";
@@ -13,7 +12,6 @@ import type { WakeLockAttributes } from "../wakelock/index.js";
13
12
  export interface Attributes {
14
13
  announcer: AnnouncerAttributes;
15
14
  contextmenu: ContextMenuAttributes;
16
- dialog: DialogAttributes;
17
15
  editor: EditorAttributes;
18
16
  fullscreen: FullscreenAttributes;
19
17
  intersect: IntersectAttributes;
@@ -9,8 +9,9 @@ export const validate = <T extends HTMLElement>(
9
9
  actual: unknown,
10
10
  expected: Constructor<T>,
11
11
  ) => {
12
- if (!(actual instanceof expected))
12
+ if (!(actual instanceof expected)) {
13
13
  throw new TypeError(`${actual} is not an instance of ${expected.name}.`);
14
+ }
14
15
 
15
16
  return actual;
16
17
  };
@@ -8,8 +8,7 @@ import {
8
8
  } from "../base/index.js";
9
9
 
10
10
  export interface WakeLockAttributes
11
- extends TriggerAttributes,
12
- ContentAttributes {
11
+ extends TriggerAttributes, ContentAttributes {
13
12
  /** Auto request wakelock when user returns to inactive tab. */
14
13
  "auto-lock"?: boolean;
15
14
 
@@ -118,9 +117,7 @@ export class WakeLock extends Lifecycle(Trigger(Content(Announce()))) {
118
117
  // When the tab is not visible, the wakeLock is automatically released.
119
118
  // This requests it back if it exists, if it is `null`, that
120
119
  // means it was removed. In which case, it shouldn't be requested again.
121
- if (this.#wakeLock) {
122
- this.request();
123
- }
120
+ if (this.#wakeLock) this.request();
124
121
  },
125
122
  document,
126
123
  );
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=define.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../../src/dialog/define.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- import { define } from "../util/define.js";
2
- import { Dialog } from "./index.js";
3
- define("drab-dialog", Dialog);