@fusion.dev/helix-core 0.24.0 → 0.24.1

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.
@@ -1473,15 +1473,36 @@
1473
1473
  "text": "MutationObserver | undefined"
1474
1474
  }
1475
1475
  },
1476
+ {
1477
+ "kind": "field",
1478
+ "name": "#deferred",
1479
+ "privacy": "private",
1480
+ "type": {
1481
+ "text": "boolean"
1482
+ },
1483
+ "default": "false",
1484
+ "description": "Whether a hydrating render was told there was nothing, and needs the render after."
1485
+ },
1476
1486
  {
1477
1487
  "kind": "field",
1478
1488
  "name": "element",
1479
1489
  "type": {
1480
1490
  "text": "Element | null"
1481
1491
  },
1482
- "description": "The element `for` names, or null where there is nothing to name it in.\n\nNull on the server as well, since resolving an id wants a document. Every\nchart inherits that: the table is served whole and the drawing arrives on\nhydration.",
1492
+ "description": "The element `for` names, or null where there is nothing to name it in.\n\nNull on the server as well, since resolving an id wants a document. Every\nchart inherits that: the table is served whole and the drawing arrives on\nhydration.\n\n**And null while hydrating what a server sent**, which drew nothing, because\nthe render that hydrates has to be the server's: a drawing that differs is\na template Lit throws on. The update after it, which this asks for, draws.",
1483
1493
  "readonly": true
1484
1494
  },
1495
+ {
1496
+ "kind": "method",
1497
+ "name": "#resolve",
1498
+ "privacy": "private",
1499
+ "return": {
1500
+ "type": {
1501
+ "text": "Element | null"
1502
+ }
1503
+ },
1504
+ "description": "The element `for` names, whatever the host is rendering.\n\nApart from `element` because the watcher needs the table while a render\ncannot have it: attached on connect, which on a server's page is before\nthe render that hydrates, it resolved nothing there and never watched, so a\ntable a page filled afterwards drew no line."
1505
+ },
1485
1506
  {
1486
1507
  "kind": "field",
1487
1508
  "name": "series",
@@ -1500,6 +1521,15 @@
1500
1521
  }
1501
1522
  }
1502
1523
  },
1524
+ {
1525
+ "kind": "method",
1526
+ "name": "hostUpdated",
1527
+ "return": {
1528
+ "type": {
1529
+ "text": "void"
1530
+ }
1531
+ }
1532
+ },
1503
1533
  {
1504
1534
  "kind": "method",
1505
1535
  "name": "hostDisconnected",
@@ -3412,6 +3442,16 @@
3412
3442
  "description": "Whether this update is hydrating a server's markup, and so has to render\nexactly what the server rendered.\n\n**Lit hydrates by assuming the markup already shows the first render.** A\nvalue that differs is recorded and never written, so the page keeps the\nserver's, and a template that differs throws. The server has no children,\nso anything a component reads from its children waits for the update after\nhydration, which `finishHydration` asks for. Without a server's markup the\nfirst render reads them and there is one render.",
3413
3443
  "readonly": true
3414
3444
  },
3445
+ {
3446
+ "kind": "field",
3447
+ "name": "serverRendered",
3448
+ "type": {
3449
+ "text": "boolean"
3450
+ },
3451
+ "privacy": "protected",
3452
+ "description": "Whether this element hydrated a server's markup rather than rendering its own.\n\nFor what happened before hydration and cannot be heard after it: an image\nthe parser fetched fires `load` or `error` before any listener exists, so a\ncomponent asks the image instead, once, when this is true.",
3453
+ "readonly": true
3454
+ },
3415
3455
  {
3416
3456
  "kind": "method",
3417
3457
  "name": "finishHydration",
@@ -3546,6 +3586,30 @@
3546
3586
  "tier": "core"
3547
3587
  },
3548
3588
  "customElement": true
3589
+ },
3590
+ {
3591
+ "kind": "function",
3592
+ "name": "whenHydrated",
3593
+ "return": {
3594
+ "type": {
3595
+ "text": "void"
3596
+ }
3597
+ },
3598
+ "parameters": [
3599
+ {
3600
+ "name": "element",
3601
+ "type": {
3602
+ "text": "Element"
3603
+ }
3604
+ },
3605
+ {
3606
+ "name": "write",
3607
+ "type": {
3608
+ "text": "() => void"
3609
+ }
3610
+ }
3611
+ ],
3612
+ "description": "Writes to a child element once it has hydrated, or now where it is not\nhydrating.\n\n**For a parent that sets state on the elements it holds.** On a page a server\nrendered, the parent's `updated` can run before a child's own first update,\nand a property written then is in the child's hydrating render, which has to\nbe the server's: a mark the markup never showed, and Lit throws. Waiting for\nthat render lets it match and the write land in the one after. Anywhere else\nthe write is immediate, so a client's first render already has it."
3549
3613
  }
