camox 0.67.0 → 0.69.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.
Files changed (33) hide show
  1. package/dist/core/editing/createEditableBlock.js +2 -1
  2. package/dist/features/canvas/canvasFrameDocument.js +25 -2
  3. package/dist/features/canvas/useCanvasFrame.js +6 -2
  4. package/dist/features/preview/components/PreviewToolbar.js +77 -68
  5. package/dist/features/preview/components/previewStyles.js +11 -2
  6. package/dist/features/preview/repeatableItemTargets.js +13 -7
  7. package/dist/features/provider/AuthenticatedCamoxProvider.js +33 -28
  8. package/dist/features/renderer/RendererApp.js +202 -154
  9. package/dist/features/renderer/RendererFrames.js +87 -55
  10. package/dist/features/renderer/definitionAnswers.js +1 -0
  11. package/dist/features/renderer/rendererHost.js +4 -0
  12. package/dist/features/renderer/studioConnection.js +9 -1
  13. package/dist/features/runtime/RuntimeChrome.js +47 -61
  14. package/dist/features/runtime/pageNavigation.js +93 -17
  15. package/dist/features/runtime/rendererClient.js +13 -6
  16. package/dist/features/studio/components/ChatWidget.js +3 -4
  17. package/dist/features/studio/components/ConnectAgent.js +33 -59
  18. package/dist/features/studio/components/DraftBar.js +139 -0
  19. package/dist/features/studio/components/DraftsControl.js +129 -164
  20. package/dist/features/studio/components/LocalePicker.js +22 -4
  21. package/dist/features/studio/components/Navbar.js +3 -2
  22. package/dist/features/studio/components/ReviewDraftSheet.js +2 -21
  23. package/dist/features/studio/components/UserButton.js +7 -11
  24. package/dist/features/studio/studioStore.js +0 -13
  25. package/dist/features/studio/viewSwitch.js +64 -0
  26. package/dist/lib/auth.js +5 -1
  27. package/dist/lib/draft-scope.js +28 -15
  28. package/dist/lib/studio-reads.js +46 -13
  29. package/dist/lib/view-switch.js +64 -0
  30. package/dist/package.js +1 -1
  31. package/dist/studio.css +1 -1
  32. package/package.json +4 -4
  33. package/dist/features/studio/components/UnnamedDraftBar.js +0 -349
@@ -7,7 +7,8 @@ import { useLocalePath, useLocalizedPath } from "../../../lib/view-locale.js";
7
7
  import { STUDIO_BASE_PATH, STUDIO_CONTENT_PATH, STUDIO_SETTINGS_PATH } from "../routes.js";
8
8
  import { studioStore } from "../studioStore.js";
9
9
  import { UserButton } from "./UserButton.js";
10
- import { DraftPicker, PendingChanges } from "./DraftsControl.js";
10
+ import { ConnectAgent } from "./ConnectAgent.js";
11
+ import { DraftPicker } from "./DraftsControl.js";
11
12
  import { LocalePicker } from "./LocalePicker.js";
12
13
  import { ProjectMenu } from "./ProjectMenu.js";
13
14
  import { c } from "react/compiler-runtime";
@@ -144,7 +145,7 @@ const Navbar = (t0) => {
144
145
  if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
145
146
  t10 = /* @__PURE__ */ jsxs("div", {
146
147
  className: "flex items-center gap-2",
147
- children: [/* @__PURE__ */ jsx(PendingChanges, {}), /* @__PURE__ */ jsx(UserButton, {})]
148
+ children: [/* @__PURE__ */ jsx(ConnectAgent, {}), /* @__PURE__ */ jsx(UserButton, {})]
148
149
  });
149
150
  $[23] = t10;
150
151
  } else t10 = $[23];
@@ -1,4 +1,3 @@
1
- import { useDraftScope } from "../../../lib/draft-scope.js";
2
1
  import { reads, useReadQuery, useStudioCache } from "../../../lib/studio-reads.js";
3
2
  import { cn } from "../../../lib/utils.js";
4
3
  import { getDraftReadClient } from "../../../lib/api-client.js";
@@ -9,6 +8,7 @@ import { localeLabel } from "../localeOptions.js";
9
8
  import { askAgentMessage, findingSentence, fixLabel } from "../findingSentence.js";
