elements-kit 0.27.9 → 0.27.11
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/ui/overlay/index.d.mts +53 -45
- package/dist/ui/overlay/index.mjs +109 -104
- package/dist/utilities/element-rect.d.mts +7 -12
- package/dist/utilities/element-rect.mjs +23 -15
- package/package.json +1 -1
|
@@ -7,6 +7,10 @@ type Axis = keyof ReadonlyBox;
|
|
|
7
7
|
interface IDirection {
|
|
8
8
|
readonly direction: "ltr" | "rtl";
|
|
9
9
|
}
|
|
10
|
+
interface Point {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
}
|
|
10
14
|
interface ReadonlyBox {
|
|
11
15
|
readonly x: number;
|
|
12
16
|
readonly y: number;
|
|
@@ -78,28 +82,31 @@ type NoInline = {
|
|
|
78
82
|
* both edges of one axis.
|
|
79
83
|
*/
|
|
80
84
|
type Boundary = (BlockEdge & InlineEdge) | (BlockEdge & NoInline) | (NoBlock & InlineEdge);
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
/** Horizontal origin keyword, as CSS spells it. */
|
|
86
|
+
type OriginX = "left" | "center" | "right";
|
|
87
|
+
/** The vertical one. */
|
|
88
|
+
type OriginY = "top" | "center" | "bottom";
|
|
89
|
+
/** Which point of a box lands on its position. A `transform-origin`. */
|
|
90
|
+
interface Origin {
|
|
91
|
+
readonly x: OriginX;
|
|
92
|
+
readonly y: OriginY;
|
|
93
|
+
}
|
|
94
|
+
/** Has an origin. */
|
|
95
|
+
interface IOrigin {
|
|
96
|
+
readonly origin: Origin;
|
|
85
97
|
}
|
|
86
98
|
/**
|
|
87
|
-
* Somewhere a box may go:
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* the rest. Size is never returned: the box is placed as given, so one larger
|
|
91
|
-
* than its room overflows rather than shrinks, as CSS does.
|
|
99
|
+
* Somewhere a box may go: each axis pinned or free. `place` never writes, so
|
|
100
|
+
* the caller takes the channels it wants, and never returns a size, so a box
|
|
101
|
+
* larger than its room overflows rather than shrinks, as CSS does.
|
|
92
102
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* inset — both its edges are `null`.
|
|
103
|
+
* `x`/`y` are the pin lines, `origin` the box point landing on them — the
|
|
104
|
+
* pair places a box without measuring it. A free axis has no pin (`null`).
|
|
96
105
|
*/
|
|
97
|
-
interface Region {
|
|
98
|
-
readonly
|
|
99
|
-
readonly
|
|
100
|
-
|
|
101
|
-
readonly bottom: number | null;
|
|
102
|
-
place(box: ReadonlyBox): Placement;
|
|
106
|
+
interface Region extends IOrigin {
|
|
107
|
+
readonly x: number | null;
|
|
108
|
+
readonly y: number | null;
|
|
109
|
+
place(box: ReadonlyBox): Point;
|
|
103
110
|
}
|
|
104
111
|
/**
|
|
105
112
|
* A {@link Region} driven by writes — for gestures, where the box grows away
|
|
@@ -109,6 +116,11 @@ interface Region {
|
|
|
109
116
|
declare class MutableRegion implements Region {
|
|
110
117
|
#private;
|
|
111
118
|
constructor(boundary: Boundary);
|
|
119
|
+
/** The pin line on each axis — `null` where the axis is free. */
|
|
120
|
+
get x(): number | null;
|
|
121
|
+
get y(): number | null;
|
|
122
|
+
/** The box point that lands on ({@link x}, {@link y}). */
|
|
123
|
+
get origin(): Origin;
|
|
112
124
|
get left(): number | null;
|
|
113
125
|
get right(): number | null;
|
|
114
126
|
get top(): number | null;
|
|
@@ -117,7 +129,7 @@ declare class MutableRegion implements Region {
|
|
|
117
129
|
set right(v: number | null);
|
|
118
130
|
set top(v: number | null);
|
|
119
131
|
set bottom(v: number | null);
|
|
120
|
-
place(box: ReadonlyBox):
|
|
132
|
+
place(box: ReadonlyBox): Point;
|
|
121
133
|
}
|
|
122
134
|
//#endregion
|
|
123
135
|
//#region src/ui/overlay/anchor.d.ts
|
|
@@ -162,39 +174,29 @@ type Unordered<A extends string, B extends string> = `${A} ${B}` | `${B} ${A}`;
|
|
|
162
174
|
*/
|
|
163
175
|
type PositionAreaValue = AreaKeyword | Unordered<BlockKeyword, InlineKeyword> | Unordered<BlockKeyword, AmbiguousKeyword> | Unordered<InlineKeyword, AmbiguousKeyword> | `${AmbiguousKeyword} ${AmbiguousKeyword}`;
|
|
164
176
|
/**
|
|
165
|
-
* The reactive `position-area` property:
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* written; the caller takes what it wants from `place`:
|
|
170
|
-
*
|
|
171
|
-
* const area = new PositionArea(a, "top span-left");
|
|
172
|
-
* effect(() => { overlay.x = area.place(overlay).x; });
|
|
177
|
+
* The reactive `position-area` property: which of the anchor's edges a box
|
|
178
|
+
* pins to, and the self-alignment that follows — outward regions hug the
|
|
179
|
+
* anchor's near edge, spans its far edge, center is `anchor-center`. Not a
|
|
180
|
+
* box: a pin per axis, with no geometry of its own.
|
|
173
181
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
182
|
+
* Parsed once, at construction; the pins read the anchor on every access, so
|
|
183
|
+
* reading them in an `effect` tracks it.
|
|
176
184
|
*
|
|
177
|
-
*
|
|
178
|
-
* is
|
|
179
|
-
* being a parameter here.
|
|
180
|
-
*
|
|
181
|
-
* There is no gap parameter, for the same reason CSS has none: the offset off
|
|
182
|
-
* the anchor is the overlay's own `margin`.
|
|
185
|
+
* No gap parameter, for the same reason CSS has none: the offset off the
|
|
186
|
+
* anchor is the overlay's own `margin`.
|
|
183
187
|
*/
|
|
184
|
-
declare class PositionArea implements Region
|
|
188
|
+
declare class PositionArea implements Region {
|
|
185
189
|
#private;
|
|
186
190
|
readonly anchor: ReadonlyBox;
|
|
187
191
|
constructor(anchor: ReadonlyBox, area: PositionAreaValue);
|
|
192
|
+
/** The pin lines — the viewport point {@link origin} lands on. */
|
|
188
193
|
get x(): number;
|
|
189
194
|
get y(): number;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
get
|
|
193
|
-
get right(): number | null;
|
|
194
|
-
get top(): number | null;
|
|
195
|
-
get bottom(): number | null;
|
|
195
|
+
/** The box point landing on ({@link x}, {@link y}). Two axes, not one
|
|
196
|
+
* side: a corner area pins a corner. */
|
|
197
|
+
get origin(): Origin;
|
|
196
198
|
/** Every axis is pinned, so only the box's size is read. */
|
|
197
|
-
place(box: Pick<ReadonlyBox, "w" | "h">):
|
|
199
|
+
place(box: Pick<ReadonlyBox, "w" | "h">): Point;
|
|
198
200
|
}
|
|
199
201
|
//#endregion
|
|
200
202
|
//#region src/ui/overlay/overlay.d.ts
|
|
@@ -224,10 +226,16 @@ declare class Displacement extends PartialBox {
|
|
|
224
226
|
apply(): void;
|
|
225
227
|
clear(): void;
|
|
226
228
|
}
|
|
227
|
-
declare class OverlayBox extends TransformableBox implements IDirection {
|
|
229
|
+
declare class OverlayBox extends TransformableBox implements IDirection, IOrigin {
|
|
228
230
|
#private;
|
|
229
231
|
readonly element: HTMLElement;
|
|
230
232
|
constructor(element: HTMLElement);
|
|
233
|
+
/** The box point that lands on (x, y), and the scale's origin. */
|
|
234
|
+
get origin(): Origin;
|
|
235
|
+
set origin({
|
|
236
|
+
x,
|
|
237
|
+
y
|
|
238
|
+
}: Origin);
|
|
231
239
|
get w(): number;
|
|
232
240
|
set w(value: number);
|
|
233
241
|
get h(): number;
|
|
@@ -283,4 +291,4 @@ declare class Motion implements IMotion {
|
|
|
283
291
|
abort(initial?: number): void;
|
|
284
292
|
}
|
|
285
293
|
//#endregion
|
|
286
|
-
export { type Align, type Axis, type BlockSide, type Boundary, ElementBox, gestures_d_exports as Gestures, type IDirection, type IMotion, type InlineSide, type Inset, Motion, MutableRegion,
|
|
294
|
+
export { type Align, type Axis, type BlockSide, type Boundary, ElementBox, gestures_d_exports as Gestures, type IDirection, type IMotion, type IOrigin, type InlineSide, type Inset, Motion, MutableRegion, type Origin, type OriginX, type OriginY, OverlayBox, type PhysicalInset, type Pin, PositionArea, type PositionAreaValue, type ReadonlyBox, type Region, WINDOW_BOX, WindowBox, anchor_length };
|
|
@@ -12,10 +12,20 @@ function placePinned(pin, n) {
|
|
|
12
12
|
if (pin.align === "end") return pin.at - n;
|
|
13
13
|
return pin.at - n / 2;
|
|
14
14
|
}
|
|
15
|
-
/** One axis of
|
|
15
|
+
/** One axis of {@link Region.place}: pinned, or `own` if free. */
|
|
16
16
|
function placeAxis(pin, own, n) {
|
|
17
17
|
return pin ? placePinned(pin, n) : own;
|
|
18
18
|
}
|
|
19
|
+
/** The box point a pin lands. Physical: direction is resolved before a pin
|
|
20
|
+
* exists, so `left` is left in RTL. A free axis lands the near edge. */
|
|
21
|
+
function originX(pin) {
|
|
22
|
+
if (!pin) return "left";
|
|
23
|
+
return pin.align === "start" ? "left" : pin.align === "end" ? "right" : "center";
|
|
24
|
+
}
|
|
25
|
+
function originY(pin) {
|
|
26
|
+
if (!pin) return "top";
|
|
27
|
+
return pin.align === "start" ? "top" : pin.align === "end" ? "bottom" : "center";
|
|
28
|
+
}
|
|
19
29
|
/** The inset a pin yields on one edge: its coordinate if it pins that edge. */
|
|
20
30
|
function inset(pin, edge) {
|
|
21
31
|
return pin?.align === edge ? pin.at : null;
|
|
@@ -35,6 +45,20 @@ var MutableRegion = class {
|
|
|
35
45
|
if (top !== void 0) this.top = top;
|
|
36
46
|
if (bottom !== void 0) this.bottom = bottom;
|
|
37
47
|
}
|
|
48
|
+
/** The pin line on each axis — `null` where the axis is free. */
|
|
49
|
+
get x() {
|
|
50
|
+
return this.#x()?.at ?? null;
|
|
51
|
+
}
|
|
52
|
+
get y() {
|
|
53
|
+
return this.#y()?.at ?? null;
|
|
54
|
+
}
|
|
55
|
+
/** The box point that lands on ({@link x}, {@link y}). */
|
|
56
|
+
get origin() {
|
|
57
|
+
return {
|
|
58
|
+
x: originX(this.#x()),
|
|
59
|
+
y: originY(this.#y())
|
|
60
|
+
};
|
|
61
|
+
}
|
|
38
62
|
get left() {
|
|
39
63
|
return inset(this.#x(), "start");
|
|
40
64
|
}
|
|
@@ -79,47 +103,6 @@ var MutableRegion = class {
|
|
|
79
103
|
}
|
|
80
104
|
};
|
|
81
105
|
//#endregion
|
|
82
|
-
//#region src/ui/overlay/box.ts
|
|
83
|
-
var WindowBox = class {
|
|
84
|
-
get x() {
|
|
85
|
-
return 0;
|
|
86
|
-
}
|
|
87
|
-
get y() {
|
|
88
|
-
return 0;
|
|
89
|
-
}
|
|
90
|
-
get w() {
|
|
91
|
-
return windowSize.width();
|
|
92
|
-
}
|
|
93
|
-
get h() {
|
|
94
|
-
return windowSize.height();
|
|
95
|
-
}
|
|
96
|
-
get direction() {
|
|
97
|
-
return direction();
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
const WINDOW_BOX = new WindowBox();
|
|
101
|
-
var ElementBox = class {
|
|
102
|
-
#rect;
|
|
103
|
-
constructor(el) {
|
|
104
|
-
this.#rect = createElementRect(el);
|
|
105
|
-
}
|
|
106
|
-
[Symbol.dispose]() {
|
|
107
|
-
this.#rect[Symbol.dispose]();
|
|
108
|
-
}
|
|
109
|
-
get x() {
|
|
110
|
-
return this.#rect().left;
|
|
111
|
-
}
|
|
112
|
-
get y() {
|
|
113
|
-
return this.#rect().top;
|
|
114
|
-
}
|
|
115
|
-
get w() {
|
|
116
|
-
return this.#rect().width;
|
|
117
|
-
}
|
|
118
|
-
get h() {
|
|
119
|
-
return this.#rect().height;
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
//#endregion
|
|
123
106
|
//#region src/ui/overlay/anchor.ts
|
|
124
107
|
/**
|
|
125
108
|
* The reactive `anchor()` function: the viewport coordinate of an anchor line
|
|
@@ -280,37 +263,17 @@ function resolveArea(area, dir = "ltr", selfDir = dir) {
|
|
|
280
263
|
inline: inline ? toPhysical(inline, "inline", dir, selfDir) : "center"
|
|
281
264
|
};
|
|
282
265
|
}
|
|
283
|
-
/** One axis of the position-area containing block, as `[lo, hi]` viewport
|
|
284
|
-
* coordinates. The anchor's two edges cut `[bLo, bHi]` into before/over/after. */
|
|
285
|
-
function axisSpan(lo, hi, bLo, bHi, region) {
|
|
286
|
-
switch (region) {
|
|
287
|
-
case "start": return [bLo, lo];
|
|
288
|
-
case "end": return [hi, bHi];
|
|
289
|
-
case "center": return [lo, hi];
|
|
290
|
-
case "span-start": return [bLo, hi];
|
|
291
|
-
case "span-end": return [lo, bHi];
|
|
292
|
-
default: return [bLo, bHi];
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
266
|
/**
|
|
296
|
-
* The reactive `position-area` property:
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
* written; the caller takes what it wants from `place`:
|
|
301
|
-
*
|
|
302
|
-
* const area = new PositionArea(a, "top span-left");
|
|
303
|
-
* effect(() => { overlay.x = area.place(overlay).x; });
|
|
267
|
+
* The reactive `position-area` property: which of the anchor's edges a box
|
|
268
|
+
* pins to, and the self-alignment that follows — outward regions hug the
|
|
269
|
+
* anchor's near edge, spans its far edge, center is `anchor-center`. Not a
|
|
270
|
+
* box: a pin per axis, with no geometry of its own.
|
|
304
271
|
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
272
|
+
* Parsed once, at construction; the pins read the anchor on every access, so
|
|
273
|
+
* reading them in an `effect` tracks it.
|
|
307
274
|
*
|
|
308
|
-
*
|
|
309
|
-
* is
|
|
310
|
-
* being a parameter here.
|
|
311
|
-
*
|
|
312
|
-
* There is no gap parameter, for the same reason CSS has none: the offset off
|
|
313
|
-
* the anchor is the overlay's own `margin`.
|
|
275
|
+
* No gap parameter, for the same reason CSS has none: the offset off the
|
|
276
|
+
* anchor is the overlay's own `margin`.
|
|
314
277
|
*/
|
|
315
278
|
var PositionArea = class {
|
|
316
279
|
anchor;
|
|
@@ -319,18 +282,6 @@ var PositionArea = class {
|
|
|
319
282
|
this.anchor = anchor;
|
|
320
283
|
this.#area = resolveArea(area, rootDirection());
|
|
321
284
|
}
|
|
322
|
-
/** The inline axis as `[lo, hi]`, re-read from the anchor and window. */
|
|
323
|
-
get #ix() {
|
|
324
|
-
const a = this.anchor;
|
|
325
|
-
const w = WINDOW_BOX;
|
|
326
|
-
return axisSpan(a.x, a.x + a.w, w.x, w.x + w.w, this.#area.inline);
|
|
327
|
-
}
|
|
328
|
-
/** The block axis as `[lo, hi]`. */
|
|
329
|
-
get #iy() {
|
|
330
|
-
const a = this.anchor;
|
|
331
|
-
const w = WINDOW_BOX;
|
|
332
|
-
return axisSpan(a.y, a.y + a.h, w.y, w.y + w.h, this.#area.block);
|
|
333
|
-
}
|
|
334
285
|
get #px() {
|
|
335
286
|
const a = this.anchor;
|
|
336
287
|
return pinOf(this.#area.inline, a.x, a.x + a.w);
|
|
@@ -339,31 +290,20 @@ var PositionArea = class {
|
|
|
339
290
|
const a = this.anchor;
|
|
340
291
|
return pinOf(this.#area.block, a.y, a.y + a.h);
|
|
341
292
|
}
|
|
293
|
+
/** The pin lines — the viewport point {@link origin} lands on. */
|
|
342
294
|
get x() {
|
|
343
|
-
return this.#
|
|
295
|
+
return this.#px.at;
|
|
344
296
|
}
|
|
345
297
|
get y() {
|
|
346
|
-
return this.#
|
|
298
|
+
return this.#py.at;
|
|
347
299
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
get left() {
|
|
357
|
-
return inset(this.#px, "start");
|
|
358
|
-
}
|
|
359
|
-
get right() {
|
|
360
|
-
return inset(this.#px, "end");
|
|
361
|
-
}
|
|
362
|
-
get top() {
|
|
363
|
-
return inset(this.#py, "start");
|
|
364
|
-
}
|
|
365
|
-
get bottom() {
|
|
366
|
-
return inset(this.#py, "end");
|
|
300
|
+
/** The box point landing on ({@link x}, {@link y}). Two axes, not one
|
|
301
|
+
* side: a corner area pins a corner. */
|
|
302
|
+
get origin() {
|
|
303
|
+
return {
|
|
304
|
+
x: originX(this.#px),
|
|
305
|
+
y: originY(this.#py)
|
|
306
|
+
};
|
|
367
307
|
}
|
|
368
308
|
/** Every axis is pinned, so only the box's size is read. */
|
|
369
309
|
place(box) {
|
|
@@ -401,6 +341,47 @@ function pinOf(region, lo, hi) {
|
|
|
401
341
|
}
|
|
402
342
|
}
|
|
403
343
|
//#endregion
|
|
344
|
+
//#region src/ui/overlay/box.ts
|
|
345
|
+
var WindowBox = class {
|
|
346
|
+
get x() {
|
|
347
|
+
return 0;
|
|
348
|
+
}
|
|
349
|
+
get y() {
|
|
350
|
+
return 0;
|
|
351
|
+
}
|
|
352
|
+
get w() {
|
|
353
|
+
return windowSize.width();
|
|
354
|
+
}
|
|
355
|
+
get h() {
|
|
356
|
+
return windowSize.height();
|
|
357
|
+
}
|
|
358
|
+
get direction() {
|
|
359
|
+
return direction();
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
const WINDOW_BOX = new WindowBox();
|
|
363
|
+
var ElementBox = class {
|
|
364
|
+
#rect;
|
|
365
|
+
constructor(el) {
|
|
366
|
+
this.#rect = createElementRect(el);
|
|
367
|
+
}
|
|
368
|
+
[Symbol.dispose]() {
|
|
369
|
+
this.#rect[Symbol.dispose]();
|
|
370
|
+
}
|
|
371
|
+
get x() {
|
|
372
|
+
return this.#rect().left;
|
|
373
|
+
}
|
|
374
|
+
get y() {
|
|
375
|
+
return this.#rect().top;
|
|
376
|
+
}
|
|
377
|
+
get w() {
|
|
378
|
+
return this.#rect().width;
|
|
379
|
+
}
|
|
380
|
+
get h() {
|
|
381
|
+
return this.#rect().height;
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
//#endregion
|
|
404
385
|
//#region src/ui/overlay/overlay.ts
|
|
405
386
|
var __create = Object.create;
|
|
406
387
|
var __defProp = Object.defineProperty;
|
|
@@ -560,16 +541,27 @@ var Displacement = class extends PartialBox {
|
|
|
560
541
|
});
|
|
561
542
|
}
|
|
562
543
|
};
|
|
544
|
+
const OFFSET = {
|
|
545
|
+
left: "0%",
|
|
546
|
+
top: "0%",
|
|
547
|
+
center: "50%",
|
|
548
|
+
right: "100%",
|
|
549
|
+
bottom: "100%"
|
|
550
|
+
};
|
|
563
551
|
var OverlayBox = class extends TransformableBox {
|
|
564
552
|
element;
|
|
565
553
|
#rect;
|
|
554
|
+
#origin = {
|
|
555
|
+
x: "left",
|
|
556
|
+
y: "top"
|
|
557
|
+
};
|
|
566
558
|
constructor(element) {
|
|
567
559
|
super();
|
|
568
560
|
this.element = element;
|
|
569
561
|
this.#rect = createElementRect(element);
|
|
570
562
|
element.style.setProperty("top", "0");
|
|
571
563
|
element.style.setProperty("left", "0");
|
|
572
|
-
element.style.setProperty("translate", "calc(var(--x, 0px) + var(--dx, 0px) + var(--_ex, 0px)) calc(var(--y, 0px) + var(--dy, 0px) + var(--_ey, 0px))");
|
|
564
|
+
element.style.setProperty("translate", "calc(var(--x, 0px) + var(--dx, 0px) + var(--_ex, 0px) - var(--_ox, 0%)) calc(var(--y, 0px) + var(--dy, 0px) + var(--_ey, 0px) - var(--_oy, 0%))");
|
|
573
565
|
const [, stop] = scope(() => {
|
|
574
566
|
effect(() => {
|
|
575
567
|
this.#project("--x", this.transform.x);
|
|
@@ -595,6 +587,19 @@ var OverlayBox = class extends TransformableBox {
|
|
|
595
587
|
this.#rect[Symbol.dispose]();
|
|
596
588
|
};
|
|
597
589
|
}
|
|
590
|
+
/** The box point that lands on (x, y), and the scale's origin. */
|
|
591
|
+
get origin() {
|
|
592
|
+
return this.#origin;
|
|
593
|
+
}
|
|
594
|
+
set origin({ x, y }) {
|
|
595
|
+
this.#origin = {
|
|
596
|
+
x,
|
|
597
|
+
y
|
|
598
|
+
};
|
|
599
|
+
this.element.style.setProperty("--_ox", OFFSET[x]);
|
|
600
|
+
this.element.style.setProperty("--_oy", OFFSET[y]);
|
|
601
|
+
this.element.style.transformOrigin = `${x} ${y}`;
|
|
602
|
+
}
|
|
598
603
|
/** Write a size channel, or unset it when the axis is AUTO (NaN) so the
|
|
599
604
|
* element falls back to content sizing (`var(--w, auto)`). */
|
|
600
605
|
#project(name, ...value) {
|
|
@@ -2,19 +2,14 @@ import { r as MaybeReactive, t as Computed } from "../index-BSAqa0-0.mjs";
|
|
|
2
2
|
|
|
3
3
|
//#region src/utilities/element-rect.d.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* `target`'s bounding rect as one reactive `DOMRect`, every field from the
|
|
6
|
+
* same instant. Refreshed by a `ResizeObserver` (size) and capture-phase
|
|
7
|
+
* `scroll` / window `resize` (position), never on read. Size is the observer's
|
|
8
|
+
* border box, not the rect's: a transform scales the rect and never fires the
|
|
9
|
+
* observer.
|
|
10
10
|
*
|
|
11
|
-
* `target`
|
|
12
|
-
*
|
|
13
|
-
* keeps its identity across a swap, so consumers never rebind.
|
|
14
|
-
*
|
|
15
|
-
* The value is CACHED, not measured per read: it refreshes when one of the
|
|
16
|
-
* sources above fires, not at the moment you read it. Dispose explicitly, or
|
|
17
|
-
* let the enclosing scope do it.
|
|
11
|
+
* A reactive `target` is followed, keeping the computed's identity. Dispose
|
|
12
|
+
* explicitly, or let the enclosing scope do it.
|
|
18
13
|
*/
|
|
19
14
|
declare function createElementRect(target: MaybeReactive<Element>): Computed<DOMRect> & Disposable;
|
|
20
15
|
//#endregion
|
|
@@ -3,30 +3,38 @@ import { resolve } from "../signals/index.mjs";
|
|
|
3
3
|
import { createResizeObserver } from "./resize-observer.mjs";
|
|
4
4
|
//#region src/utilities/element-rect.ts
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* `target`'s bounding rect as one reactive `DOMRect`, every field from the
|
|
7
|
+
* same instant. Refreshed by a `ResizeObserver` (size) and capture-phase
|
|
8
|
+
* `scroll` / window `resize` (position), never on read. Size is the observer's
|
|
9
|
+
* border box, not the rect's: a transform scales the rect and never fires the
|
|
10
|
+
* observer.
|
|
11
11
|
*
|
|
12
|
-
* `target`
|
|
13
|
-
*
|
|
14
|
-
* keeps its identity across a swap, so consumers never rebind.
|
|
15
|
-
*
|
|
16
|
-
* The value is CACHED, not measured per read: it refreshes when one of the
|
|
17
|
-
* sources above fires, not at the moment you read it. Dispose explicitly, or
|
|
18
|
-
* let the enclosing scope do it.
|
|
12
|
+
* A reactive `target` is followed, keeping the computed's identity. Dispose
|
|
13
|
+
* explicitly, or let the enclosing scope do it.
|
|
19
14
|
*/
|
|
20
15
|
function createElementRect(target) {
|
|
21
|
-
|
|
16
|
+
let size;
|
|
17
|
+
const read = (el) => {
|
|
18
|
+
const r = el.getBoundingClientRect();
|
|
19
|
+
return size ? new DOMRect(r.x, r.y, size.width, size.height) : r;
|
|
20
|
+
};
|
|
21
|
+
const cache = signal(read(resolve(target)));
|
|
22
22
|
const updateRect = (el) => {
|
|
23
|
-
cache(el
|
|
23
|
+
cache(read(el));
|
|
24
24
|
};
|
|
25
25
|
const stop = effectScope(() => {
|
|
26
26
|
effect(() => {
|
|
27
27
|
const el = resolve(target);
|
|
28
|
+
size = void 0;
|
|
28
29
|
createResizeObserver(el, (entries) => {
|
|
29
|
-
for (const entry of entries)
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const box = entry.borderBoxSize?.[0];
|
|
32
|
+
if (box) size = {
|
|
33
|
+
width: box.inlineSize,
|
|
34
|
+
height: box.blockSize
|
|
35
|
+
};
|
|
36
|
+
updateRect(entry.target);
|
|
37
|
+
}
|
|
30
38
|
});
|
|
31
39
|
const remeasure = () => updateRect(el);
|
|
32
40
|
window.addEventListener("scroll", remeasure, {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elements-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.27.
|
|
4
|
+
"version": "0.27.11",
|
|
5
5
|
"description": "A lightweight reactive UI library that transforms native HTMLElements into reactive components with signals. Ideal for framework-agnostic applications and web components.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"webcomponents",
|