3550
3614
  ],
3551
3615
  "exports": [
@@ -3556,6 +3620,14 @@
3556
3620
  "name": "HelixElement",
3557
3621
  "module": "src/helix-element/helix-element.ts"
3558
3622
  }
3623
+ },
3624
+ {
3625
+ "kind": "js",
3626
+ "name": "whenHydrated",
3627
+ "declaration": {
3628
+ "name": "whenHydrated",
3629
+ "module": "src/helix-element/helix-element.ts"
3630
+ }
3559
3631
  }
3560
3632
  ]
3561
3633
  },
@@ -3798,6 +3870,20 @@
3798
3870
  "module": "src/helix-element/helix-element.ts"
3799
3871
  }
3800
3872
  },
3873
+ {
3874
+ "kind": "field",
3875
+ "name": "serverRendered",
3876
+ "type": {
3877
+ "text": "boolean"
3878
+ },
3879
+ "privacy": "protected",
3880
+ "description": "Whether this element hydrated a server's markup rather than rendering its own.\n\nFor what happened before hydration and cannot be heard after it: an image\nthe parser fetched fires `load` or `error` before any listener exists, so a\ncomponent asks the image instead, once, when this is true.",
3881
+ "readonly": true,
3882
+ "inheritedFrom": {
3883
+ "name": "HelixElement",
3884
+ "module": "src/helix-element/helix-element.ts"
3885
+ }
3886
+ },
3801
3887
  {
3802
3888
  "kind": "method",
3803
3889
  "name": "finishHydration",
@@ -4745,6 +4831,14 @@
4745
4831
  "module": "./helix-element/helix-element.js"
4746
4832
  }
4747
4833
  },