10
9
  import { useShowInCanvas } from "../showInCanvas.js";
11
10
  import { draftLabel, plural, timeAgo } from "../draftLabel.js";
11
+ import { useLeaveDraft } from "../viewSwitch.js";
12
12
  import { c } from "react/compiler-runtime";
13
13
  import * as React from "react";
14
14
  import { CHECKS_RUNNING_ERROR, CONFLICTS_CHANGED_ERROR, FINDINGS_OPEN_ERROR, REVISION_CHANGED_ERROR, TRANSLATIONS_PENDING_ERROR } from "@camox/api-contract/drafts";
@@ -1133,25 +1133,6 @@ function _temp11(bullet, index) {
1133
1133
  function _temp10(error) {
1134
1134
  return toast.error(error.message || "Could not summarize the draft");
1135
1135
  }
1136
- /** Switches the studio to Live once its draft ended here, replacing the draft's URL entry. */
1137
- function useLeaveDraft() {
1138
- const $ = c(2);
1139
- const draftScope = useDraftScope();
1140
- let t0;
1141
- if ($[0] !== draftScope) {
1142
- t0 = (ended, t1) => {
1143
- const { discarded: t2 } = t1 === void 0 ? {} : t1;
1144
- const discarded = t2 === void 0 ? false : t2;
1145
- draftScope.leave(ended);
1146
- if (!ended) return;
1147
- const what = discarded ? "Changes discarded" : `Draft ${ended.outcome}`;
1148
- toast.success(`${what}. You're now viewing Live.`);
1149
- };
1150
- $[0] = draftScope;
1151
- $[1] = t0;
1152
- } else t0 = $[1];
1153
- return t0;
1154
- }
1155
1136
  /**
1156
1137
  * Renames a regular draft, whichever draft the studio views: the request names the draft it
1157
1138
  * renames. A blank name clears it, so the draft shows its computed label again.
@@ -1807,4 +1788,4 @@ function _temp14(error) {
1807
1788
  }
1808
1789
 
1809
1790
  //#endregion
1810
- export { DeleteDraftDialog, ReviewDraftSheet, useLeaveDraft, useRenameDraft };
1791
+ export { DeleteDraftDialog, ReviewDraftSheet, useRenameDraft };
@@ -9,7 +9,6 @@ import { useApplyTheme } from "../useTheme.js";
9
9
  import { c } from "react/compiler-runtime";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import { useSelector } from "@xstate/store-react";
12
- import { Button } from "@camox/ui/button";
13
12
  import { Check, Command, EyeOff, LogOut, Monitor, Moon, Settings, Sun, User } from "lucide-react";
14
13
  import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
15
14
  import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@camox/ui/dropdown-menu";
@@ -22,11 +21,7 @@ const UserButton = () => {
22
21
  if (!isAuthenticated || isLoading) {
23
22
  let t0;
24
23
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
25
- t0 = /* @__PURE__ */ jsx(Button, {
26
- variant: "outline",
27
- size: "icon",
28
- children: /* @__PURE__ */ jsx(User, { className: "h-4 w-4" })
29
- });
24
+ t0 = /* @__PURE__ */ jsx(Avatar, { children: /* @__PURE__ */ jsx(AvatarFallback, { children: /* @__PURE__ */ jsx(User, { className: "size-4" }) }) });
30
25
  $[0] = t0;
31
26
  } else t0 = $[0];
32
27
  return t0;
