@fusion.dev/helix-core 0.160.0 → 0.161.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/custom-elements.json +48 -4
- package/dist/controllers/virtualize-controller/virtualize-controller.d.ts +22 -0
- package/dist/controllers/virtualize-controller/virtualize-controller.js +22 -5
- package/dist/events/details.d.ts +6 -0
- package/dist/mixins/mixin-controller-active/mixin-controller-active.d.ts +6 -2
- package/dist/mixins/mixin-controller-active/mixin-controller-active.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/custom-elements.json
CHANGED
|
@@ -5977,6 +5977,25 @@
|
|
|
5977
5977
|
},
|
|
5978
5978
|
"description": "Whether the reader is scrolling: a finger is on the box, the box moved\nwithin the last 150 milliseconds, or it has moved and its `scroll` event\nhas not arrived yet.\n\nFor a host that holds its own reader: a write to the scroll offset while\nthis is true ends a fling on iOS, and a reader position noted before the\nlast move is out of date."
|
|
5979
5979
|
},
|
|
5980
|
+
{
|
|
5981
|
+
"kind": "method",
|
|
5982
|
+
"name": "noteClamp",
|
|
5983
|
+
"privacy": "private",
|
|
5984
|
+
"return": {
|
|
5985
|
+
"type": {
|
|
5986
|
+
"text": "number"
|
|
5987
|
+
}
|
|
5988
|
+
},
|
|
5989
|
+
"parameters": [
|
|
5990
|
+
{
|
|
5991
|
+
"name": "box",
|
|
5992
|
+
"type": {
|
|
5993
|
+
"text": "HTMLElement"
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
],
|
|
5997
|
+
"description": "Takes the offset as the box's own where the box moved it up only because\nthe set below it got shorter, which the browser does to keep the offset\ninside the content, and answers where it was before.\n\n**Not a reader scrolling.** Rows at the end of the set measured shorter\nthan their estimates shrink the content, and the box pulls its offset back\nto the new bottom before any `scroll` event arrives. Read as a scroll, the\ndifference went into the spacer as drift and was then paid a second time:\nin Chromium, End on 2,000 rows of one to five lines left the window 292\npixels above the last item, which stayed drawn below the box as the row\nholding focus."
|
|
5998
|
+
},
|
|
5980
5999
|
{
|
|
5981
6000
|
"kind": "field",
|
|
5982
6001
|
"name": "rest",
|
|
@@ -6091,6 +6110,17 @@
|
|
|
6091
6110
|
},
|
|
6092
6111
|
"description": "How tall one item is on the straight line: the drawn rows' height once\nread, and `estimate` until then.\n\n**An estimate that is wrong on the straight line leaves the end of the\nset out of reach.** Rows of 21 pixels placed at 32 fill two thirds of the\nroom they are counted for, so the window stops short of the bottom of the\nbox and the spacer after it holds the rest: in Chromium, `scrollToIndex`\non the last of 5,000 such rows scrolled to the end and drew nothing there.\nReading the drawn rows once corrects the slope, and it is still a line."
|
|
6093
6112
|
},
|
|
6113
|
+
{
|
|
6114
|
+
"kind": "method",
|
|
6115
|
+
"name": "gap",
|
|
6116
|
+
"privacy": "private",
|
|
6117
|
+
"return": {
|
|
6118
|
+
"type": {
|
|
6119
|
+
"text": "number"
|
|
6120
|
+
}
|
|
6121
|
+
},
|
|
6122
|
+
"description": "The space the host draws between two items, which each item counts."
|
|
6123
|
+
},
|
|
6094
6124
|
{
|
|
6095
6125
|
"kind": "method",
|
|
6096
6126
|
"name": "sampleRows",
|
|
@@ -18483,9 +18513,16 @@
|
|
|
18483
18513
|
"type": {
|
|
18484
18514
|
"text": "string"
|
|
18485
18515
|
}
|
|
18516
|
+
},
|
|
18517
|
+
{
|
|
18518
|
+
"name": "cause",
|
|
18519
|
+
"optional": true,
|
|
18520
|
+
"type": {
|
|
18521
|
+
"text": "string"
|
|
18522
|
+
}
|
|
18486
18523
|
}
|
|
18487
18524
|
],
|
|
18488
|
-
"description": "Requests a new current item, and returns whether the change was applied."
|
|
18525
|
+
"description": "Requests a new current item, and returns whether the change was applied.\n`cause` says why, where the family names its causes, and reaches\n`helix-before-activate` as `detail.cause`."
|
|
18489
18526
|
},
|
|
18490
18527
|
{
|
|
18491
18528
|
"kind": "method",
|
|
@@ -18557,9 +18594,16 @@
|
|
|
18557
18594
|
"type": {
|
|
18558
18595
|
"text": "string"
|
|
18559
18596
|
}
|
|
18597
|
+
},
|
|
18598
|
+
{
|
|
18599
|
+
"name": "cause",
|
|
18600
|
+
"optional": true,
|
|
18601
|
+
"type": {
|
|
18602
|
+
"text": "string"
|
|
18603
|
+
}
|
|
18560
18604
|
}
|
|
18561
18605
|
],
|
|
18562
|
-
"description": "Requests a new current item, and returns whether the change was applied.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-activate` is\na refusal and nothing moves. Unlike a native control, nothing has moved\nby the time this runs, so refusing is simply not writing: there is\nnothing to put back. Nobody refusing means the set updates itself,\nwhether or not a consumer declared `active`, a declared property being a\nseed and a correction."
|
|
18606
|
+
"description": "Requests a new current item, and returns whether the change was applied.\n\nAnnounces before it acts, so `preventDefault()` on the `helix-before-activate` is\na refusal and nothing moves. Unlike a native control, nothing has moved\nby the time this runs, so refusing is simply not writing: there is\nnothing to put back. Nobody refusing means the set updates itself,\nwhether or not a consumer declared `active`, a declared property being a\nseed and a correction. `cause` says why, where the family names its\ncauses, and reaches the event as `detail.cause`."
|
|
18563
18607
|
},
|
|
18564
18608
|
{
|
|
18565
18609
|
"kind": "method",
|
|
@@ -32859,7 +32903,7 @@
|
|
|
32859
32903
|
"type": {
|
|
32860
32904
|
"text": "string"
|
|
32861
32905
|
},
|
|
32862
|
-
"default": "'0.
|
|
32906
|
+
"default": "'0.161.0'",
|
|
32863
32907
|
"description": "The version of the package this file ships in.\n\n**Written by `fusion/scripts/version.mjs`** wherever it writes the package's\n`package.json`, and stamped back into the repository beside it after a\nrelease, so the two never disagree; a spec beside this holds them to it.\nNothing else in the running code knows which release it is."
|
|
32864
32908
|
}
|
|
32865
32909
|
],
|
|
@@ -33419,6 +33463,6 @@
|
|
|
33419
33463
|
],
|
|
33420
33464
|
"helix": {
|
|
33421
33465
|
"package": "@fusion.dev/helix-core",
|
|
33422
|
-
"version": "0.
|
|
33466
|
+
"version": "0.161.0"
|
|
33423
33467
|
}
|
|
33424
33468
|
}
|
|
@@ -7,6 +7,12 @@ export interface VirtualizeOptions {
|
|
|
7
7
|
count: () => number;
|
|
8
8
|
/** How tall one item is along the scroll axis, in pixels. */
|
|
9
9
|
estimate: () => number;
|
|
10
|
+
/**
|
|
11
|
+
* The space between two items along the scroll axis, in pixels, which the
|
|
12
|
+
* host draws, such as a flex or grid `gap`. Each item counts it as part of
|
|
13
|
+
* its own size. Zero by default.
|
|
14
|
+
*/
|
|
15
|
+
gap?: () => number;
|
|
10
16
|
/**
|
|
11
17
|
* Rows kept either side of what fits, so a scroll reveals something drawn
|
|
12
18
|
* rather than something blank. Four by default.
|
|
@@ -213,6 +219,20 @@ export declare class VirtualizeController implements ReactiveController {
|
|
|
213
219
|
* last move is out of date.
|
|
214
220
|
*/
|
|
215
221
|
scrolling(): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Takes the offset as the box's own where the box moved it up only because
|
|
224
|
+
* the set below it got shorter, which the browser does to keep the offset
|
|
225
|
+
* inside the content, and answers where it was before.
|
|
226
|
+
*
|
|
227
|
+
* **Not a reader scrolling.** Rows at the end of the set measured shorter
|
|
228
|
+
* than their estimates shrink the content, and the box pulls its offset back
|
|
229
|
+
* to the new bottom before any `scroll` event arrives. Read as a scroll, the
|
|
230
|
+
* difference went into the spacer as drift and was then paid a second time:
|
|
231
|
+
* in Chromium, End on 2,000 rows of one to five lines left the window 292
|
|
232
|
+
* pixels above the last item, which stayed drawn below the box as the row
|
|
233
|
+
* holding focus.
|
|
234
|
+
*/
|
|
235
|
+
private noteClamp;
|
|
216
236
|
/** Squares the spacer and the scroll offset once the box is still. */
|
|
217
237
|
private readonly rest;
|
|
218
238
|
/**
|
|
@@ -264,6 +284,8 @@ export declare class VirtualizeController implements ReactiveController {
|
|
|
264
284
|
* Reading the drawn rows once corrects the slope, and it is still a line.
|
|
265
285
|
*/
|
|
266
286
|
private line;
|
|
287
|
+
/** The space the host draws between two items, which each item counts. */
|
|
288
|
+
private gap;
|
|
267
289
|
/**
|
|
268
290
|
* Reads the drawn rows' height once for the straight line, for a host that
|
|
269
291
|
* offers `rows` and does not measure.
|
|
@@ -17,7 +17,11 @@ export class VirtualizeController {
|
|
|
17
17
|
this.touching = false;
|
|
18
18
|
this.uneven = false;
|
|
19
19
|
this.handleScroll = () => {
|
|
20
|
-
const
|
|
20
|
+
const box = this.options.container();
|
|
21
|
+
if (box) {
|
|
22
|
+
this.noteClamp(box);
|
|
23
|
+
}
|
|
24
|
+
const top = box?.scrollTop ?? 0;
|
|
21
25
|
if (top !== this.lastTop) {
|
|
22
26
|
this.heading = top > this.lastTop ? 1 : -1;
|
|
23
27
|
this.lastTop = top;
|
|
@@ -95,6 +99,15 @@ export class VirtualizeController {
|
|
|
95
99
|
this.resting !== undefined ||
|
|
96
100
|
(this.options.container()?.scrollTop ?? this.lastTop) !== this.lastTop);
|
|
97
101
|
}
|
|
102
|
+
noteClamp(box) {
|
|
103
|
+
const was = this.lastTop;
|
|
104
|
+
if (!this.touching &&
|
|
105
|
+
box.scrollTop < was &&
|
|
106
|
+
box.scrollTop >= box.scrollHeight - box.clientHeight - 1) {
|
|
107
|
+
this.lastTop = box.scrollTop;
|
|
108
|
+
}
|
|
109
|
+
return was;
|
|
110
|
+
}
|
|
98
111
|
square() {
|
|
99
112
|
const box = this.options.container();
|
|
100
113
|
if (this.drift > 0 && box) {
|
|
@@ -161,7 +174,10 @@ export class VirtualizeController {
|
|
|
161
174
|
}
|
|
162
175
|
line() {
|
|
163
176
|
const estimate = Math.max(1, this.options.estimate());
|
|
164
|
-
return this.sample?.estimate === estimate ? this.sample.size : estimate;
|
|
177
|
+
return this.sample?.estimate === estimate ? this.sample.size : estimate + this.gap();
|
|
178
|
+
}
|
|
179
|
+
gap() {
|
|
180
|
+
return Math.max(0, this.options.gap?.() ?? 0);
|
|
165
181
|
}
|
|
166
182
|
sampleRows() {
|
|
167
183
|
const estimate = Math.max(1, this.options.estimate());
|
|
@@ -176,7 +192,7 @@ export class VirtualizeController {
|
|
|
176
192
|
const uneven = Math.max(...seen) - Math.min(...seen) > 1;
|
|
177
193
|
if (this.sample?.estimate !== estimate) {
|
|
178
194
|
const was = this.line();
|
|
179
|
-
const size = Math.max(1, seen.reduce((sum, height) => sum + height, 0) / seen.length);
|
|
195
|
+
const size = Math.max(1, seen.reduce((sum, height) => sum + height, 0) / seen.length) + this.gap();
|
|
180
196
|
this.sample = { estimate, size };
|
|
181
197
|
if (Math.abs(size - was) >= 0.5) {
|
|
182
198
|
const box = this.options.container();
|
|
@@ -291,12 +307,13 @@ export class VirtualizeController {
|
|
|
291
307
|
}
|
|
292
308
|
const total = Math.max(0, this.options.count());
|
|
293
309
|
const box = this.options.container();
|
|
310
|
+
const from = box ? this.noteClamp(box) : this.lastTop;
|
|
294
311
|
const top = box ? this.offset(box) : 0;
|
|
295
312
|
const anchor = this.target ?? this.heights.indexAt(top, total);
|
|
296
313
|
const was = this.heights.before(anchor, total);
|
|
297
314
|
let news = false;
|
|
298
315
|
for (const { element, index } of rows) {
|
|
299
|
-
if (this.heights.record(index, element.getBoundingClientRect().height)) {
|
|
316
|
+
if (this.heights.record(index, element.getBoundingClientRect().height + this.gap())) {
|
|
300
317
|
news = true;
|
|
301
318
|
}
|
|
302
319
|
}
|
|
@@ -310,7 +327,7 @@ export class VirtualizeController {
|
|
|
310
327
|
this.drift -= moved;
|
|
311
328
|
}
|
|
312
329
|
else {
|
|
313
|
-
box.scrollTop
|
|
330
|
+
box.scrollTop = from + moved;
|
|
314
331
|
this.lastTop = box.scrollTop;
|
|
315
332
|
}
|
|
316
333
|
}
|
package/dist/events/details.d.ts
CHANGED
|
@@ -258,6 +258,12 @@ export interface TourAskDetail {
|
|
|
258
258
|
* that `event.target` does not.
|
|
259
259
|
*/
|
|
260
260
|
export interface ChangeDetail {
|
|
261
|
+
/**
|
|
262
|
+
* Why the change was asked for, where a family names its causes. Video
|
|
263
|
+
* Playlist sends `ended`, `next`, `press`, `previous`, and `removed` on
|
|
264
|
+
* `helix-before-activate`.
|
|
265
|
+
*/
|
|
266
|
+
cause?: string;
|
|
261
267
|
/** The value after the change. */
|
|
262
268
|
value: string;
|
|
263
269
|
}
|
|
@@ -21,8 +21,12 @@ export declare class MixinControllerActiveInterface {
|
|
|
21
21
|
* is written.
|
|
22
22
|
*/
|
|
23
23
|
defaultActive: string;
|
|
24
|
-
/**
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Requests a new current item, and returns whether the change was applied.
|
|
26
|
+
* `cause` says why, where the family names its causes, and reaches
|
|
27
|
+
* `helix-before-activate` as `detail.cause`.
|
|
28
|
+
*/
|
|
29
|
+
requestActive(next: string, cause?: string): boolean;
|
|
26
30
|
/**
|
|
27
31
|
* Which item is current, given what there is to choose from.
|
|
28
32
|
*
|
|
@@ -23,7 +23,7 @@ export const MixinControllerActive = (Base) => {
|
|
|
23
23
|
this.activeState = next;
|
|
24
24
|
this.requestUpdate('active', previous);
|
|
25
25
|
}
|
|
26
|
-
requestActive(next) {
|
|
26
|
+
requestActive(next, cause) {
|
|
27
27
|
if (next === this.active) {
|
|
28
28
|
return true;
|
|
29
29
|
}
|
|
@@ -34,7 +34,7 @@ export const MixinControllerActive = (Base) => {
|
|
|
34
34
|
this.activeState = value;
|
|
35
35
|
this.requestUpdate('active', previous);
|
|
36
36
|
},
|
|
37
|
-
event: (value) => new HelixBeforeActivateEvent({ value }),
|
|
37
|
+
event: (value) => new HelixBeforeActivateEvent(cause === undefined ? { value } : { cause, value }),
|
|
38
38
|
host: this,
|
|
39
39
|
next,
|
|
40
40
|
});
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.161.0';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-core",
|
|
3
3
|
"description": "Helix element primitives: base classes, mixins, decorators, utilities.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.161.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@floating-ui/dom": "^1.8.0",
|
|
59
|
-
"@fusion.dev/helix-icons": "0.
|
|
59
|
+
"@fusion.dev/helix-icons": "0.161.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@fusion.dev/helix-cem": "0.
|
|
63
|
-
"@fusion.dev/helix-testing": "0.
|
|
62
|
+
"@fusion.dev/helix-cem": "0.161.0",
|
|
63
|
+
"@fusion.dev/helix-testing": "0.161.0",
|
|
64
64
|
"@lit-labs/ssr": "^4.1.0",
|
|
65
65
|
"lit": "^3.2.1"
|
|
66
66
|
},
|