4834
+ {
4835
+ "kind": "js",
4836
+ "name": "whenHydrated",
4837
+ "declaration": {
4838
+ "name": "whenHydrated",
4839
+ "module": "./helix-element/helix-element.js"
4840
+ }
4841
+ },
4748
4842
  {
4749
4843
  "kind": "js",
4750
4844
  "name": "HelixFormElement",
@@ -36,11 +36,16 @@ export declare class SourceController implements ReactiveController {
36
36
  * Null on the server as well, since resolving an id wants a document. Every
37
37
  * chart inherits that: the table is served whole and the drawing arrives on
38
38
  * hydration.
39
+ *
40
+ * **And null while hydrating what a server sent**, which drew nothing, because
41
+ * the render that hydrates has to be the server's: a drawing that differs is
42
+ * a template Lit throws on. The update after it, which this asks for, draws.
39
43
  */
40
44
  get element(): Element | null;
41
45
  /** The series it holds, or none. */
42
46
  get series(): Series[];
43
47
  hostConnected(): void;
48
+ hostUpdated(): void;
44
49
  hostDisconnected(): void;
45
50
  /**
46
51
  * Points the watcher at whatever `for` names now.
@@ -2,11 +2,19 @@ import { readSeries } from '../../utils/read-series/read-series.js';
2
2
  export class SourceController {
3
3
  #host;
4
4
  #observer;
5
+ #deferred = false;
5
6
  constructor(host) {
6
7
  this.#host = host;
7
8
  host.addController(this);
8
9
  }
9
10
  get element() {
11
+ if (this.#host.hydrating === true) {
12
+ this.#deferred = this.#host.for !== '';
13
+ return null;
14
+ }
15
+ return this.#resolve();
16
+ }
17
+ #resolve() {
10
18
  const host = this.#host;
11
19
  if (host.for === '') {
12
20
  return null;
@@ -31,13 +39,19 @@ export class SourceController {
31
39
  hostConnected() {
32
40
  this.watch();
33
41
  }
42
+ hostUpdated() {
43
+ if (this.#deferred) {
44
+ this.#deferred = false;
45
+ this.#host.requestUpdate();
46
+ }
47
+ }
34
48
  hostDisconnected() {
35
49
  this.#observer?.disconnect();
36
50
  this.#observer = undefined;
37
51
  }
38
52
  watch() {
39
53
  this.#observer?.disconnect();
40
- const element = this.element;
54
+ const element = this.#resolve();
41
55
  if (!element || typeof MutationObserver === 'undefined') {
42
56
  return;
43
57
  }
@@ -134,6 +134,14 @@ export declare class HelixElement extends LitElement {
134
134
  * first render reads them and there is one render.
135
135
  */
136
136
  protected get hydrating(): boolean;
137
+ /**
138
+ * Whether this element hydrated a server's markup rather than rendering its own.
139
+ *
140
+ * For what happened before hydration and cannot be heard after it: an image
141
+ * the parser fetched fires `load` or `error` before any listener exists, so a
142
+ * component asks the image instead, once, when this is true.
143
+ */
144
+ protected get serverRendered(): boolean;
137
145
  /**
138
146
  * Asks for the update a hydration put off, so the reads it skipped happen.
139
147
  *
@@ -249,3 +257,15 @@ export declare class HelixElement extends LitElement {
249
257
  */
250
258
  protected firstUpdated(changed: PropertyValues): void;
251
259
  }
260
+ /**
261
+ * Writes to a child element once it has hydrated, or now where it is not
262
+ * hydrating.
263
+ *
264
+ * **For a parent that sets state on the elements it holds.** On a page a server
265
+ * rendered, the parent's `updated` can run before a child's own first update,
266
+ * and a property written then is in the child's hydrating render, which has to
267
+ * be the server's: a mark the markup never showed, and Lit throws. Waiting for
268
+ * that render lets it match and the write land in the one after. Anywhere else
269
+ * the write is immediate, so a client's first render already has it.
270
+ */
271
+ export declare const whenHydrated: (element: Element, write: () => void) => void;
@@ -148,6 +148,9 @@ export class HelixElement extends LitElement {
148
148
  get hydrating() {
149
149
  return this.fromServer && !this.hasUpdated;
150
150
  }
151
+ get serverRendered() {
152
+ return this.fromServer;
153
+ }
151
154
  finishHydration() {
152
155
  if (this.fromServer) {
153
156
  this.requestUpdate();
@@ -205,3 +208,12 @@ export class HelixElement extends LitElement {
205
208
  });
206
209
  }
207
210
  }
211
+ export const whenHydrated = (element, write) => {
212
+ const child = element;
213
+ if (child.hydrating === true && child.updateComplete) {
214
+ void child.updateComplete.then(write);
215
+ }
216
+ else {
217
+ write();
218
+ }
219
+ };
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { type TokenColor, TokenColorController, } from './controllers/token-colo
15
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 FacetDetail, type FilterDetail, HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCaretEvent, HelixCompleteEvent, HelixConsoleEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixFacetEvent, HelixFilterEvent, HelixHistoryEvent, HelixNavigateEvent, HelixNextEvent, HelixPreviousEvent, HelixReadEvent, HelixReorderEvent, 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
- export { HelixElement } from './helix-element/helix-element.js';
18
+ export { HelixElement, whenHydrated } from './helix-element/helix-element.js';
19
19
  export { HelixFormElement } from './helix-form-element/helix-form-element.js';
20
20
  export { MixinChartSource, type MixinChartSourceInterface, PALETTE, seriesIndex, } from './mixins/mixin-chart-source/mixin-chart-source.js';
21
21
  export { type CollectionElement, MixinCollection, } from './mixins/mixin-collection/mixin-collection.js';
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ export { TokenColorController, } from './controllers/token-color-controller/toke
15
15
  export { VirtualizeController, } from './controllers/virtualize-controller/virtualize-controller.js';
16
16
  export { eventsForTag, registerElementEvents } from './events/element-events.js';
17
17
  export { HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeChangeEvent, HelixBeforeCloseEvent, HelixBeforeCollapseEvent, HelixBeforeEditEvent, HelixBeforeOpenEvent, HelixBeforePanelResizeEvent, HelixBeforePinEvent, HelixBeforeResizeEvent, HelixBeforeSplitEvent, HelixBeforeToggleEvent, HelixCaretEvent, HelixCompleteEvent, HelixConsoleEvent, HelixCopyEvent, HelixCreateEvent, HelixDismissEvent, HelixFacetEvent, HelixFilterEvent, HelixHistoryEvent, HelixNavigateEvent, HelixNextEvent, HelixPreviousEvent, HelixReadEvent, HelixReorderEvent, HelixResizeEvent, HelixSampleEndEvent, HelixSampleStartEvent, HelixScrolledEvent, HelixSelectEvent, HelixSendEvent, HelixShortcutEvent, HelixSortEvent, HelixTourAskEvent, } from './events/events.js';
18
- export { HelixElement } from './helix-element/helix-element.js';
18
+ export { HelixElement, whenHydrated } from './helix-element/helix-element.js';
19
19
  export { HelixFormElement } from './helix-form-element/helix-form-element.js';
20
20
  export { MixinChartSource, PALETTE, seriesIndex, } from './mixins/mixin-chart-source/mixin-chart-source.js';
21
21
  export { MixinCollection, } from './mixins/mixin-collection/mixin-collection.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.24.0",
4
+ "version": "0.24.1",
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.24.0"
37
+ "@fusion.dev/helix-icons": "0.24.1"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@custom-elements-manifest/analyzer": "^0.11.0",
41
- "@fusion.dev/helix-cem": "0.24.0",
42
- "@fusion.dev/helix-testing": "0.24.0",
41
+ "@fusion.dev/helix-cem": "0.24.1",
42
+ "@fusion.dev/helix-testing": "0.24.1",
43
43
  "lit": "^3.2.1"
44
44
  },
45
45
  "homepage": "https://fusion.dev",