@@ -62,11 +57,12 @@ function AuthenticatedUserButton({ theme, setTheme }) {
62
57
  const userImage = session?.user?.image;
63
58
  const userInitials = userName.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
64
59
  return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
65
- render: /* @__PURE__ */ jsx(Button, {
66
- variant: "outline",
67
- size: "icon"
68
- }),
69
- children: /* @__PURE__ */ jsx(User, { className: "text-muted-foreground" })
60
+ "aria-label": "Account",
61
+ className: "focus-visible:ring-ring/50 rounded-full outline-none focus-visible:ring-3",
62
+ children: /* @__PURE__ */ jsxs(Avatar, { children: [userImage && /* @__PURE__ */ jsx(AvatarImage, {
63
+ src: userImage,
64
+ alt: userName
65
+ }), /* @__PURE__ */ jsx(AvatarFallback, { children: userInitials })] })
70
66
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
71
67
  className: "w-72",
72
68
  align: "end",
@@ -10,7 +10,6 @@ const studioStore = createStore({
10
10
  startRenaming: false
11
11
  },
12
12
  isDeleteDraftDialogOpen: false,
13
- isKeepDraftOpen: false,
14
13
  localeDialog: null,
15
14
  websiteLocation: null,
16
15
  agentAsk: null,
@@ -79,18 +78,6 @@ const studioStore = createStore({
79
78
  isDeleteDraftDialogOpen: false
80
79
  };
81
80
  },
82
- openKeepDraft: (context) => {
83
- return {
84
- ...context,
85
- isKeepDraftOpen: true
86
- };
87
- },
88
- closeKeepDraft: (context) => {
89
- return {
90
- ...context,
91
- isKeepDraftOpen: false
92
- };
93
- },
94
81
  openLocaleDialog: (context, event) => {
95
82
  return {
96
83
  ...context,
@@ -0,0 +1,64 @@
1
+ import { useDraftScope } from "../../lib/draft-scope.js";
2
+ import { useViewShown } from "../../lib/view-switch.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { toast } from "@camox/ui/toaster";
5
+
6
+ //#region src/features/studio/viewSwitch.ts
7
+ /**
8
+ * Tells the editor the studio heard them while it switches to another draft or locale: the
9
+ * studio keeps showing what it showed until the next view is ready, then shows it at once.
10
+ * `switching` settles once it shows.
11
+ */
12
+ function toastSwitch(switching, messages) {
13
+ toast.promise(switching, {
14
+ ...messages,
15
+ error: "Something went wrong while switching. Reload the page to try again."
16
+ });
17
+ }
18
+ /**
19
+ * Switches to another draft or locale with `navigate`, which starts the navigation that does,
20
+ * saying so in a toast until the next view shows.
21
+ */
22
+ function useSwitchView() {
23
+ const $ = c(2);
24
+ const shown = useViewShown();
25
+ let t0;
26
+ if ($[0] !== shown) {
27
+ t0 = (navigate, messages) => toastSwitch(Promise.resolve(navigate()).then(() => shown()), messages);
28
+ $[0] = shown;
29
+ $[1] = t0;
30
+ } else t0 = $[1];
31
+ return t0;
32
+ }
33
+ /**
34
+ * Switches the studio to Live once the draft it views ended, by this member, here or in another
35
+ * tab, replacing the draft's URL entry. Called once the studio already left the draft, it does
36
+ * nothing.
37
+ */
38
+ function useLeaveDraft() {
39
+ const $ = c(3);
40
+ const draftScope = useDraftScope();
41
+ const shown = useViewShown();
42
+ let t0;
43
+ if ($[0] !== draftScope || $[1] !== shown) {
44
+ t0 = (ended, t1) => {
45
+ const { discarded: t2 } = t1 === void 0 ? {} : t1;
46
+ const discarded = t2 === void 0 ? false : t2;
47
+ if (ended && draftScope.current() !== ended.draftId) return;
48
+ draftScope.leave(ended);
49
+ if (!ended) return;
50
+ const what = discarded ? "Changes discarded" : `Draft ${ended.outcome}`;
51
+ toastSwitch(shown(), {
52
+ loading: `${what}. Switching to Live…`,
53
+ success: `${what}. You're now viewing Live.`
54
+ });
55
+ };
56
+ $[0] = draftScope;
57
+ $[1] = shown;
58
+ $[2] = t0;
59
+ } else t0 = $[2];
60
+ return t0;
61
+ }
62
+
63
+ //#endregion
64
+ export { useLeaveDraft, useSwitchView };
package/dist/lib/auth.js CHANGED
@@ -250,6 +250,10 @@ function useSessionState(authClient, track) {
250
250
  const subscribe = t1;
251
251
  return React.useSyncExternalStore(track ? subscribe : noSubscription, getSnapshot, getSnapshot);
252
252
  }
253
+ /** The id of the member signed in, as the session the client holds says: null without one. */
254
+ function signedInUserId(authClient) {
255
+ return authClient.$store.atoms.session.value.data?.user?.id ?? null;
256
+ }
253
257
  function useAuthState() {
254
258
  const $ = c(10);
255
259
  const { authClient, initialAuthenticated: t0, exchangingToken: t1, sessionless: t2 } = useAuthContext();
@@ -394,4 +398,4 @@ function _temp4() {
394
398
  }
395
399
 
396
400
  //#endregion
397
- export { AuthContext, createCamoxAuthClient, getAuthCookieHeader, getAuthRequestCredentials, useAuthActions, useAuthContext, useAuthState, useIsAuthenticated, useProcessOtt, useProjectUuid, useSignInRedirect };
401
+ export { AuthContext, createCamoxAuthClient, getAuthCookieHeader, getAuthRequestCredentials, signedInUserId, useAuthActions, useAuthContext, useAuthState, useIsAuthenticated, useProcessOtt, useProjectUuid, useSignInRedirect };
@@ -158,37 +158,50 @@ const DraftScopeContext = React.createContext(null);
158
158
  /**
159
159
  * The draft scope the studio is in, for handlers and effects. Render code reads the draft it
160
160
  * views from `useCurrentDraftId`: the scope object never changes, so a memoized render reading
161
- * `current()` from it would keep showing the draft of its first render.
161
+ * `current()` from it would keep showing the draft of its first render, and while a switch to
162
+ * another draft loads, `current()` already names the next one.
162
163
  */
163
164
  function useDraftScope() {
164
165
  const scope = React.useContext(DraftScopeContext);
165
166
  if (!scope) throw new Error("useDraftScope must be used inside a DraftScopeContext provider");
166
167
  return scope;
167
168
  }
169
+ /**
170
+ * The draft the page runtime's committed render shows, or null for Live: undefined outside it.
171
+ * A switch to another draft renders in a transition, so until it commits the studio keeps
172
+ * showing the draft it was in, while the scope already reads and writes the next one.
173
+ */
174
+ const ShownDraftContext = React.createContext(void 0);
168
175
  const noScope = () => null;
169
176
  const noSubscription = () => () => {};
177
+ /** The draft the render shows: the committed one in the page runtime, the scope's elsewhere. */
178
+ function useShownDraft(scope) {
179
+ const shown = React.use(ShownDraftContext);
180
+ const current = scope?.current ?? noScope;
181
+ const followed = shown === void 0 && scope ? scope.subscribe : noSubscription;
182
+ const draftId = React.useSyncExternalStore(followed, current, current);
183
+ return shown === void 0 ? draftId : shown;
184
+ }
170
185
  /** The draft the studio is in, or null for Live. The caller re-renders after every move. */
171
186
  function useCurrentDraftId() {
172
- const scope = useDraftScope();
173
- return React.useSyncExternalStore(scope.subscribe, scope.current, scope.current);
187
+ return useShownDraft(useDraftScope());
174
188
  }
175
189
  /** The draft scope and the draft it views, outside the studio too, where there is none. */
176
190
  function useOptionalDraftScope() {
177
191
  const $ = c(3);
178
192
  const scope = React.useContext(DraftScopeContext);
179
- const current = scope?.current ?? noScope;
180
- const draftId = React.useSyncExternalStore(scope?.subscribe ?? noSubscription, current, current);
181
- let t0;
182
- if ($[0] !== draftId || $[1] !== scope) {
183
- t0 = {
193
+ const t0 = useShownDraft(scope);
194
+ let t1;
195
+ if ($[0] !== scope || $[1] !== t0) {
196
+ t1 = {
184
197
  scope,
185
- draftId
198
+ draftId: t0
186
199
  };
187
- $[0] = draftId;
188
- $[1] = scope;
189
- $[2] = t0;
190
- } else t0 = $[2];
191
- return t0;
200
+ $[0] = scope;
201
+ $[1] = t0;
202
+ $[2] = t1;
203
+ } else t1 = $[2];
204
+ return t1;
192
205
  }
193
206
  /**
194
207
  * Follows the draft a browser URL names, for a studio mounted in a host application, whose
@@ -199,4 +212,4 @@ function followUrl(scope, href) {
199
212
  }
200
213
 
201
214
  //#endregion
202
- export { DraftScopeContext, createDraftScope, draftNamedBy, followUrl, useCurrentDraftId, useDraftScope, useOptionalDraftScope, withoutDraft };
215
+ export { DraftScopeContext, ShownDraftContext, createDraftScope, draftNamedBy, followUrl, useCurrentDraftId, useDraftScope, useOptionalDraftScope, withoutDraft };
@@ -2,11 +2,12 @@ import { useCurrentDraftId } from "./draft-scope.js";
2
2
  import { ViewLocaleContext } from "./view-locale-context.js";
3
3
  import { fetchRuntimeJson } from "../features/runtime/navigationTarget.js";
4
4
  import { collectFileIds } from "./normalized-data.js";
5
+ import { useSwitchHold } from "./view-switch.js";
5
6
  import { c } from "react/compiler-runtime";
6
7
  import * as React from "react";
7
8
  import { inScope, queryKeys, scopeOfKey } from "@camox/api-contract/query-keys";
8
9
  import { PATROLLER_IDS } from "@camox/api-contract/patrol";
9
- import { useQueries, useQuery, useSuspenseQuery } from "@tanstack/react-query";
10
+ import { useQueries, useQuery, useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
10
11
 
11
12
  //#region src/lib/studio-reads.ts
12
13
  function entry(definition) {
@@ -505,7 +506,7 @@ function useStudioCache() {
505
506
  }
506
507
  /**
507
508
  * The draft and locale the caller's render shows, which its reads name: the read hooks re-render
508
- * after a move to another draft, and a locale switch mounts the page afresh.
509
+ * after a move to another draft or locale, reading its keys.
509
510
  */
510
511
  function useShownTarget() {
511
512
  const $ = c(3);
@@ -548,7 +549,7 @@ function useRead(read) {
548
549
  * the locale the caller's render shows, unless `locale` names another.
549
550
  */
550
551
  function useReadQuery(read, t0) {
551
- const $ = c(13);
552
+ const $ = c(18);
552
553
  let t1;
553
554
  if ($[0] !== t0) {
554
555
  t1 = t0 === void 0 ? {} : t0;
@@ -558,6 +559,7 @@ function useReadQuery(read, t0) {
558
559
  const { enabled, select, locale } = t1;
559
560
  const shown = useShownTarget();
560
561
  const cache = useStudioCache();
562
+ const queryClient = useQueryClient();
561
563
  let t2;
562
564
  if ($[2] !== locale || $[3] !== shown) {
563
565
  t2 = locale ? {
@@ -577,24 +579,38 @@ function useReadQuery(read, t0) {
577
579
  $[7] = read;
578
580
  $[8] = t3;
579
581
  } else t3 = $[8];
582
+ const options = t3;
580
583
  let t4;
581
- if ($[9] !== enabled || $[10] !== select || $[11] !== t3) {
584
+ if ($[9] !== enabled || $[10] !== options || $[11] !== select) {
582
585
  t4 = {
583
- ...t3,
586
+ ...options,
584
587
  enabled,
585
588
  select
586
589
  };
587
590
  $[9] = enabled;
588
- $[10] = select;
589
- $[11] = t3;
591
+ $[10] = options;
592
+ $[11] = select;
590
593
  $[12] = t4;
591
594
  } else t4 = $[12];
592
- return useQuery(t4);
595
+ const result = useQuery(t4);
596
+ let t5;
597
+ if ($[13] !== enabled || $[14] !== options || $[15] !== queryClient || $[16] !== result) {
598
+ t5 = () => enabled !== false && result.isPending ? queryClient.fetchQuery(options) : null;
599
+ $[13] = enabled;
600
+ $[14] = options;
601
+ $[15] = queryClient;
602
+ $[16] = result;
603
+ $[17] = t5;
604
+ } else t5 = $[17];
605
+ const hold = useSwitchHold(t5);
606
+ if (hold) throw hold;
607
+ return result;
593
608
  }
594
609
  function useReadQueries(list, combine) {
595
- const $ = c(10);
610
+ const $ = c(13);
596
611
  const inDraft = useShownTarget();
597
612
  const cache = useStudioCache();
613
+ const queryClient = useQueryClient();
598
614
  let t0;
599
615
  if ($[0] !== cache || $[1] !== inDraft || $[2] !== list) {
600
616
  let t1;
@@ -610,17 +626,34 @@ function useReadQueries(list, combine) {
610
626
  $[2] = list;
611
627
  $[3] = t0;
612
628
  } else t0 = $[3];
629
+ const queries = t0;
613
630
  let t1;
614
- if ($[7] !== combine || $[8] !== t0) {
631
+ if ($[7] !== combine || $[8] !== queries) {
615
632
  t1 = {
616
- queries: t0,
633
+ queries,
617
634
  combine
618
635
  };
619
636
  $[7] = combine;
620
- $[8] = t0;
637
+ $[8] = queries;
621
638
  $[9] = t1;
622
639
  } else t1 = $[9];
623
- return useQueries(t1);
640
+ const combined = useQueries(t1);
641
+ let t2;
642
+ if ($[10] !== queries || $[11] !== queryClient) {
643
+ t2 = () => {
644
+ const loading = queries.filter((t3) => {
645
+ const { queryKey } = t3;
646
+ return (queryClient.getQueryState(queryKey)?.status ?? "pending") === "pending";
647
+ });
648
+ return loading.length ? Promise.all(loading.map((options) => queryClient.fetchQuery(options))) : null;
649
+ };
650
+ $[10] = queries;
651
+ $[11] = queryClient;
652
+ $[12] = t2;
653
+ } else t2 = $[12];
654
+ const hold = useSwitchHold(t2);
655
+ if (hold) throw hold;
656
+ return combined;
624
657
  }
625
658
 
626
659
  //#endregion
@@ -0,0 +1,64 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import * as React from "react";
3
+
4
+ //#region src/lib/view-switch.ts
5
+ const ViewSwitchesContext = React.createContext(null);
6
+ /**
7
+ * Set while a render switches to another view: the time after which it stops waiting for reads
8
+ * and commits with what it has. Null otherwise.
9
+ */
10
+ const ViewSwitchDeadlineContext = React.createContext(null);
11
+ /** How long a switch waits for the next view before showing it however far it got. */
12
+ const SWITCH_WAIT_MS = 1e4;
13
+ /** Prepares the studio's part of every switch with `preparer`, while mounted. */
14
+ function useViewPreparer(preparer) {
15
+ const $ = c(5);
16
+ const switches = React.use(ViewSwitchesContext);
17
+ const prepare = React.useEffectEvent(preparer);
18
+ let t0;
19
+ if ($[0] !== prepare || $[1] !== switches) {
20
+ t0 = () => switches?.prepare((next) => prepare(next));
21
+ $[0] = prepare;
22
+ $[1] = switches;
23
+ $[2] = t0;
24
+ } else t0 = $[2];
25
+ let t1;
26
+ if ($[3] !== switches) {
27
+ t1 = [switches];
28
+ $[3] = switches;
29
+ $[4] = t1;
30
+ } else t1 = $[4];
31
+ React.useEffect(t0, t1);
32
+ }
33
+ /**
34
+ * The last navigation started, settling once it shows: for the studio to say a switch it started,
35
+ * or one that followed what it did, is under way. Outside the page runtime, it settles at once.
36
+ */
37
+ function useViewShown() {
38
+ const $ = c(2);
39
+ const switches = React.use(ViewSwitchesContext);
40
+ let t0;
41
+ if ($[0] !== switches) {
42
+ t0 = () => switches?.shown() ?? Promise.resolve();
43
+ $[0] = switches;
44
+ $[1] = t0;
45
+ } else t0 = $[1];
46
+ return t0;
47
+ }
48
+ /**
49
+ * While a render switches views, a read still loading holds the switch back rather than show
50
+ * its loading state: the promise to suspend on until it loads or the switch stops waiting.
51
+ * Undefined when the render should show the read as it is.
52
+ */
53
+ function useSwitchHold(loading) {
54
+ const deadline = React.use(ViewSwitchDeadlineContext);
55
+ if (deadline === null) return void 0;
56
+ const left = deadline - Date.now();
57
+ if (left <= 0) return void 0;
58
+ const pending = loading();
59
+ if (!pending) return void 0;
60
+ return Promise.race([pending.catch(() => {}), new Promise((resolve) => setTimeout(resolve, left))]);
61
+ }
62
+
63
+ //#endregion
64
+ export { SWITCH_WAIT_MS, ViewSwitchDeadlineContext, ViewSwitchesContext, useSwitchHold, useViewPreparer, useViewShown };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.67.0";
2
+ var version = "0.69.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };