@fusion.dev/helix-core 0.5.0 → 0.7.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.
@@ -2033,7 +2033,18 @@
2033
2033
  },
2034
2034
  {
2035
2035
  "kind": "method",
2036
- "name": "measured",
2036
+ "name": "measuring",
2037
+ "privacy": "private",
2038
+ "return": {
2039
+ "type": {
2040
+ "text": "boolean"
2041
+ }
2042
+ },
2043
+ "description": "Whether this pass places by measurement: offered, and wanted."
2044
+ },
2045
+ {
2046
+ "kind": "method",
2047
+ "name": "placed",
2037
2048
  "privacy": "private",
2038
2049
  "return": {
2039
2050
  "type": {
@@ -3902,6 +3913,14 @@
3902
3913
  "module": "./controllers/token-color-controller/token-color-controller.js"
3903
3914
  }
3904
3915
  },
3916
+ {
3917
+ "kind": "js",
3918
+ "name": "Rendered",
3919
+ "declaration": {
3920
+ "name": "Rendered",
3921
+ "module": "./controllers/virtualize-controller/virtualize-controller.js"
3922
+ }
3923
+ },
3905
3924
  {
3906
3925
  "kind": "js",
3907
3926
  "name": "VirtualizeController",
@@ -22,11 +22,35 @@ export interface VirtualizeOptions {
22
22
  * came to; a host that returns nothing gets every item at `estimate`, which
23
23
  * is right whenever the rows really are uniform and is cheaper.
24
24
  *
25
- * The first element returned is `window.first`. Order is the only thing
26
- * connecting an element to an index, since the controller cannot ask a row
27
- * which item it drew.
25
+ * **Each row carries its own index rather than being counted off from
26
+ * `window.first`.** A host is free to place its rows whenever it likes, and
27
+ * `hostUpdated` runs *before* `updated`, so a host that appends there has the
28
+ * previous window's rows in the tree when this is asked. Counting positionally
29
+ * would then record the heights of the right elements against the wrong
30
+ * items, and be silently wrong exactly when the window moved.
28
31
  */
29
- rows?: () => Iterable<HTMLElement>;
32
+ rows?: () => Iterable<Rendered>;
33
+ /**
34
+ * Whether to place by measurement on this pass, for a host that can be told.
35
+ *
36
+ * **Separate from `rows` because the two answer different questions**: `rows`
37
+ * says a host is able to report what it drew, and this says it wants the
38
+ * measured placement today. A host with a `measured` attribute needs to
39
+ * change its mind at runtime, and a controller is constructed once.
40
+ *
41
+ * True by default, so a host that supplies `rows` and nothing else measures.
42
+ * The uniform path is kept for the case it is better at: it converts offset
43
+ * to index by division, where the measured one builds prefix sums across the
44
+ * whole set the first time it is asked.
45
+ */
46
+ measured?: () => boolean;
47
+ }
48
+ /** A row that has been drawn, and which item of the set it drew. */
49
+ export interface Rendered {
50
+ /** The element, measured along the scroll axis. */
51
+ element: HTMLElement;
52
+ /** Which item it is, in the whole set rather than in the window. */
53
+ index: number;
30
54
  }
31
55
  /** Which slice is rendered, and how much empty space stands in for the rest. */
32
56
  export interface Window {
@@ -130,6 +154,8 @@ export declare class VirtualizeController implements ReactiveController {
130
154
  measure(): void;
131
155
  /** The straight line: one estimate, so offset and index convert by division. */
132
156
  private uniform;
157
+ /** Whether this pass places by measurement: offered, and wanted. */
158
+ private measuring;
133
159
  /**
134
160
  * The measured version, which asks where each item starts rather than dividing.
135
161
  *
@@ -137,7 +163,7 @@ export declare class VirtualizeController implements ReactiveController {
137
163
  * because it stops at the bottom of the viewport: it is bounded by what fits
138
164
  * on screen plus the overscan, whatever the set's length.
139
165
  */
140
- private measured;
166
+ private placed;
141
167
  /**
142
168
  * Measures what was just drawn, and holds the reader still if it moved.
143
169
  *
@@ -47,8 +47,8 @@ export class VirtualizeController {
47
47
  return;
48
48
  }
49
49
  const overscan = this.options.overscan ?? 4;
50
- const next = this.options.rows
51
- ? this.measured(box, total, overscan)
50
+ const next = this.measuring()
51
+ ? this.placed(box, total, overscan)
52
52
  : this.uniform(box, total, size, overscan);
53
53
  if (this.last?.count !== total || this.last.estimate !== size) {
54
54
  this.last = { count: total, estimate: size };
@@ -76,7 +76,10 @@ export class VirtualizeController {
76
76
  const last = Math.min(total, first + fits);
77
77
  return { after: Math.max(0, (total - last) * size), before: first * size, first, last };
78
78
  }
79
- measured(box, total, overscan) {
79
+ measuring() {
80
+ return this.options.rows !== undefined && (this.options.measured?.() ?? true);
81
+ }
82
+ placed(box, total, overscan) {
80
83
  const first = Math.max(0, this.heights.indexAt(box.scrollTop, total) - overscan);
81
84
  const bottom = box.scrollTop + box.clientHeight;
82
85
  let last = this.heights.indexAt(box.scrollTop, total);
@@ -92,6 +95,9 @@ export class VirtualizeController {
92
95
  };
93
96
  }
94
97
  hostUpdated() {
98
+ if (!this.measuring()) {
99
+ return;
100
+ }
95
101
  const rows = this.options.rows?.();
96
102
  if (!rows) {
97
103
  return;
@@ -99,12 +105,10 @@ export class VirtualizeController {
99
105
  const total = Math.max(0, this.options.count());
100
106
  const was = this.heights.before(this.window.first, total);
101
107
  let news = false;
102
- let index = this.window.first;
103
- for (const row of rows) {
104
- if (this.heights.record(index, row.getBoundingClientRect().height)) {
108
+ for (const { element, index } of rows) {
109
+ if (this.heights.record(index, element.getBoundingClientRect().height)) {
105
110
  news = true;
106
111
  }
107
- index += 1;
108
112
  }
109
113
  if (!news) {
110
114
  return;
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export { KeyboardNavigationController, type KeyboardNavigationOptions, type Navi
12
12
  export { PopoverController, type PopoverOptions, } from './controllers/popover-controller/popover-controller.js';
13
13
  export { SourceController, type SourceHost, } from './controllers/source-controller/source-controller.js';
14
14
  export { type TokenColor, TokenColorController, } from './controllers/token-color-controller/token-color-controller.js';
15
- export { VirtualizeController, type VirtualizeOptions, type Window as VirtualizeWindow, } from './controllers/virtualize-controller/virtualize-controller.js';
15
+ export { type Rendered, VirtualizeController, type VirtualizeOptions, type Window as VirtualizeWindow, } from './controllers/virtualize-controller/virtualize-controller.js';
16
16
  export { eventsForTag, registerElementEvents } from './events/element-events.js';
17
17
  export { type CaretDetail, type ChangeDetail, type CompleteDetail, type ConsoleDetail, type CopyDetail, type CreateDetail, type DismissDetail, type FilterDetail, HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCaretEvent, HelixCompleteEvent, HelixConsoleEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixFilterEvent, HelixNavigateEvent, HelixNextEvent, HelixPreviousEvent, HelixReadEvent, HelixResizeEvent, HelixSampleEndEvent, HelixSampleStartEvent, HelixScrolledEvent, HelixSelectEvent, HelixSendEvent, HelixShortcutEvent, HelixSortEvent, HelixTourAskEvent, type NavigateDetail, type OpenDetail, type ReadDetail, type ResizeDetail, type ScrolledDetail, type SelectDetail, type SendDetail, type ShortcutDetail, type SkipDetail, type SortDetail, type ToggleDetail, } from './events/events.js';
18
18
  export { HelixElement } from './helix-element/helix-element.js';
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.5.0",
4
+ "version": "0.7.0",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -34,12 +34,12 @@
34
34
  "bugs": "https://github.com/project-fusion/fusion/issues",
35
35
  "dependencies": {
36
36
  "@floating-ui/dom": "^1.8.0",
37
- "@fusion.dev/helix-icons": "0.5.0"
37
+ "@fusion.dev/helix-icons": "0.7.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@custom-elements-manifest/analyzer": "^0.11.0",
41
- "@fusion.dev/helix-cem": "0.5.0",
42
- "@fusion.dev/helix-testing": "0.5.0",
41
+ "@fusion.dev/helix-cem": "0.7.0",
42
+ "@fusion.dev/helix-testing": "0.7.0",
43
43
  "lit": "^3.2.1"
44
44
  },
45
45
  "homepage": "https://fusion.dev",