@gears-frontx/react 0.2.0-alpha.0 → 0.2.0-alpha.3
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/CLAUDE.md +30 -10
- package/dist/index.cjs +254 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +169 -10
- package/dist/index.d.ts +169 -10
- package/dist/index.js +192 -82
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +7 -4
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +5 -2
- package/dist/testing.js.map +1 -1
- package/package.json +3 -4
- package/commands/frontx-duplicate-screenset.md +0 -58
- package/commands/frontx-new-component.md +0 -57
- package/commands/frontx-new-mfe.md +0 -153
- package/commands/frontx-new-screen.md +0 -45
- package/commands/frontx-new-screenset.md +0 -57
package/dist/index.d.cts
CHANGED
|
@@ -366,10 +366,9 @@ declare function useApiSuspenseInfiniteQuery<TPage = unknown, TError = Error>(op
|
|
|
366
366
|
/**
|
|
367
367
|
* useApiStream - Declarative SSE streaming hook
|
|
368
368
|
*
|
|
369
|
-
* Accepts a StreamDescriptor from @gears-frontx/api and
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* a manual disconnect function.
|
|
369
|
+
* Accepts a StreamDescriptor from @gears-frontx/api and returns the latest
|
|
370
|
+
* event, accumulated events, connection status, and a manual disconnect
|
|
371
|
+
* function.
|
|
373
372
|
*
|
|
374
373
|
* @example
|
|
375
374
|
* ```tsx
|
|
@@ -395,17 +394,96 @@ interface ApiStreamOptions {
|
|
|
395
394
|
}
|
|
396
395
|
/** Return type of useApiStream. */
|
|
397
396
|
interface ApiStreamResult<TEvent> {
|
|
398
|
-
/** Latest event payload
|
|
397
|
+
/** Latest event payload, set in both modes — `undefined` until the first event and after each connect attempt resets it. */
|
|
399
398
|
data: TEvent | undefined;
|
|
400
399
|
/** All received events when `mode: 'accumulate'`; empty array in `'latest'` mode. */
|
|
401
400
|
events: TEvent[];
|
|
402
401
|
/** Connection lifecycle status. */
|
|
403
402
|
status: StreamStatus;
|
|
404
|
-
/**
|
|
403
|
+
/** Last connect error — set when a connect attempt rejects, cleared when the next attempt starts. */
|
|
405
404
|
error: Error | null;
|
|
406
405
|
/** Manually close the connection. */
|
|
407
406
|
disconnect: () => void;
|
|
408
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Manages the status lifecycle for a single SSE stream connection.
|
|
410
|
+
*
|
|
411
|
+
* **Status values**
|
|
412
|
+
* - `'idle'` — no connection is being attempted. This is the status whenever
|
|
413
|
+
* `enabled` is `false`, including on mount: a hook that mounts disabled
|
|
414
|
+
* never reports anything but `'idle'` until `enabled` flips to `true`. A
|
|
415
|
+
* hook that mounts enabled skips `'idle'` entirely — the status is set
|
|
416
|
+
* during render, so its very first render already reports `'connecting'`.
|
|
417
|
+
* Consumers must not assume `'idle'` means "never
|
|
418
|
+
* connected" — a stream that is disabled after having connected returns to
|
|
419
|
+
* `'idle'` too, and `data`/`events` from the earlier connection are not
|
|
420
|
+
* cleared by that transition alone (they are cleared by mode/key changes,
|
|
421
|
+
* see below).
|
|
422
|
+
* - `'connecting'` — a connection attempt is committed to but has not settled.
|
|
423
|
+
* It is published during the render that turns the stream on, which is
|
|
424
|
+
* before `descriptor.connect()` runs: the call is made from an effect after
|
|
425
|
+
* that render commits. So `'connecting'` means "this stream is being
|
|
426
|
+
* opened", not "the connect promise is pending" — for one render the two
|
|
427
|
+
* differ, and a consumer that reads the status as proof a request is already
|
|
428
|
+
* in flight is reading it too strongly.
|
|
429
|
+
* - `'connected'` — set both when `connect()` resolves (unless a disconnect
|
|
430
|
+
* was requested while it was pending) and, independently, whenever the
|
|
431
|
+
* `onEvent` callback delivers a new event. Because every event re-asserts
|
|
432
|
+
* `'connected'`, this status also serves as "still receiving events."
|
|
433
|
+
* - `'disconnected'` — reached via any of: the descriptor's `onComplete`
|
|
434
|
+
* callback firing (the stream ended normally), `connect()` rejecting while
|
|
435
|
+
* a disconnect was requested concurrently, or the manual `disconnect()`
|
|
436
|
+
* function being called. `disconnect()` has no `enabled` guard, but calling
|
|
437
|
+
* it while the stream is disabled is not observable: the stored status moves
|
|
438
|
+
* to `'disconnected'` while the published one stays `'idle'`, and flipping
|
|
439
|
+
* `enabled` back to `true` sets `'connecting'` during that render, so the
|
|
440
|
+
* stored `'disconnected'` is overwritten before it is ever returned.
|
|
441
|
+
* - `'error'` — `connect()` rejected and no disconnect was requested while it
|
|
442
|
+
* was pending. `error` holds the rejection, coerced to an `Error` if it
|
|
443
|
+
* wasn't one already.
|
|
444
|
+
*
|
|
445
|
+
* **Transitions**
|
|
446
|
+
* - Mounting enabled, `enabled` becoming `true`, or `descriptor.key` / `mode`
|
|
447
|
+
* changing while `enabled` is `true`: `data`, `events`, and `error` are reset
|
|
448
|
+
* and status is set to `'connecting'` synchronously during render (not from
|
|
449
|
+
* an effect); `connect()` is then called from an effect that runs after that
|
|
450
|
+
* render commits.
|
|
451
|
+
* - `descriptor.key` or `mode` changing while `enabled` is `false`: `data`,
|
|
452
|
+
* `events`, and `error` are reset all the same, since that reset is not gated
|
|
453
|
+
* on `enabled`, but the status write is - so no `'connecting'` is written and
|
|
454
|
+
* the published status stays `'idle'`; `connect()` is not called. The skipped
|
|
455
|
+
* `'connecting'` is not owed later either: the change counts as handled when
|
|
456
|
+
* it happens, so what publishes `'connecting'` is the subsequent flip of
|
|
457
|
+
* `enabled` to `true`, once, for whichever key and mode are in force by then.
|
|
458
|
+
* - `enabled` becomes `false` (or starts `false`): the published status is
|
|
459
|
+
* `'idle'` for as long as `enabled` stays `false` — it is derived from
|
|
460
|
+
* `enabled` rather than written, so nothing a prior connection stored can
|
|
461
|
+
* surface through it — and `connect()` is never called; no other field is
|
|
462
|
+
* reset by this transition alone.
|
|
463
|
+
* - Unmount, `descriptor.key` change, `mode` change, or `enabled` flipping to
|
|
464
|
+
* `false` while connected or connecting: the previous connection is torn
|
|
465
|
+
* down via `descriptor.disconnect()` once its `connect()` promise settles
|
|
466
|
+
* (or immediately skipped if it rejected). All four share the same cleanup
|
|
467
|
+
* path: the effect's cleanup runs on every dependency change and on unmount.
|
|
468
|
+
* - Calling `disconnect()`: if a connection id is already resolved, it is
|
|
469
|
+
* disconnected immediately and status becomes `'disconnected'`. If
|
|
470
|
+
* `connect()` is still pending, the request is recorded and honored when
|
|
471
|
+
* the promise settles — the newly resolved connection is torn down instead
|
|
472
|
+
* of being adopted, and status is `'disconnected'`. One caveat:
|
|
473
|
+
* `disconnect()` does not cancel the event callback, so a buffered or
|
|
474
|
+
* in-flight event landing after the call re-asserts `'connected'` — and in
|
|
475
|
+
* the pending-connect case the settle handler tears the connection down
|
|
476
|
+
* without touching status, so that stray `'connected'` persists.
|
|
477
|
+
* - Stream completion while `connect()` is still pending: the current
|
|
478
|
+
* implementation lets `onComplete` set `'disconnected'`, then the settle
|
|
479
|
+
* handler adopts the connection id and re-asserts `'connected'` anyway.
|
|
480
|
+
* This is known current behavior, not a durable guarantee: a pending
|
|
481
|
+
* upstream derived-status rewrite is expected to remove this transition.
|
|
482
|
+
*
|
|
483
|
+
* `enabled` (default `true`) is the only way to defer connecting past mount;
|
|
484
|
+
* flipping it back to `true` re-runs the same connect sequence as a fresh
|
|
485
|
+
* mount would.
|
|
486
|
+
*/
|
|
409
487
|
declare function useApiStream<TEvent>(descriptor: StreamDescriptor<TEvent>, options?: ApiStreamOptions): ApiStreamResult<TEvent>;
|
|
410
488
|
|
|
411
489
|
/**
|
|
@@ -498,7 +576,7 @@ declare const MfeProvider: React__default.FC<MfeProviderProps>;
|
|
|
498
576
|
* // bridge.executeActionsChain(chain);
|
|
499
577
|
* // bridge.subscribeToProperty(propertyTypeId, callback);
|
|
500
578
|
*
|
|
501
|
-
* return <div>Domain: {bridge.
|
|
579
|
+
* return <div>Domain: {bridge.extDomainId}</div>;
|
|
502
580
|
* }
|
|
503
581
|
* ```
|
|
504
582
|
*/
|
|
@@ -698,13 +776,23 @@ declare function useRegisteredPackages(): string[];
|
|
|
698
776
|
*
|
|
699
777
|
* Styling strategy:
|
|
700
778
|
* 1. adoptHostStylesIntoShadowRoot() clones all host <style> and <link> into the
|
|
701
|
-
* shadow root, bringing the full compiled Tailwind CSS (including
|
|
702
|
-
* since the host's content paths cover src/mfe_packages/**).
|
|
779
|
+
* front of the shadow root, bringing the full compiled Tailwind CSS (including
|
|
780
|
+
* MFE utilities, since the host's content paths cover src/mfe_packages/**).
|
|
781
|
+
* Front, not back, so the MFE's own stylesheets outrank them - see the method.
|
|
703
782
|
* 2. injectBaseResets() adds box-model resets and :host defaults that aren't part
|
|
704
|
-
* of Tailwind's compiled output but are needed for consistent rendering
|
|
783
|
+
* of Tailwind's compiled output but are needed for consistent rendering, and
|
|
784
|
+
* positions them at the end of the shell-owned head - after the adopted block
|
|
785
|
+
* and the isolation style, ahead of the MFE's own CSS.
|
|
705
786
|
* 3. Subclasses may override initializeStyles() to inject additional CSS that is
|
|
706
787
|
* not covered by the host stylesheet (e.g., MFE-specific @font-face rules).
|
|
707
788
|
*
|
|
789
|
+
* Every mount therefore leaves the same sequence - adopted host block, shadow
|
|
790
|
+
* isolation, base resets, then the MFE's stylesheets - so the shell's CSS is
|
|
791
|
+
* context and the MFE wins every specificity tie against all three shell blocks.
|
|
792
|
+
* Steps 1 and 2 both position what they own rather than appending beside it,
|
|
793
|
+
* because a remounted container arrives with its shadow root intact and the MFE's
|
|
794
|
+
* own stylesheet removed and re-appended around the remount - see each method.
|
|
795
|
+
*
|
|
708
796
|
* Theme CSS variables are delivered via CSS inheritance from :root (Shadow DOM)
|
|
709
797
|
* or via MountManager injection (iframe). MFE lifecycles do NOT need to subscribe
|
|
710
798
|
* to theme changes or call applyThemeToShadowRoot.
|
|
@@ -721,12 +809,83 @@ declare abstract class ThemeAwareReactLifecycle implements MfeEntryLifecycle<Chi
|
|
|
721
809
|
/**
|
|
722
810
|
* Copy all inline <style> and <link rel="stylesheet"> from the host document
|
|
723
811
|
* into the shadow root so that Tailwind and component styles apply inside the MFE.
|
|
812
|
+
*
|
|
813
|
+
* The clones are inserted ahead of everything already in the shadow root, never
|
|
814
|
+
* appended, because adopted host styles are context rather than authority: where
|
|
815
|
+
* they and the MFE's own CSS declare the same property at equal specificity, the
|
|
816
|
+
* MFE has to win. Appending inverted that. `MfeHandlerMF` injects the MFE's
|
|
817
|
+
* compiled stylesheet into the shadow root before it calls mount, so an appended
|
|
818
|
+
* clone of the shell's Tailwind preflight - whose
|
|
819
|
+
* `button, [type='button'], [type='reset'], [type='submit']` rule sets
|
|
820
|
+
* `background-color: transparent` at specificity (0,1,0) - tied with
|
|
821
|
+
* `@gears-frontx/ui-kit`'s single-class button rule and won on document order,
|
|
822
|
+
* leaving every kit Button transparent until it was hovered.
|
|
823
|
+
*
|
|
824
|
+
* Inserting at the front rather than pushing MFE styles to the back is what makes
|
|
825
|
+
* the invariant hold for stylesheets that appear after mount too - a lazily
|
|
826
|
+
* imported component's CSS module, or whatever initializeStyles() adds - since
|
|
827
|
+
* those land behind the adopted block by construction.
|
|
828
|
+
*
|
|
829
|
+
* A cascade layer around the adopted CSS was the alternative and is rejected:
|
|
830
|
+
* layered rules lose to unlayered ones at *any* specificity, so a host utility
|
|
831
|
+
* class would stop overriding an MFE element selector. Document order keeps
|
|
832
|
+
* specificity in charge and only settles the ties.
|
|
833
|
+
*
|
|
834
|
+
* The block replaces its predecessor instead of stacking on it, the same
|
|
835
|
+
* upsert shape `injectStylesheet` and `injectCssVariables` use in
|
|
836
|
+
* `@gears-frontx/mfes`' shadow utilities, widened from one id-keyed node to a
|
|
837
|
+
* marked block. Replacement is required rather than tidy: `createShadowRoot`
|
|
838
|
+
* hands back an existing `element.shadowRoot` instead of attaching a new one,
|
|
839
|
+
* so remounting the same container runs this method again on a shadow root
|
|
840
|
+
* that already holds a full adopted block, and appending would grow it once
|
|
841
|
+
* per mount with no bound. It does not save re-resolving the cloned `<link>`s -
|
|
842
|
+
* every mount clones them afresh and the browser resolves each clone; what
|
|
843
|
+
* replacement buys is that the count stays at one block instead of one per
|
|
844
|
+
* mount.
|
|
845
|
+
*
|
|
846
|
+
* The block is rebuilt from the host head rather than left in place, because
|
|
847
|
+
* the head is not fixed: a lazily imported chunk adds stylesheets to it after
|
|
848
|
+
* the first mount, and the second mount has to pick those up.
|
|
849
|
+
*
|
|
850
|
+
* The fresh block goes in before the previous one comes out. Removing first
|
|
851
|
+
* leaves the shadow root with no host CSS at all, and everything between that
|
|
852
|
+
* removal and the insertion is synchronous work in this same task - so the gap
|
|
853
|
+
* never reaches a paint, but any code that reads computed styles from the tree
|
|
854
|
+
* in between sees an unstyled one. Inserting first costs one moment with two
|
|
855
|
+
* blocks present, which changes nothing: the old block is a clone of the same
|
|
856
|
+
* host head and loses every tie to the new one on document order anyway.
|
|
724
857
|
*/
|
|
725
858
|
protected adoptHostStylesIntoShadowRoot(shadowRoot: ShadowRoot): void;
|
|
726
859
|
/**
|
|
727
860
|
* Box-model resets and :host defaults needed inside every shadow root.
|
|
728
861
|
* These aren't part of Tailwind's compiled output but are required for
|
|
729
862
|
* consistent rendering across browsers.
|
|
863
|
+
*
|
|
864
|
+
* Reuses the node a previous mount left behind, exactly as `injectStylesheet`
|
|
865
|
+
* does in `@gears-frontx/mfes`' shadow utilities: a remount runs against a
|
|
866
|
+
* shadow root that `createShadowRoot` handed back intact, and appending a
|
|
867
|
+
* second copy would add one node per mount forever.
|
|
868
|
+
*
|
|
869
|
+
* Reuse alone is not enough, which is why the node is also positioned on every
|
|
870
|
+
* mount rather than left where the previous one sat. These resets are context
|
|
871
|
+
* like the adopted block is - `border-color: currentColor` on `*` is a 0-0-0
|
|
872
|
+
* declaration that beats an MFE preflight's own 0-0-0 reset purely on document
|
|
873
|
+
* order - so they have to stay ahead of the MFE's CSS, and where they land is
|
|
874
|
+
* not stable on its own. `MfeHandlerMF.wrapLifecycleWithStylesheets` removes the
|
|
875
|
+
* MFE's stylesheet on unmount and appends a fresh one before the next mount, so
|
|
876
|
+
* a node merely left in place ends up ahead of that stylesheet on a remount and
|
|
877
|
+
* behind it on the first mount: two different cascades for one component.
|
|
878
|
+
* Anchoring it to the end of the shell-owned head gives every mount the same
|
|
879
|
+
* order - adopted block, isolation, resets, MFE - which is also the order the
|
|
880
|
+
* adoption method's invariant is written against.
|
|
881
|
+
*
|
|
882
|
+
* With no shell-owned node to anchor to, the resets go to the front. That is the
|
|
883
|
+
* plain-`Element` container: no adopted block, no isolation style, and the MFE
|
|
884
|
+
* stylesheet already appended by the handler, so the front is again the only
|
|
885
|
+
* position that leaves the MFE winning ties.
|
|
886
|
+
*
|
|
887
|
+
* Looked up by attribute-selector form rather than `getElementById`, which
|
|
888
|
+
* `ShadowRoot` has but `Element` does not, and this hook takes either.
|
|
730
889
|
*/
|
|
731
890
|
private injectBaseResets;
|
|
732
891
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -366,10 +366,9 @@ declare function useApiSuspenseInfiniteQuery<TPage = unknown, TError = Error>(op
|
|
|
366
366
|
/**
|
|
367
367
|
* useApiStream - Declarative SSE streaming hook
|
|
368
368
|
*
|
|
369
|
-
* Accepts a StreamDescriptor from @gears-frontx/api and
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* a manual disconnect function.
|
|
369
|
+
* Accepts a StreamDescriptor from @gears-frontx/api and returns the latest
|
|
370
|
+
* event, accumulated events, connection status, and a manual disconnect
|
|
371
|
+
* function.
|
|
373
372
|
*
|
|
374
373
|
* @example
|
|
375
374
|
* ```tsx
|
|
@@ -395,17 +394,96 @@ interface ApiStreamOptions {
|
|
|
395
394
|
}
|
|
396
395
|
/** Return type of useApiStream. */
|
|
397
396
|
interface ApiStreamResult<TEvent> {
|
|
398
|
-
/** Latest event payload
|
|
397
|
+
/** Latest event payload, set in both modes — `undefined` until the first event and after each connect attempt resets it. */
|
|
399
398
|
data: TEvent | undefined;
|
|
400
399
|
/** All received events when `mode: 'accumulate'`; empty array in `'latest'` mode. */
|
|
401
400
|
events: TEvent[];
|
|
402
401
|
/** Connection lifecycle status. */
|
|
403
402
|
status: StreamStatus;
|
|
404
|
-
/**
|
|
403
|
+
/** Last connect error — set when a connect attempt rejects, cleared when the next attempt starts. */
|
|
405
404
|
error: Error | null;
|
|
406
405
|
/** Manually close the connection. */
|
|
407
406
|
disconnect: () => void;
|
|
408
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Manages the status lifecycle for a single SSE stream connection.
|
|
410
|
+
*
|
|
411
|
+
* **Status values**
|
|
412
|
+
* - `'idle'` — no connection is being attempted. This is the status whenever
|
|
413
|
+
* `enabled` is `false`, including on mount: a hook that mounts disabled
|
|
414
|
+
* never reports anything but `'idle'` until `enabled` flips to `true`. A
|
|
415
|
+
* hook that mounts enabled skips `'idle'` entirely — the status is set
|
|
416
|
+
* during render, so its very first render already reports `'connecting'`.
|
|
417
|
+
* Consumers must not assume `'idle'` means "never
|
|
418
|
+
* connected" — a stream that is disabled after having connected returns to
|
|
419
|
+
* `'idle'` too, and `data`/`events` from the earlier connection are not
|
|
420
|
+
* cleared by that transition alone (they are cleared by mode/key changes,
|
|
421
|
+
* see below).
|
|
422
|
+
* - `'connecting'` — a connection attempt is committed to but has not settled.
|
|
423
|
+
* It is published during the render that turns the stream on, which is
|
|
424
|
+
* before `descriptor.connect()` runs: the call is made from an effect after
|
|
425
|
+
* that render commits. So `'connecting'` means "this stream is being
|
|
426
|
+
* opened", not "the connect promise is pending" — for one render the two
|
|
427
|
+
* differ, and a consumer that reads the status as proof a request is already
|
|
428
|
+
* in flight is reading it too strongly.
|
|
429
|
+
* - `'connected'` — set both when `connect()` resolves (unless a disconnect
|
|
430
|
+
* was requested while it was pending) and, independently, whenever the
|
|
431
|
+
* `onEvent` callback delivers a new event. Because every event re-asserts
|
|
432
|
+
* `'connected'`, this status also serves as "still receiving events."
|
|
433
|
+
* - `'disconnected'` — reached via any of: the descriptor's `onComplete`
|
|
434
|
+
* callback firing (the stream ended normally), `connect()` rejecting while
|
|
435
|
+
* a disconnect was requested concurrently, or the manual `disconnect()`
|
|
436
|
+
* function being called. `disconnect()` has no `enabled` guard, but calling
|
|
437
|
+
* it while the stream is disabled is not observable: the stored status moves
|
|
438
|
+
* to `'disconnected'` while the published one stays `'idle'`, and flipping
|
|
439
|
+
* `enabled` back to `true` sets `'connecting'` during that render, so the
|
|
440
|
+
* stored `'disconnected'` is overwritten before it is ever returned.
|
|
441
|
+
* - `'error'` — `connect()` rejected and no disconnect was requested while it
|
|
442
|
+
* was pending. `error` holds the rejection, coerced to an `Error` if it
|
|
443
|
+
* wasn't one already.
|
|
444
|
+
*
|
|
445
|
+
* **Transitions**
|
|
446
|
+
* - Mounting enabled, `enabled` becoming `true`, or `descriptor.key` / `mode`
|
|
447
|
+
* changing while `enabled` is `true`: `data`, `events`, and `error` are reset
|
|
448
|
+
* and status is set to `'connecting'` synchronously during render (not from
|
|
449
|
+
* an effect); `connect()` is then called from an effect that runs after that
|
|
450
|
+
* render commits.
|
|
451
|
+
* - `descriptor.key` or `mode` changing while `enabled` is `false`: `data`,
|
|
452
|
+
* `events`, and `error` are reset all the same, since that reset is not gated
|
|
453
|
+
* on `enabled`, but the status write is - so no `'connecting'` is written and
|
|
454
|
+
* the published status stays `'idle'`; `connect()` is not called. The skipped
|
|
455
|
+
* `'connecting'` is not owed later either: the change counts as handled when
|
|
456
|
+
* it happens, so what publishes `'connecting'` is the subsequent flip of
|
|
457
|
+
* `enabled` to `true`, once, for whichever key and mode are in force by then.
|
|
458
|
+
* - `enabled` becomes `false` (or starts `false`): the published status is
|
|
459
|
+
* `'idle'` for as long as `enabled` stays `false` — it is derived from
|
|
460
|
+
* `enabled` rather than written, so nothing a prior connection stored can
|
|
461
|
+
* surface through it — and `connect()` is never called; no other field is
|
|
462
|
+
* reset by this transition alone.
|
|
463
|
+
* - Unmount, `descriptor.key` change, `mode` change, or `enabled` flipping to
|
|
464
|
+
* `false` while connected or connecting: the previous connection is torn
|
|
465
|
+
* down via `descriptor.disconnect()` once its `connect()` promise settles
|
|
466
|
+
* (or immediately skipped if it rejected). All four share the same cleanup
|
|
467
|
+
* path: the effect's cleanup runs on every dependency change and on unmount.
|
|
468
|
+
* - Calling `disconnect()`: if a connection id is already resolved, it is
|
|
469
|
+
* disconnected immediately and status becomes `'disconnected'`. If
|
|
470
|
+
* `connect()` is still pending, the request is recorded and honored when
|
|
471
|
+
* the promise settles — the newly resolved connection is torn down instead
|
|
472
|
+
* of being adopted, and status is `'disconnected'`. One caveat:
|
|
473
|
+
* `disconnect()` does not cancel the event callback, so a buffered or
|
|
474
|
+
* in-flight event landing after the call re-asserts `'connected'` — and in
|
|
475
|
+
* the pending-connect case the settle handler tears the connection down
|
|
476
|
+
* without touching status, so that stray `'connected'` persists.
|
|
477
|
+
* - Stream completion while `connect()` is still pending: the current
|
|
478
|
+
* implementation lets `onComplete` set `'disconnected'`, then the settle
|
|
479
|
+
* handler adopts the connection id and re-asserts `'connected'` anyway.
|
|
480
|
+
* This is known current behavior, not a durable guarantee: a pending
|
|
481
|
+
* upstream derived-status rewrite is expected to remove this transition.
|
|
482
|
+
*
|
|
483
|
+
* `enabled` (default `true`) is the only way to defer connecting past mount;
|
|
484
|
+
* flipping it back to `true` re-runs the same connect sequence as a fresh
|
|
485
|
+
* mount would.
|
|
486
|
+
*/
|
|
409
487
|
declare function useApiStream<TEvent>(descriptor: StreamDescriptor<TEvent>, options?: ApiStreamOptions): ApiStreamResult<TEvent>;
|
|
410
488
|
|
|
411
489
|
/**
|
|
@@ -498,7 +576,7 @@ declare const MfeProvider: React__default.FC<MfeProviderProps>;
|
|
|
498
576
|
* // bridge.executeActionsChain(chain);
|
|
499
577
|
* // bridge.subscribeToProperty(propertyTypeId, callback);
|
|
500
578
|
*
|
|
501
|
-
* return <div>Domain: {bridge.
|
|
579
|
+
* return <div>Domain: {bridge.extDomainId}</div>;
|
|
502
580
|
* }
|
|
503
581
|
* ```
|
|
504
582
|
*/
|
|
@@ -698,13 +776,23 @@ declare function useRegisteredPackages(): string[];
|
|
|
698
776
|
*
|
|
699
777
|
* Styling strategy:
|
|
700
778
|
* 1. adoptHostStylesIntoShadowRoot() clones all host <style> and <link> into the
|
|
701
|
-
* shadow root, bringing the full compiled Tailwind CSS (including
|
|
702
|
-
* since the host's content paths cover src/mfe_packages/**).
|
|
779
|
+
* front of the shadow root, bringing the full compiled Tailwind CSS (including
|
|
780
|
+
* MFE utilities, since the host's content paths cover src/mfe_packages/**).
|
|
781
|
+
* Front, not back, so the MFE's own stylesheets outrank them - see the method.
|
|
703
782
|
* 2. injectBaseResets() adds box-model resets and :host defaults that aren't part
|
|
704
|
-
* of Tailwind's compiled output but are needed for consistent rendering
|
|
783
|
+
* of Tailwind's compiled output but are needed for consistent rendering, and
|
|
784
|
+
* positions them at the end of the shell-owned head - after the adopted block
|
|
785
|
+
* and the isolation style, ahead of the MFE's own CSS.
|
|
705
786
|
* 3. Subclasses may override initializeStyles() to inject additional CSS that is
|
|
706
787
|
* not covered by the host stylesheet (e.g., MFE-specific @font-face rules).
|
|
707
788
|
*
|
|
789
|
+
* Every mount therefore leaves the same sequence - adopted host block, shadow
|
|
790
|
+
* isolation, base resets, then the MFE's stylesheets - so the shell's CSS is
|
|
791
|
+
* context and the MFE wins every specificity tie against all three shell blocks.
|
|
792
|
+
* Steps 1 and 2 both position what they own rather than appending beside it,
|
|
793
|
+
* because a remounted container arrives with its shadow root intact and the MFE's
|
|
794
|
+
* own stylesheet removed and re-appended around the remount - see each method.
|
|
795
|
+
*
|
|
708
796
|
* Theme CSS variables are delivered via CSS inheritance from :root (Shadow DOM)
|
|
709
797
|
* or via MountManager injection (iframe). MFE lifecycles do NOT need to subscribe
|
|
710
798
|
* to theme changes or call applyThemeToShadowRoot.
|
|
@@ -721,12 +809,83 @@ declare abstract class ThemeAwareReactLifecycle implements MfeEntryLifecycle<Chi
|
|
|
721
809
|
/**
|
|
722
810
|
* Copy all inline <style> and <link rel="stylesheet"> from the host document
|
|
723
811
|
* into the shadow root so that Tailwind and component styles apply inside the MFE.
|
|
812
|
+
*
|
|
813
|
+
* The clones are inserted ahead of everything already in the shadow root, never
|
|
814
|
+
* appended, because adopted host styles are context rather than authority: where
|
|
815
|
+
* they and the MFE's own CSS declare the same property at equal specificity, the
|
|
816
|
+
* MFE has to win. Appending inverted that. `MfeHandlerMF` injects the MFE's
|
|
817
|
+
* compiled stylesheet into the shadow root before it calls mount, so an appended
|
|
818
|
+
* clone of the shell's Tailwind preflight - whose
|
|
819
|
+
* `button, [type='button'], [type='reset'], [type='submit']` rule sets
|
|
820
|
+
* `background-color: transparent` at specificity (0,1,0) - tied with
|
|
821
|
+
* `@gears-frontx/ui-kit`'s single-class button rule and won on document order,
|
|
822
|
+
* leaving every kit Button transparent until it was hovered.
|
|
823
|
+
*
|
|
824
|
+
* Inserting at the front rather than pushing MFE styles to the back is what makes
|
|
825
|
+
* the invariant hold for stylesheets that appear after mount too - a lazily
|
|
826
|
+
* imported component's CSS module, or whatever initializeStyles() adds - since
|
|
827
|
+
* those land behind the adopted block by construction.
|
|
828
|
+
*
|
|
829
|
+
* A cascade layer around the adopted CSS was the alternative and is rejected:
|
|
830
|
+
* layered rules lose to unlayered ones at *any* specificity, so a host utility
|
|
831
|
+
* class would stop overriding an MFE element selector. Document order keeps
|
|
832
|
+
* specificity in charge and only settles the ties.
|
|
833
|
+
*
|
|
834
|
+
* The block replaces its predecessor instead of stacking on it, the same
|
|
835
|
+
* upsert shape `injectStylesheet` and `injectCssVariables` use in
|
|
836
|
+
* `@gears-frontx/mfes`' shadow utilities, widened from one id-keyed node to a
|
|
837
|
+
* marked block. Replacement is required rather than tidy: `createShadowRoot`
|
|
838
|
+
* hands back an existing `element.shadowRoot` instead of attaching a new one,
|
|
839
|
+
* so remounting the same container runs this method again on a shadow root
|
|
840
|
+
* that already holds a full adopted block, and appending would grow it once
|
|
841
|
+
* per mount with no bound. It does not save re-resolving the cloned `<link>`s -
|
|
842
|
+
* every mount clones them afresh and the browser resolves each clone; what
|
|
843
|
+
* replacement buys is that the count stays at one block instead of one per
|
|
844
|
+
* mount.
|
|
845
|
+
*
|
|
846
|
+
* The block is rebuilt from the host head rather than left in place, because
|
|
847
|
+
* the head is not fixed: a lazily imported chunk adds stylesheets to it after
|
|
848
|
+
* the first mount, and the second mount has to pick those up.
|
|
849
|
+
*
|
|
850
|
+
* The fresh block goes in before the previous one comes out. Removing first
|
|
851
|
+
* leaves the shadow root with no host CSS at all, and everything between that
|
|
852
|
+
* removal and the insertion is synchronous work in this same task - so the gap
|
|
853
|
+
* never reaches a paint, but any code that reads computed styles from the tree
|
|
854
|
+
* in between sees an unstyled one. Inserting first costs one moment with two
|
|
855
|
+
* blocks present, which changes nothing: the old block is a clone of the same
|
|
856
|
+
* host head and loses every tie to the new one on document order anyway.
|
|
724
857
|
*/
|
|
725
858
|
protected adoptHostStylesIntoShadowRoot(shadowRoot: ShadowRoot): void;
|
|
726
859
|
/**
|
|
727
860
|
* Box-model resets and :host defaults needed inside every shadow root.
|
|
728
861
|
* These aren't part of Tailwind's compiled output but are required for
|
|
729
862
|
* consistent rendering across browsers.
|
|
863
|
+
*
|
|
864
|
+
* Reuses the node a previous mount left behind, exactly as `injectStylesheet`
|
|
865
|
+
* does in `@gears-frontx/mfes`' shadow utilities: a remount runs against a
|
|
866
|
+
* shadow root that `createShadowRoot` handed back intact, and appending a
|
|
867
|
+
* second copy would add one node per mount forever.
|
|
868
|
+
*
|
|
869
|
+
* Reuse alone is not enough, which is why the node is also positioned on every
|
|
870
|
+
* mount rather than left where the previous one sat. These resets are context
|
|
871
|
+
* like the adopted block is - `border-color: currentColor` on `*` is a 0-0-0
|
|
872
|
+
* declaration that beats an MFE preflight's own 0-0-0 reset purely on document
|
|
873
|
+
* order - so they have to stay ahead of the MFE's CSS, and where they land is
|
|
874
|
+
* not stable on its own. `MfeHandlerMF.wrapLifecycleWithStylesheets` removes the
|
|
875
|
+
* MFE's stylesheet on unmount and appends a fresh one before the next mount, so
|
|
876
|
+
* a node merely left in place ends up ahead of that stylesheet on a remount and
|
|
877
|
+
* behind it on the first mount: two different cascades for one component.
|
|
878
|
+
* Anchoring it to the end of the shell-owned head gives every mount the same
|
|
879
|
+
* order - adopted block, isolation, resets, MFE - which is also the order the
|
|
880
|
+
* adoption method's invariant is written against.
|
|
881
|
+
*
|
|
882
|
+
* With no shell-owned node to anchor to, the resets go to the front. That is the
|
|
883
|
+
* plain-`Element` container: no adopted block, no isolation style, and the MFE
|
|
884
|
+
* stylesheet already appended by the handler, so the front is again the only
|
|
885
|
+
* position that leaves the MFE winning ties.
|
|
886
|
+
*
|
|
887
|
+
* Looked up by attribute-selector form rather than `getElementById`, which
|
|
888
|
+
* `ShadowRoot` has but `Element` does not, and this hook takes either.
|
|
730
889
|
*/
|
|
731
890
|
private injectBaseResets;
|
|
732
891
|
/**
|