@bodil/dom 0.1.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/LICENCE.md +288 -0
- package/dist/component.d.ts +147 -0
- package/dist/component.js +405 -0
- package/dist/component.js.map +1 -0
- package/dist/component.test.d.ts +1 -0
- package/dist/component.test.js +141 -0
- package/dist/component.test.js.map +1 -0
- package/dist/css.d.ts +14 -0
- package/dist/css.js +63 -0
- package/dist/css.js.map +1 -0
- package/dist/decorators/attribute.d.ts +26 -0
- package/dist/decorators/attribute.js +115 -0
- package/dist/decorators/attribute.js.map +1 -0
- package/dist/decorators/attribute.test.d.ts +1 -0
- package/dist/decorators/attribute.test.js +148 -0
- package/dist/decorators/attribute.test.js.map +1 -0
- package/dist/decorators/connect.d.ts +9 -0
- package/dist/decorators/connect.js +44 -0
- package/dist/decorators/connect.js.map +1 -0
- package/dist/decorators/connect.test.d.ts +1 -0
- package/dist/decorators/connect.test.js +196 -0
- package/dist/decorators/connect.test.js.map +1 -0
- package/dist/decorators/reactive.d.ts +7 -0
- package/dist/decorators/reactive.js +45 -0
- package/dist/decorators/reactive.js.map +1 -0
- package/dist/decorators/reactive.test.d.ts +1 -0
- package/dist/decorators/reactive.test.js +113 -0
- package/dist/decorators/reactive.test.js.map +1 -0
- package/dist/decorators/require.d.ts +3 -0
- package/dist/decorators/require.js +6 -0
- package/dist/decorators/require.js.map +1 -0
- package/dist/decorators/require.test.d.ts +1 -0
- package/dist/decorators/require.test.js +117 -0
- package/dist/decorators/require.test.js.map +1 -0
- package/dist/dom.d.ts +92 -0
- package/dist/dom.js +354 -0
- package/dist/dom.js.map +1 -0
- package/dist/emitter.d.ts +10 -0
- package/dist/emitter.js +17 -0
- package/dist/emitter.js.map +1 -0
- package/dist/event.d.ts +70 -0
- package/dist/event.js +14 -0
- package/dist/event.js.map +1 -0
- package/dist/event.test.d.ts +1 -0
- package/dist/event.test.js +20 -0
- package/dist/event.test.js.map +1 -0
- package/dist/geometry.d.ts +48 -0
- package/dist/geometry.js +117 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/scheduler.d.ts +2 -0
- package/dist/scheduler.js +54 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/slot.d.ts +31 -0
- package/dist/slot.js +67 -0
- package/dist/slot.js.map +1 -0
- package/dist/test-global.d.ts +0 -0
- package/dist/test-global.js +5 -0
- package/dist/test-global.js.map +1 -0
- package/package.json +116 -0
- package/src/component.test.ts +90 -0
- package/src/component.ts +607 -0
- package/src/css.ts +69 -0
- package/src/decorators/attribute.test.ts +77 -0
- package/src/decorators/attribute.ts +197 -0
- package/src/decorators/connect.test.ts +119 -0
- package/src/decorators/connect.ts +85 -0
- package/src/decorators/reactive.test.ts +45 -0
- package/src/decorators/reactive.ts +80 -0
- package/src/decorators/require.test.ts +57 -0
- package/src/decorators/require.ts +11 -0
- package/src/dom.ts +456 -0
- package/src/emitter.ts +32 -0
- package/src/event.test.ts +22 -0
- package/src/event.ts +74 -0
- package/src/geometry.ts +147 -0
- package/src/index.ts +12 -0
- package/src/scheduler.ts +58 -0
- package/src/slot.ts +95 -0
- package/src/test-global.ts +5 -0
package/dist/geometry.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
function rectFor(value) {
|
|
2
|
+
const bounds = value instanceof Element ? value.getBoundingClientRect() : value;
|
|
3
|
+
return new DOMRect(roundByDPR(bounds.x), roundByDPR(bounds.y), roundByDPR(bounds.width), roundByDPR(bounds.height));
|
|
4
|
+
}
|
|
5
|
+
function rectPoints(rect) {
|
|
6
|
+
return [
|
|
7
|
+
DOMPoint.fromPoint({ x: rect.left, y: rect.top }),
|
|
8
|
+
DOMPoint.fromPoint({ x: rect.right, y: rect.top }),
|
|
9
|
+
DOMPoint.fromPoint({ x: rect.right, y: rect.bottom }),
|
|
10
|
+
DOMPoint.fromPoint({ x: rect.left, y: rect.bottom }),
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
function normalsIntersect(left1, right1, y1, x2, top2, bottom2) {
|
|
14
|
+
return left1 <= x2 && right1 >= x2 && top2 <= y1 && bottom2 >= y1;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Test whether the rectangle `inner` is fully contained inside the rectangle
|
|
18
|
+
* `outer`.
|
|
19
|
+
*/
|
|
20
|
+
export function contains(inner, outer) {
|
|
21
|
+
const a = rectFor(inner), b = rectFor(outer);
|
|
22
|
+
return a.top >= b.top && a.bottom <= b.bottom && a.left >= b.left && a.right <= b.right;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Test whether the point `p` lies inside the rectangle `rect`.
|
|
26
|
+
*/
|
|
27
|
+
export function containsPoint(p, rect) {
|
|
28
|
+
const r = rectFor(rect);
|
|
29
|
+
return p.x >= r.left && p.x <= r.right && p.y >= r.top && p.y <= r.bottom;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Test whether the rectangles `rectA` and `rectB` intersect.
|
|
33
|
+
*/
|
|
34
|
+
export function intersects(rectA, rectB) {
|
|
35
|
+
const a = rectFor(rectA), b = rectFor(rectB);
|
|
36
|
+
// For each of the two horizontal edges in each rectangle, check if they
|
|
37
|
+
// intersect with any of the two vertical edges in the opposite rectangle.
|
|
38
|
+
// If no edges intersect, we check to see if any of the four corner points
|
|
39
|
+
// of each rectangle lies inside the other rectangle. If none of these
|
|
40
|
+
// conditions are true, the rectangles don't intersect.
|
|
41
|
+
return (normalsIntersect(a.left, a.right, a.top, b.left, b.top, b.bottom) ||
|
|
42
|
+
normalsIntersect(a.left, a.right, a.bottom, b.left, b.top, b.bottom) ||
|
|
43
|
+
normalsIntersect(a.left, a.right, a.top, b.right, b.top, b.bottom) ||
|
|
44
|
+
normalsIntersect(a.left, a.right, a.bottom, b.right, b.top, b.bottom) ||
|
|
45
|
+
normalsIntersect(b.left, b.right, b.top, a.left, a.top, a.bottom) ||
|
|
46
|
+
normalsIntersect(b.left, b.right, b.bottom, a.left, a.top, a.bottom) ||
|
|
47
|
+
normalsIntersect(b.left, b.right, b.top, a.right, a.top, a.bottom) ||
|
|
48
|
+
normalsIntersect(b.left, b.right, b.bottom, a.right, a.top, a.bottom) ||
|
|
49
|
+
rectPoints(a).some((p) => containsPoint(p, b)) ||
|
|
50
|
+
rectPoints(b).some((p) => containsPoint(p, a)));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Test if a rectangle intersects with a given Y coordinate bound.
|
|
54
|
+
*/
|
|
55
|
+
export function intersectsHeightRange(rect, top, bottom) {
|
|
56
|
+
const r = rectFor(rect);
|
|
57
|
+
return r.bottom >= top && r.top <= bottom;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Test if a rectangle intersects with a given Y coordinate.
|
|
61
|
+
*/
|
|
62
|
+
export function intersectsHeight(rect, y, margin = 0) {
|
|
63
|
+
return intersectsHeightRange(rect, y - margin, y + margin);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Test if a rectangle lies fully within a given Y coordinate bound.
|
|
67
|
+
*/
|
|
68
|
+
export function containsHeightRange(rect, top, bottom) {
|
|
69
|
+
const r = rectFor(rect);
|
|
70
|
+
return r.top >= top && r.bottom <= bottom;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Decide how much of a rectangle lies within a given Y coordinate bound.
|
|
74
|
+
* Returns a value between 0 and 1.
|
|
75
|
+
*/
|
|
76
|
+
export function containsHeightRatio(rect, top, bottom) {
|
|
77
|
+
const r = rectFor(rect);
|
|
78
|
+
if (r.bottom < top || r.top > bottom) {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
if (r.top >= top && r.bottom <= bottom) {
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
if (r.top < top) {
|
|
85
|
+
return (r.bottom - top) / r.height;
|
|
86
|
+
}
|
|
87
|
+
else if (r.bottom > bottom) {
|
|
88
|
+
return (bottom - r.top) / r.height;
|
|
89
|
+
}
|
|
90
|
+
throw new Error("unexpected fallthrough case in containsHeightRatio()");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Return a {@link DOMRect} that is aligned inside `outer` while preserving the
|
|
94
|
+
* aspect ratio of `inner`.
|
|
95
|
+
*/
|
|
96
|
+
export function fitRect(inner, outer) {
|
|
97
|
+
if (inner.width / inner.height < outer.width / outer.height) {
|
|
98
|
+
// portrait
|
|
99
|
+
const scale = outer.height / inner.height;
|
|
100
|
+
const targetWidth = inner.width * scale;
|
|
101
|
+
return new DOMRect(outer.width / 2 - targetWidth / 2, 0, targetWidth, outer.height);
|
|
102
|
+
}
|
|
103
|
+
// landscape
|
|
104
|
+
const scale = outer.width / inner.width;
|
|
105
|
+
const targetHeight = inner.height * scale;
|
|
106
|
+
return new DOMRect(0, outer.height / 2 - targetHeight / 2, outer.width, targetHeight);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Round a value to the window's device pixel ratio.
|
|
110
|
+
*
|
|
111
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
|
|
112
|
+
*/
|
|
113
|
+
export function roundByDPR(value) {
|
|
114
|
+
const dpr = window.devicePixelRatio || 1;
|
|
115
|
+
return Math.round(value * dpr) / dpr;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM and web component tools.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import * as component from "./component";
|
|
6
|
+
import * as css from "./css";
|
|
7
|
+
import * as dom from "./dom";
|
|
8
|
+
import * as event from "./event";
|
|
9
|
+
import * as geometry from "./geometry";
|
|
10
|
+
export { component, css, dom, event, geometry };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM and web component tools.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import * as component from "./component";
|
|
6
|
+
import * as css from "./css";
|
|
7
|
+
import * as dom from "./dom";
|
|
8
|
+
import * as event from "./event";
|
|
9
|
+
import * as geometry from "./geometry";
|
|
10
|
+
export { component, css, dom, event, geometry };
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAC7B,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DisposableContext, timeout } from "@bodil/core/disposable";
|
|
2
|
+
import { animationFrame } from "./dom";
|
|
3
|
+
const MAX_BATCH_TIME = 1000 / 15; // 30fps
|
|
4
|
+
const MIN_JOBS_PER_BATCH = 32;
|
|
5
|
+
let schedulerRequested = false;
|
|
6
|
+
const scheduledJobs = new Set();
|
|
7
|
+
const schedulerContext = new DisposableContext();
|
|
8
|
+
function shiftSet(set) {
|
|
9
|
+
const result = set[Symbol.iterator]().next();
|
|
10
|
+
if (result.done === true) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const item = result.value;
|
|
14
|
+
set.delete(item);
|
|
15
|
+
return item;
|
|
16
|
+
}
|
|
17
|
+
function runScheduler() {
|
|
18
|
+
schedulerContext.dispose();
|
|
19
|
+
const startTime = performance.now();
|
|
20
|
+
let count = 0;
|
|
21
|
+
let item;
|
|
22
|
+
while ((item = shiftSet(scheduledJobs)) !== undefined) {
|
|
23
|
+
count += 1;
|
|
24
|
+
try {
|
|
25
|
+
item.performUpdate();
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
// eslint-disable-next-line no-console
|
|
29
|
+
console.error("error while updating:", e);
|
|
30
|
+
}
|
|
31
|
+
const elapsedTime = performance.now() - startTime;
|
|
32
|
+
if (elapsedTime > MAX_BATCH_TIME && count >= MIN_JOBS_PER_BATCH) {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (scheduledJobs.size > 0) {
|
|
37
|
+
startScheduler();
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
schedulerRequested = false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function startScheduler() {
|
|
44
|
+
schedulerContext.use(animationFrame(runScheduler));
|
|
45
|
+
schedulerContext.use(timeout(runScheduler, 1000));
|
|
46
|
+
}
|
|
47
|
+
export function scheduler(component) {
|
|
48
|
+
scheduledJobs.add(component);
|
|
49
|
+
if (!schedulerRequested) {
|
|
50
|
+
schedulerRequested = true;
|
|
51
|
+
startScheduler();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGpE,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,cAAc,GAAW,IAAI,GAAG,EAAE,CAAC,CAAC,QAAQ;AAClD,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B,IAAI,kBAAkB,GAAG,KAAK,CAAC;AAC/B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAa,CAAC;AAC3C,MAAM,gBAAgB,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAEjD,SAAS,QAAQ,CAAI,GAAW;IAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7C,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;IAC1B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,YAAY;IACjB,gBAAgB,CAAC,OAAO,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,IAAI,CAAC;IACT,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QACpD,KAAK,IAAI,CAAC,CAAC;QACX,IAAI,CAAC;YACA,IAA6C,CAAC,aAAa,EAAE,CAAC;QACnE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAClD,IAAI,WAAW,GAAG,cAAc,IAAI,KAAK,IAAI,kBAAkB,EAAE,CAAC;YAC9D,MAAM;QACV,CAAC;IACL,CAAC;IACD,IAAI,aAAa,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACzB,cAAc,EAAE,CAAC;IACrB,CAAC;SAAM,CAAC;QACJ,kBAAkB,GAAG,KAAK,CAAC;IAC/B,CAAC;AACL,CAAC;AAED,SAAS,cAAc;IACnB,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IACnD,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,SAAoB;IAC1C,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACtB,kBAAkB,GAAG,IAAI,CAAC;QAC1B,cAAc,EAAE,CAAC;IACrB,CAAC;AACL,CAAC"}
|
package/dist/slot.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Signal } from "@bodil/signal";
|
|
2
|
+
import type { ReactiveController } from "lit";
|
|
3
|
+
import type { Constructor } from "type-fest";
|
|
4
|
+
import type { Component } from "./component";
|
|
5
|
+
export interface QuerySlotOptions extends AssignedNodesOptions {
|
|
6
|
+
/** The name of the slot to query, or `undefined` for the default slot. */
|
|
7
|
+
slot?: string;
|
|
8
|
+
/** Whether to include all nodes instead of just elements. */
|
|
9
|
+
nodes?: boolean;
|
|
10
|
+
/** A CSS selector to filter by. */
|
|
11
|
+
selector?: string;
|
|
12
|
+
/** A class constructor to filter by, eg. `instanceOf: HTMLDivElement` */
|
|
13
|
+
instanceOf?: Constructor<unknown>;
|
|
14
|
+
/** Create a signal which will update with changes to the slot's contents. */
|
|
15
|
+
reactive?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function findSlot(root: Component, slot: string | undefined): HTMLSlotElement | null;
|
|
18
|
+
export declare class SlotChangeController implements ReactiveController {
|
|
19
|
+
private readonly host;
|
|
20
|
+
private readonly slot;
|
|
21
|
+
private readonly sig;
|
|
22
|
+
private readonly query;
|
|
23
|
+
private readonly context;
|
|
24
|
+
constructor(host: Component, slot: string | undefined, sig: Signal.State<Array<Node>>, query: (slot: HTMLSlotElement) => Array<Node>);
|
|
25
|
+
updateSlot(slot: HTMLSlotElement): void;
|
|
26
|
+
hostDisconnected(): void;
|
|
27
|
+
hostConnected(): void;
|
|
28
|
+
hostUpdated(): void;
|
|
29
|
+
}
|
|
30
|
+
export declare function getOrSetQuery<A>(obj: object, options: QuerySlotOptions, create: () => A): A;
|
|
31
|
+
export declare function getOrSetSignal<A>(obj: object, query: unknown, create: () => A): A;
|
package/dist/slot.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DisposableContext } from "@bodil/core/disposable";
|
|
2
|
+
import { eventListener } from "./event";
|
|
3
|
+
export function findSlot(root, slot) {
|
|
4
|
+
const slotSelector = `slot${slot !== undefined ? `[name=${slot}]` : ":not([name])"}`;
|
|
5
|
+
return root.renderRoot.querySelector(slotSelector);
|
|
6
|
+
}
|
|
7
|
+
export class SlotChangeController {
|
|
8
|
+
constructor(host, slot, sig, query) {
|
|
9
|
+
this.host = host;
|
|
10
|
+
this.slot = slot;
|
|
11
|
+
this.sig = sig;
|
|
12
|
+
this.query = query;
|
|
13
|
+
this.context = new DisposableContext();
|
|
14
|
+
}
|
|
15
|
+
updateSlot(slot) {
|
|
16
|
+
this.sig.set(this.query(slot));
|
|
17
|
+
}
|
|
18
|
+
hostDisconnected() {
|
|
19
|
+
this.context.dispose();
|
|
20
|
+
}
|
|
21
|
+
hostConnected() {
|
|
22
|
+
this.hostUpdated();
|
|
23
|
+
}
|
|
24
|
+
hostUpdated() {
|
|
25
|
+
this.context.dispose();
|
|
26
|
+
const slot = findSlot(this.host, this.slot);
|
|
27
|
+
if (slot !== null) {
|
|
28
|
+
this.context.use(eventListener(slot, "slotchange", this.updateSlot.bind(this, slot)));
|
|
29
|
+
this.updateSlot(slot);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const queryCache = new WeakMap();
|
|
34
|
+
export function getOrSetQuery(obj, options, create) {
|
|
35
|
+
let stringCache = queryCache.get(obj);
|
|
36
|
+
if (stringCache === undefined) {
|
|
37
|
+
stringCache = new Map();
|
|
38
|
+
queryCache.set(obj, stringCache);
|
|
39
|
+
}
|
|
40
|
+
const key = `query:${options.selector ?? ""}:${options.nodes ?? false}:${options.flatten ?? false}`;
|
|
41
|
+
let constructorCache = stringCache.get(key);
|
|
42
|
+
if (constructorCache === undefined) {
|
|
43
|
+
constructorCache = new Map();
|
|
44
|
+
stringCache.set(key, constructorCache);
|
|
45
|
+
}
|
|
46
|
+
let query = constructorCache.get(options.instanceOf);
|
|
47
|
+
if (query === undefined) {
|
|
48
|
+
query = create();
|
|
49
|
+
constructorCache.set(options.instanceOf, query);
|
|
50
|
+
}
|
|
51
|
+
return query;
|
|
52
|
+
}
|
|
53
|
+
const signalCache = new WeakMap();
|
|
54
|
+
export function getOrSetSignal(obj, query, create) {
|
|
55
|
+
let innerCache = signalCache.get(obj);
|
|
56
|
+
if (innerCache === undefined) {
|
|
57
|
+
innerCache = new Map();
|
|
58
|
+
signalCache.set(obj, innerCache);
|
|
59
|
+
}
|
|
60
|
+
let signal = innerCache.get(query);
|
|
61
|
+
if (signal === undefined) {
|
|
62
|
+
signal = create();
|
|
63
|
+
innerCache.set(query, signal);
|
|
64
|
+
}
|
|
65
|
+
return signal;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=slot.js.map
|
package/dist/slot.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.js","sourceRoot":"","sources":["../src/slot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAM3D,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAexC,MAAM,UAAU,QAAQ,CAAC,IAAe,EAAE,IAAwB;IAC9D,MAAM,YAAY,GAAG,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;IACrF,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAkB,YAAY,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,OAAO,oBAAoB;IAG7B,YACqB,IAAe,EACf,IAAwB,EACxB,GAA8B,EAC9B,KAA6C;QAH7C,SAAI,GAAJ,IAAI,CAAW;QACf,SAAI,GAAJ,IAAI,CAAoB;QACxB,QAAG,GAAH,GAAG,CAA2B;QAC9B,UAAK,GAAL,KAAK,CAAwC;QANjD,YAAO,GAAG,IAAI,iBAAiB,EAAE,CAAC;IAOhD,CAAC;IAEJ,UAAU,CAAC,IAAqB;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,gBAAgB;QACZ,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,aAAa;QACT,IAAI,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IAED,WAAW;QACP,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YACtF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACL,CAAC;CACJ;AAED,MAAM,UAAU,GAAG,IAAI,OAAO,EAA8C,CAAC;AAE7E,MAAM,UAAU,aAAa,CAAI,GAAW,EAAE,OAAyB,EAAE,MAAe;IACpF,IAAI,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC5B,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC;QACxB,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,OAAO,CAAC,QAAQ,IAAI,EAAE,IAAI,OAAO,CAAC,KAAK,IAAI,KAAK,IAAI,OAAO,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC;IACpG,IAAI,gBAAgB,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACjC,gBAAgB,GAAG,IAAI,GAAG,EAAE,CAAC;QAC7B,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,KAAK,GAAG,MAAM,EAAE,CAAC;QACjB,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,KAAU,CAAC;AACtB,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,OAAO,EAAiC,CAAC;AAEjE,MAAM,UAAU,cAAc,CAAI,GAAW,EAAE,KAAc,EAAE,MAAe;IAC1E,IAAI,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC3B,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;QACvB,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,GAAG,MAAM,EAAE,CAAC;QAClB,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAW,CAAC;AACvB,CAAC"}
|
|
File without changes
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shut up, Wesley! https://github.com/lit/lit/issues/4877
|
|
3
|
+
globalThis.litIssuedWarnings ??= new Set();
|
|
4
|
+
globalThis.litIssuedWarnings.add("Lit is in dev mode. Not recommended for production! See https://lit.dev/msg/dev-mode for more information.");
|
|
5
|
+
//# sourceMappingURL=test-global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-global.js","sourceRoot":"","sources":["../src/test-global.ts"],"names":[],"mappings":";AAAA,0DAA0D;AACzD,UAAkB,CAAC,iBAAiB,KAAK,IAAI,GAAG,EAAE,CAAC;AACnD,UAAkB,CAAC,iBAAiB,CAAC,GAAG,CACrC,4GAA4G,CAC/G,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bodil/dom",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "DOM and web component tools",
|
|
5
|
+
"homepage": "https://codeberg.org/bodil/dom",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://codeberg.org/bodil/dom.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "EUPL-1.2+",
|
|
11
|
+
"module": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"import": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"./component": {
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./dist/component.d.ts",
|
|
27
|
+
"import": "./dist/component.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./css": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/css.d.ts",
|
|
33
|
+
"import": "./dist/css.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"./dom": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/dom.d.ts",
|
|
39
|
+
"import": "./dist/dom.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"./event": {
|
|
43
|
+
"import": {
|
|
44
|
+
"types": "./dist/event.d.ts",
|
|
45
|
+
"import": "./dist/event.js"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"./geometry": {
|
|
49
|
+
"import": {
|
|
50
|
+
"types": "./dist/geometry.d.ts",
|
|
51
|
+
"import": "./dist/geometry.js"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@bodil/core": "^0.4.9",
|
|
60
|
+
"@bodil/opt": "^0.4.2",
|
|
61
|
+
"@bodil/signal": "^0.3.3",
|
|
62
|
+
"lit": "^3.3.1",
|
|
63
|
+
"type-fest": "^5.3.1"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
67
|
+
"@eslint/js": "^9.39.2",
|
|
68
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
|
69
|
+
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
|
70
|
+
"@typescript-eslint/parser": "^8.49.0",
|
|
71
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
72
|
+
"eslint": "^9.39.2",
|
|
73
|
+
"eslint-config-prettier": "^10.1.8",
|
|
74
|
+
"eslint-plugin-jsdoc": "^54.7.0",
|
|
75
|
+
"globals": "^16.5.0",
|
|
76
|
+
"happy-dom": "^20.0.11",
|
|
77
|
+
"npm-run-all2": "^8.0.4",
|
|
78
|
+
"prettier": "^3.7.4",
|
|
79
|
+
"typedoc": "^0.28.15",
|
|
80
|
+
"typedoc-plugin-extras": "^4.0.1",
|
|
81
|
+
"typedoc-plugin-mdn-links": "^5.0.10",
|
|
82
|
+
"typescript": "^5.9.3",
|
|
83
|
+
"vitest": "^4.0.15"
|
|
84
|
+
},
|
|
85
|
+
"prettier": {
|
|
86
|
+
"editorconfig": true,
|
|
87
|
+
"plugins": [
|
|
88
|
+
"@ianvs/prettier-plugin-sort-imports"
|
|
89
|
+
],
|
|
90
|
+
"importOrderParserPlugins": [
|
|
91
|
+
"typescript",
|
|
92
|
+
"decorators"
|
|
93
|
+
],
|
|
94
|
+
"importOrderTypeScriptVersion": "5.0.0",
|
|
95
|
+
"importOrder": [
|
|
96
|
+
"",
|
|
97
|
+
"<BUILTIN_MODULES>",
|
|
98
|
+
"",
|
|
99
|
+
"<THIRD_PARTY_MODULES>",
|
|
100
|
+
"",
|
|
101
|
+
"^[.](?!.*[?]inline$)",
|
|
102
|
+
"",
|
|
103
|
+
"[?]inline$"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"scripts": {
|
|
107
|
+
"build": "tsc",
|
|
108
|
+
"test": "vitest --run",
|
|
109
|
+
"check:eslint": "eslint src",
|
|
110
|
+
"check:tsc": "tsc --noEmit",
|
|
111
|
+
"check": "run-p check:tsc check:eslint",
|
|
112
|
+
"doc": "typedoc",
|
|
113
|
+
"doc:readthedocs": "typedoc --out $READTHEDOCS_OUTPUT/html",
|
|
114
|
+
"prepublish": "tsc"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Signal } from "@bodil/signal";
|
|
2
|
+
import { html } from "lit";
|
|
3
|
+
import { customElement } from "lit/decorators.js";
|
|
4
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
|
+
import { expect, expectTypeOf, test } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { Component } from "./component";
|
|
8
|
+
|
|
9
|
+
test("Component.query", async () => {
|
|
10
|
+
@customElement("query-test-class")
|
|
11
|
+
class QueryTestClass extends Component {
|
|
12
|
+
div = createRef<HTMLDivElement>();
|
|
13
|
+
p = createRef<HTMLParagraphElement>();
|
|
14
|
+
render() {
|
|
15
|
+
return html`<div ${ref(this.div)} class="welp"></div>
|
|
16
|
+
<p ${ref(this.p)} class="welp"></p>`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const t = document.createElement("query-test-class") as QueryTestClass;
|
|
21
|
+
document.body.append(t);
|
|
22
|
+
await t.updateComplete;
|
|
23
|
+
|
|
24
|
+
expect(t.query("div")).toBe(t.div.value);
|
|
25
|
+
expectTypeOf(t.query("div")).toEqualTypeOf<HTMLDivElement | null>();
|
|
26
|
+
expect(t.query("p")).toBe(t.p.value);
|
|
27
|
+
expectTypeOf(t.query("p")).toEqualTypeOf<HTMLParagraphElement | null>();
|
|
28
|
+
expect(t.query(".welp")).toBe(t.div.value);
|
|
29
|
+
expectTypeOf(t.query(".welp")).toEqualTypeOf<Element | null>();
|
|
30
|
+
|
|
31
|
+
expect(Array.from(t.queryAll("div"))).deep.equal([t.div.value]);
|
|
32
|
+
expectTypeOf(t.queryAll("div")).toEqualTypeOf<NodeListOf<HTMLDivElement>>();
|
|
33
|
+
expect(Array.from(t.queryAll("p"))).deep.equal([t.p.value]);
|
|
34
|
+
expectTypeOf(t.queryAll("p")).toEqualTypeOf<NodeListOf<HTMLParagraphElement>>();
|
|
35
|
+
expect(Array.from(t.queryAll(".welp"))).deep.equal([t.div.value, t.p.value]);
|
|
36
|
+
expectTypeOf(t.queryAll(".welp")).toEqualTypeOf<NodeListOf<Element>>();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("Component.querySlot", async () => {
|
|
40
|
+
@customElement("query-slot-test-class")
|
|
41
|
+
class QuerySlotTestClass extends Component {
|
|
42
|
+
render() {
|
|
43
|
+
return html`<slot></slot><slot name="fixes-the-bug"></slot>`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const t = document.createElement("query-slot-test-class") as QuerySlotTestClass;
|
|
48
|
+
document.body.append(t);
|
|
49
|
+
|
|
50
|
+
const e = (cls: string, slot?: string) => {
|
|
51
|
+
const el = document.createElement("div");
|
|
52
|
+
el.classList.add(cls);
|
|
53
|
+
if (slot !== undefined) {
|
|
54
|
+
el.slot = slot;
|
|
55
|
+
}
|
|
56
|
+
t.append(el);
|
|
57
|
+
return el;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const joe = e("joe");
|
|
61
|
+
const mike = e("mike");
|
|
62
|
+
const robert = e("robert", "fixes-the-bug");
|
|
63
|
+
|
|
64
|
+
await t.updateComplete;
|
|
65
|
+
|
|
66
|
+
expect(t.querySlot()).deep.equal([joe, mike]);
|
|
67
|
+
expect(t.querySlot({ slot: "fixes-the-bug" })).deep.equal([robert]);
|
|
68
|
+
|
|
69
|
+
const slot = t.querySlot({ slot: "fixes-the-bug", reactive: true });
|
|
70
|
+
expectTypeOf(slot).toEqualTypeOf<Signal.Computed<Array<Element>>>();
|
|
71
|
+
expect(slot.get()).deep.equal([robert]);
|
|
72
|
+
joe.slot = "fixes-the-bug"; // for argument's sake
|
|
73
|
+
expect(slot.get()).deep.equal([joe, robert]);
|
|
74
|
+
expect(t.querySlot()).deep.equal([mike]);
|
|
75
|
+
robert.removeAttribute("slot");
|
|
76
|
+
expect(slot.get()).deep.equal([joe]);
|
|
77
|
+
expect(t.querySlot()).deep.equal([mike, robert]);
|
|
78
|
+
|
|
79
|
+
const divsByInstance = t.querySlot({ instanceOf: HTMLDivElement });
|
|
80
|
+
expectTypeOf(divsByInstance).toEqualTypeOf<Array<HTMLDivElement>>();
|
|
81
|
+
expect(divsByInstance).deep.equal([mike, robert]);
|
|
82
|
+
|
|
83
|
+
const divsBySelector = t.querySlot({ selector: "div" });
|
|
84
|
+
expectTypeOf(divsBySelector).toEqualTypeOf<Array<HTMLDivElement>>();
|
|
85
|
+
expect(divsBySelector).deep.equal([mike, robert]);
|
|
86
|
+
|
|
87
|
+
expect(t.querySlot({ selector: "div.robert" })).deep.equal([robert]);
|
|
88
|
+
|
|
89
|
+
expectTypeOf(t.querySlot({ nodes: true })).toEqualTypeOf<Array<Node>>();
|
|
90
|
+
});
|