@valbuild/next 0.96.2 → 0.97.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 (44) hide show
  1. package/README.md +33 -0
  2. package/client/dist/valbuild-next-client.cjs.dev.js +29 -10
  3. package/client/dist/valbuild-next-client.cjs.prod.js +29 -10
  4. package/client/dist/valbuild-next-client.esm.js +29 -10
  5. package/dist/{ValNextProvider-26ef0c1c.cjs.dev.js → ValNextProvider-03a9f8fd.cjs.dev.js} +103 -25
  6. package/dist/ValNextProvider-6103cb74.cjs.js +7 -0
  7. package/dist/{ValNextProvider-b0d9fa24.cjs.prod.js → ValNextProvider-6103cb74.cjs.prod.js} +103 -25
  8. package/dist/{ValNextProvider-e163e127.esm.js → ValNextProvider-7302b8af.esm.js} +104 -26
  9. package/dist/ValOverlayContext-3c37e5a7.esm.js +251 -0
  10. package/dist/ValOverlayContext-c6f27a6d.cjs.dev.js +262 -0
  11. package/dist/ValOverlayContext-f7f45bc7.cjs.js +7 -0
  12. package/dist/ValOverlayContext-f7f45bc7.cjs.prod.js +262 -0
  13. package/dist/declarations/src/ValProvider.d.ts +1 -0
  14. package/dist/declarations/src/initVal.d.ts +25 -0
  15. package/dist/defineProperty-8951f469.cjs.prod.js +29 -0
  16. package/dist/defineProperty-cca5affa.esm.js +26 -0
  17. package/dist/defineProperty-f90345d7.cjs.dev.js +29 -0
  18. package/dist/{objectSpread2-3c87fb4f.cjs.prod.js → objectSpread2-13f847a9.cjs.prod.js} +2 -27
  19. package/dist/{objectSpread2-792eb2c2.cjs.dev.js → objectSpread2-58024783.cjs.dev.js} +2 -27
  20. package/dist/{objectSpread2-c1340c1c.esm.js → objectSpread2-60d1bd93.esm.js} +2 -25
  21. package/dist/{routeFromVal-ef8c304a.cjs.prod.js → routeFromVal-13c832b2.cjs.prod.js} +1 -1
  22. package/dist/{routeFromVal-748d2aec.esm.js → routeFromVal-8855a5cc.esm.js} +1 -1
  23. package/dist/{routeFromVal-8fdaa0d0.cjs.dev.js → routeFromVal-9b610e77.cjs.dev.js} +1 -1
  24. package/dist/valbuild-next.cjs.dev.js +46 -3
  25. package/dist/valbuild-next.cjs.prod.js +46 -3
  26. package/dist/valbuild-next.esm.js +46 -3
  27. package/dist/{asyncToGenerator-8e5c36c8.cjs.prod.js → version-0e6da9a7.cjs.prod.js} +10 -0
  28. package/dist/{asyncToGenerator-500f022f.esm.js → version-4d7b692c.esm.js} +10 -1
  29. package/dist/{asyncToGenerator-c3823d62.cjs.dev.js → version-c311d818.cjs.dev.js} +10 -0
  30. package/package.json +14 -8
  31. package/rsc/dist/valbuild-next-rsc.cjs.dev.js +35 -35
  32. package/rsc/dist/valbuild-next-rsc.cjs.prod.js +35 -35
  33. package/rsc/dist/valbuild-next-rsc.esm.js +4 -4
  34. package/server/dist/valbuild-next-server.cjs.dev.js +9 -9
  35. package/server/dist/valbuild-next-server.cjs.prod.js +9 -9
  36. package/server/dist/valbuild-next-server.esm.js +3 -3
  37. package/dist/ValNextProvider-b0d9fa24.cjs.js +0 -7
  38. package/dist/ValOverlayContext-6635a4d7.esm.js +0 -114
  39. package/dist/ValOverlayContext-942f1294.cjs.js +0 -7
  40. package/dist/ValOverlayContext-942f1294.cjs.prod.js +0 -125
  41. package/dist/ValOverlayContext-c82a4507.cjs.dev.js +0 -125
  42. package/dist/version-16f6b0ce.esm.js +0 -10
  43. package/dist/version-d034b2fc.cjs.dev.js +0 -12
  44. package/dist/version-d2061026.cjs.prod.js +0 -12
package/README.md CHANGED
@@ -333,6 +333,39 @@ import { s } from "./val.config";
333
333
  s.string().nullable(); // <- Schema<string | null>
334
334
  ```
335
335
 
336
+ ## Description
337
+
338
+ All schema types can be given a human-readable description with `.describe(text)`. Descriptions are shown in the Val editor UI as muted helper text under the field label, helping editors understand what a field is for without leaving the page.
339
+
340
+ ```ts
341
+ import { s } from "./val.config";
342
+
343
+ s.object({
344
+ name: s.string().describe("The author's full name"),
345
+ }).describe("Author of the blog post");
346
+ ```
347
+
348
+ For records, calling `.describe()` on the **key** schema labels the record keys in the editor (useful when the key is something like an email or slug that benefits from extra context), while calling it on the **value** schema describes the entry itself.
349
+
350
+ ```ts
351
+ s.record(
352
+ s.string().describe("Email"),
353
+ s.object({ name: s.string() }).describe("Author"),
354
+ );
355
+ ```
356
+
357
+ `.describe()` can be combined freely with other modifiers and is preserved through `.nullable()`, `.validate()`, `.minLength()`, etc.:
358
+
359
+ ```ts
360
+ s.string().describe("Slug").minLength(1).maxLength(64);
361
+ ```
362
+
363
+ Pass `null` to clear a previously set description (useful when extending a base schema):
364
+
365
+ ```ts
366
+ s.string().describe("Original").describe(null); // no description on the resulting schema
367
+ ```
368
+
336
369
  ## Array
337
370
 
338
371
  ```ts
@@ -6,11 +6,12 @@ require('client-only');
6
6
  var core = require('@valbuild/core');
7
7
  var stega = require('@valbuild/react/stega');
8
8
  var React = require('react');
9
- var ValOverlayContext = require('../../dist/ValOverlayContext-c82a4507.cjs.dev.js');
10
- var routeFromVal = require('../../dist/routeFromVal-8fdaa0d0.cjs.dev.js');
9
+ var ValOverlayContext = require('../../dist/ValOverlayContext-c6f27a6d.cjs.dev.js');
10
+ var routeFromVal = require('../../dist/routeFromVal-9b610e77.cjs.dev.js');
11
11
  require('../../dist/createForOfIteratorHelper-0445603c.cjs.dev.js');
12
12
  require('../../dist/unsupportedIterableToArray-c8ab77c9.cjs.dev.js');
13
- require('../../dist/objectSpread2-792eb2c2.cjs.dev.js');
13
+ require('../../dist/objectSpread2-58024783.cjs.dev.js');
14
+ require('../../dist/defineProperty-f90345d7.cjs.dev.js');
14
15
  require('../../dist/slicedToArray-44036a76.cjs.dev.js');
15
16
  require('@valbuild/shared/internal');
16
17
 
@@ -31,6 +32,23 @@ function useValStega(selector) {
31
32
  }, store ? store.getServerSnapshot(moduleIds) : function () {
32
33
  return;
33
34
  });
35
+ // Suspense gate. `suspend` is false during SSR and hydration (so the static
36
+ // committed source is rendered, matching the server HTML exactly) and is
37
+ // activated by ValProvider after hydration — inside a transition — when the
38
+ // `suspend` prop is set AND the Val Enable cookie is present (checked
39
+ // client-side; the server store is never populated). It never deactivates.
40
+ // The production path (no cookie) skips the call entirely. The
41
+ // `draftMode !== false` check is a release valve: with draft mode off the
42
+ // store never receives source updates, so waitForLoad could only ever
43
+ // resolve via its timeout — and would then re-suspend on every subsequent
44
+ // render since the resolved promise is evicted from the cache. draftMode is
45
+ // null until the first /draft/stat poll resolves; null -> true keeps
46
+ // suspending, -> false only unblocks, and false -> true happens only on an
47
+ // explicit draft-mode enable which already refreshes the route.
48
+ // React.use is allowed inside conditionals — it is not a hook.
49
+ if (valOverlayContext.suspend && valOverlayContext.draftMode !== false && store && !store.hasAllLoaded(moduleIds)) {
50
+ React__default["default"].use(store.waitForLoad(moduleIds));
51
+ }
34
52
  return stega.stegaEncode(selector, {
35
53
  disabled: !valOverlayContext.draftMode,
36
54
  getModule: function getModule(moduleId) {
@@ -44,17 +62,18 @@ function resolveParams(params) {
44
62
  if (!params) {
45
63
  return null;
46
64
  }
47
- var resolvedParams = "then" in params ? undefined : params;
48
65
  if ("then" in params) {
49
- if ("use" in React__default["default"]) {
50
- // This feels fairly safe: use should be possible to use inside if (?) and the if should most likely
51
- resolvedParams = React__default["default"].use(params);
52
- } else {
53
- console.error("Val: useValRoute params argument was promise, but the React.use hook is unavailable. Please resolve the promise before passing it to useValRoute (or upgrade to React 19+).");
66
+ // Defensive guard: peerDependencies declare React >=19, but if a consumer
67
+ // somehow ends up on React 18 with a promise params arg, surface a
68
+ // diagnosable error instead of a cryptic `TypeError: React.use is not a
69
+ // function`. Callers treat null as the error sentinel.
70
+ if (!("use" in React__default["default"])) {
71
+ console.error("Val: useValRoute received a Promise params argument but React.use is unavailable. Upgrade to React 19+ or pre-resolve the promise before passing it.");
54
72
  return null;
55
73
  }
74
+ return React__default["default"].use(params);
56
75
  }
57
- return resolvedParams;
76
+ return params;
58
77
  }
59
78
  function useValRouteStega(selector, params) {
60
79
  var val = useValStega(selector);
@@ -6,11 +6,12 @@ require('client-only');
6
6
  var core = require('@valbuild/core');
7
7
  var stega = require('@valbuild/react/stega');
8
8
  var React = require('react');
9
- var ValOverlayContext = require('../../dist/ValOverlayContext-942f1294.cjs.prod.js');
10
- var routeFromVal = require('../../dist/routeFromVal-ef8c304a.cjs.prod.js');
9
+ var ValOverlayContext = require('../../dist/ValOverlayContext-f7f45bc7.cjs.prod.js');
10
+ var routeFromVal = require('../../dist/routeFromVal-13c832b2.cjs.prod.js');
11
11
  require('../../dist/createForOfIteratorHelper-d4afcad8.cjs.prod.js');
12
12
  require('../../dist/unsupportedIterableToArray-0d2087a2.cjs.prod.js');
13
- require('../../dist/objectSpread2-3c87fb4f.cjs.prod.js');
13
+ require('../../dist/objectSpread2-13f847a9.cjs.prod.js');
14
+ require('../../dist/defineProperty-8951f469.cjs.prod.js');
14
15
  require('../../dist/slicedToArray-ce613de6.cjs.prod.js');
15
16
  require('@valbuild/shared/internal');
16
17
 
@@ -31,6 +32,23 @@ function useValStega(selector) {
31
32
  }, store ? store.getServerSnapshot(moduleIds) : function () {
32
33
  return;
33
34
  });
35
+ // Suspense gate. `suspend` is false during SSR and hydration (so the static
36
+ // committed source is rendered, matching the server HTML exactly) and is
37
+ // activated by ValProvider after hydration — inside a transition — when the
38
+ // `suspend` prop is set AND the Val Enable cookie is present (checked
39
+ // client-side; the server store is never populated). It never deactivates.
40
+ // The production path (no cookie) skips the call entirely. The
41
+ // `draftMode !== false` check is a release valve: with draft mode off the
42
+ // store never receives source updates, so waitForLoad could only ever
43
+ // resolve via its timeout — and would then re-suspend on every subsequent
44
+ // render since the resolved promise is evicted from the cache. draftMode is
45
+ // null until the first /draft/stat poll resolves; null -> true keeps
46
+ // suspending, -> false only unblocks, and false -> true happens only on an
47
+ // explicit draft-mode enable which already refreshes the route.
48
+ // React.use is allowed inside conditionals — it is not a hook.
49
+ if (valOverlayContext.suspend && valOverlayContext.draftMode !== false && store && !store.hasAllLoaded(moduleIds)) {
50
+ React__default["default"].use(store.waitForLoad(moduleIds));
51
+ }
34
52
  return stega.stegaEncode(selector, {
35
53
  disabled: !valOverlayContext.draftMode,
36
54
  getModule: function getModule(moduleId) {
@@ -44,17 +62,18 @@ function resolveParams(params) {
44
62
  if (!params) {
45
63
  return null;
46
64
  }
47
- var resolvedParams = "then" in params ? undefined : params;
48
65
  if ("then" in params) {
49
- if ("use" in React__default["default"]) {
50
- // This feels fairly safe: use should be possible to use inside if (?) and the if should most likely
51
- resolvedParams = React__default["default"].use(params);
52
- } else {
53
- console.error("Val: useValRoute params argument was promise, but the React.use hook is unavailable. Please resolve the promise before passing it to useValRoute (or upgrade to React 19+).");
66
+ // Defensive guard: peerDependencies declare React >=19, but if a consumer
67
+ // somehow ends up on React 18 with a promise params arg, surface a
68
+ // diagnosable error instead of a cryptic `TypeError: React.use is not a
69
+ // function`. Callers treat null as the error sentinel.
70
+ if (!("use" in React__default["default"])) {
71
+ console.error("Val: useValRoute received a Promise params argument but React.use is unavailable. Upgrade to React 19+ or pre-resolve the promise before passing it.");
54
72
  return null;
55
73
  }
74
+ return React__default["default"].use(params);
56
75
  }
57
- return resolvedParams;
76
+ return params;
58
77
  }
59
78
  function useValRouteStega(selector, params) {
60
79
  var val = useValStega(selector);
@@ -2,11 +2,12 @@ import 'client-only';
2
2
  import { Internal } from '@valbuild/core';
3
3
  import { getModuleIds, stegaEncode } from '@valbuild/react/stega';
4
4
  import React from 'react';
5
- import { useValOverlayContext } from '../../dist/ValOverlayContext-6635a4d7.esm.js';
6
- import { i as initValRouteFromVal, g as getValRouteUrlFromVal } from '../../dist/routeFromVal-748d2aec.esm.js';
5
+ import { useValOverlayContext } from '../../dist/ValOverlayContext-3c37e5a7.esm.js';
6
+ import { i as initValRouteFromVal, g as getValRouteUrlFromVal } from '../../dist/routeFromVal-8855a5cc.esm.js';
7
7
  import '../../dist/createForOfIteratorHelper-5758a730.esm.js';
8
8
  import '../../dist/unsupportedIterableToArray-5baabfdc.esm.js';
9
- import '../../dist/objectSpread2-c1340c1c.esm.js';
9
+ import '../../dist/objectSpread2-60d1bd93.esm.js';
10
+ import '../../dist/defineProperty-cca5affa.esm.js';
10
11
  import '../../dist/slicedToArray-aa291011.esm.js';
11
12
  import '@valbuild/shared/internal';
12
13
 
@@ -23,6 +24,23 @@ function useValStega(selector) {
23
24
  }, store ? store.getServerSnapshot(moduleIds) : function () {
24
25
  return;
25
26
  });
27
+ // Suspense gate. `suspend` is false during SSR and hydration (so the static
28
+ // committed source is rendered, matching the server HTML exactly) and is
29
+ // activated by ValProvider after hydration — inside a transition — when the
30
+ // `suspend` prop is set AND the Val Enable cookie is present (checked
31
+ // client-side; the server store is never populated). It never deactivates.
32
+ // The production path (no cookie) skips the call entirely. The
33
+ // `draftMode !== false` check is a release valve: with draft mode off the
34
+ // store never receives source updates, so waitForLoad could only ever
35
+ // resolve via its timeout — and would then re-suspend on every subsequent
36
+ // render since the resolved promise is evicted from the cache. draftMode is
37
+ // null until the first /draft/stat poll resolves; null -> true keeps
38
+ // suspending, -> false only unblocks, and false -> true happens only on an
39
+ // explicit draft-mode enable which already refreshes the route.
40
+ // React.use is allowed inside conditionals — it is not a hook.
41
+ if (valOverlayContext.suspend && valOverlayContext.draftMode !== false && store && !store.hasAllLoaded(moduleIds)) {
42
+ React.use(store.waitForLoad(moduleIds));
43
+ }
26
44
  return stegaEncode(selector, {
27
45
  disabled: !valOverlayContext.draftMode,
28
46
  getModule: function getModule(moduleId) {
@@ -36,17 +54,18 @@ function resolveParams(params) {
36
54
  if (!params) {
37
55
  return null;
38
56
  }
39
- var resolvedParams = "then" in params ? undefined : params;
40
57
  if ("then" in params) {
41
- if ("use" in React) {
42
- // This feels fairly safe: use should be possible to use inside if (?) and the if should most likely
43
- resolvedParams = React.use(params);
44
- } else {
45
- console.error("Val: useValRoute params argument was promise, but the React.use hook is unavailable. Please resolve the promise before passing it to useValRoute (or upgrade to React 19+).");
58
+ // Defensive guard: peerDependencies declare React >=19, but if a consumer
59
+ // somehow ends up on React 18 with a promise params arg, surface a
60
+ // diagnosable error instead of a cryptic `TypeError: React.use is not a
61
+ // function`. Callers treat null as the error sentinel.
62
+ if (!("use" in React)) {
63
+ console.error("Val: useValRoute received a Promise params argument but React.use is unavailable. Upgrade to React 19+ or pre-resolve the promise before passing it.");
46
64
  return null;
47
65
  }
66
+ return React.use(params);
48
67
  }
49
- return resolvedParams;
68
+ return params;
50
69
  }
51
70
  function useValRouteStega(selector, params) {
52
71
  var val = useValStega(selector);
@@ -4,18 +4,20 @@
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var slicedToArray = require('./slicedToArray-44036a76.cjs.dev.js');
7
- var objectSpread2 = require('./objectSpread2-792eb2c2.cjs.dev.js');
7
+ var objectSpread2 = require('./objectSpread2-58024783.cjs.dev.js');
8
8
  var core = require('@valbuild/core');
9
9
  var ui = require('@valbuild/ui');
10
10
  var navigation = require('next/navigation');
11
11
  var Script = require('next/script');
12
12
  var React = require('react');
13
- var ValOverlayContext = require('./ValOverlayContext-c82a4507.cjs.dev.js');
13
+ var ValOverlayContext = require('./ValOverlayContext-c6f27a6d.cjs.dev.js');
14
14
  var stega = require('@valbuild/react/stega');
15
15
  var internal = require('@valbuild/shared/internal');
16
16
  var cssUtils = require('./cssUtils-9c11102f.cjs.dev.js');
17
+ var createForOfIteratorHelper = require('./createForOfIteratorHelper-0445603c.cjs.dev.js');
17
18
  var jsxRuntime = require('react/jsx-runtime');
18
19
  require('./unsupportedIterableToArray-c8ab77c9.cjs.dev.js');
20
+ require('./defineProperty-f90345d7.cjs.dev.js');
19
21
 
20
22
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
21
23
 
@@ -41,6 +43,39 @@ function initSessionTheme(config) {
41
43
  return theme;
42
44
  }
43
45
 
46
+ /**
47
+ * Returns true if the Val Enable cookie is set to "true" in the given cookie
48
+ * string (typically `document.cookie`).
49
+ *
50
+ * Exact-token match: a naive `includes("val_enable=true")` would also match
51
+ * unrelated cookies like `xval_enable=true`. The server sets the cookie to
52
+ * "false" (rather than deleting it) on disable, so the value must be checked
53
+ * too.
54
+ */
55
+ function hasValEnableCookie(cookieString) {
56
+ var _iterator = createForOfIteratorHelper._createForOfIteratorHelper(cookieString.split(";")),
57
+ _step;
58
+ try {
59
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
60
+ var part = _step.value;
61
+ var eq = part.indexOf("=");
62
+ if (eq === -1) {
63
+ continue;
64
+ }
65
+ var name = part.slice(0, eq).trim();
66
+ var value = part.slice(eq + 1).trim();
67
+ if (name === core.Internal.VAL_ENABLE_COOKIE_NAME && value === "true") {
68
+ return true;
69
+ }
70
+ }
71
+ } catch (err) {
72
+ _iterator.e(err);
73
+ } finally {
74
+ _iterator.f();
75
+ }
76
+ return false;
77
+ }
78
+
44
79
  var ValNextProvider = function ValNextProvider(props) {
45
80
  // TODO: use config:
46
81
  var route = "/api/val";
@@ -54,27 +89,40 @@ var ValNextProvider = function ValNextProvider(props) {
54
89
  var valStore = React__default["default"].useMemo(function () {
55
90
  return new ValOverlayContext.ValExternalStore();
56
91
  }, []);
57
- var _React$useState = React__default["default"].useState(),
92
+ // Whether useValStega should actually suspend. False during SSR and the
93
+ // hydration render — the server store is never populated (draft data
94
+ // arrives via browser CustomEvents only), so suspending there would just
95
+ // stall into the waitForLoad timeout, and hydration must render the static
96
+ // source so it matches the server HTML exactly. Activated post-hydration
97
+ // (in an effect, only when the Val Enable cookie is present) inside a
98
+ // transition: React keeps the static content visible while hooks suspend
99
+ // and then swaps to draft data as a normal update — no Suspense fallback
100
+ // flash and no hydration mismatch.
101
+ var _React$useState = React__default["default"].useState(false),
58
102
  _React$useState2 = slicedToArray._slicedToArray(_React$useState, 2),
59
- mountOverlay = _React$useState2[0],
60
- setMountOverlay = _React$useState2[1];
61
- var _React$useState3 = React__default["default"].useState(null),
103
+ suspendActive = _React$useState2[0],
104
+ setSuspendActive = _React$useState2[1];
105
+ var _React$useState3 = React__default["default"].useState(),
62
106
  _React$useState4 = slicedToArray._slicedToArray(_React$useState3, 2),
63
- draftMode = _React$useState4[0],
64
- setDraftMode = _React$useState4[1];
65
- var _React$useState5 = React__default["default"].useState(false),
107
+ mountOverlay = _React$useState4[0],
108
+ setMountOverlay = _React$useState4[1];
109
+ var _React$useState5 = React__default["default"].useState(null),
66
110
  _React$useState6 = slicedToArray._slicedToArray(_React$useState5, 2),
67
- spaReady = _React$useState6[0],
68
- setSpaReady = _React$useState6[1]; // TODO: consider removing spaReady - it is not used? If we remove, clean up the custom events that send the message too...
111
+ draftMode = _React$useState6[0],
112
+ setDraftMode = _React$useState6[1];
113
+ var _React$useState7 = React__default["default"].useState(false),
114
+ _React$useState8 = slicedToArray._slicedToArray(_React$useState7, 2),
115
+ spaReady = _React$useState8[0],
116
+ setSpaReady = _React$useState8[1]; // TODO: consider removing spaReady - it is not used? If we remove, clean up the custom events that send the message too...
69
117
  var router = navigation.useRouter();
70
118
  var _React$useTransition = React__default["default"].useTransition(),
71
119
  _React$useTransition2 = slicedToArray._slicedToArray(_React$useTransition, 2),
72
120
  startTransition = _React$useTransition2[1];
73
121
  var rerenderCounterRef = React__default["default"].useRef(0);
74
- var _React$useState7 = React__default["default"].useState(null),
75
- _React$useState8 = slicedToArray._slicedToArray(_React$useState7, 2),
76
- iframeSrc = _React$useState8[0],
77
- setIframeSrc = _React$useState8[1];
122
+ var _React$useState9 = React__default["default"].useState(null),
123
+ _React$useState0 = slicedToArray._slicedToArray(_React$useState9, 2),
124
+ iframeSrc = _React$useState0[0],
125
+ setIframeSrc = _React$useState0[1];
78
126
  var pathname = navigation.usePathname();
79
127
  React.useEffect(function () {
80
128
  window.dispatchEvent(new CustomEvent("val-provider:pathname", {
@@ -91,8 +139,21 @@ var ValNextProvider = function ValNextProvider(props) {
91
139
  setMountOverlay(false);
92
140
  return;
93
141
  }
94
- setMountOverlay(document.cookie.includes("".concat(core.Internal.VAL_ENABLE_COOKIE_NAME, "=true")));
142
+ setMountOverlay(hasValEnableCookie(document.cookie));
95
143
  }, []);
144
+ React__default["default"].useEffect(function () {
145
+ // Activate the Suspense gate after hydration. Inside a transition so
146
+ // already-visible (static) content stays on screen while useValStega
147
+ // suspends — no fallback flash — and the swap to draft data commits as a
148
+ // normal update instead of a hydration mismatch. Never deactivated:
149
+ // components must not stop suspending across renders (the draft-mode-off
150
+ // release valve lives in useValStega instead).
151
+ if (props.suspend && shouldEnableVal()) {
152
+ startTransition(function () {
153
+ setSuspendActive(true);
154
+ });
155
+ }
156
+ }, [props.suspend]);
96
157
  React__default["default"].useEffect(function () {
97
158
  if (!mountOverlay) {
98
159
  return;
@@ -179,7 +240,11 @@ var ValNextProvider = function ValNextProvider(props) {
179
240
  return;
180
241
  }
181
242
  if (res.status === 401) {
182
- // ignore when not authorized
243
+ // Not authorized (e.g. stale Val Enable cookie after the session
244
+ // expired): treat draft mode as off so useValStega's Suspense gate
245
+ // is released instead of leaving draftMode stuck at null and
246
+ // re-suspending into the waitForLoad timeout.
247
+ setDraftMode(false);
183
248
  return;
184
249
  }
185
250
  if (res.status !== 200) {
@@ -275,10 +340,10 @@ var ValNextProvider = function ValNextProvider(props) {
275
340
  window.dispatchEvent(new CustomEvent("val-append-overlay"));
276
341
  }
277
342
  });
278
- var _React$useState9 = React__default["default"].useState(null),
279
- _React$useState0 = slicedToArray._slicedToArray(_React$useState9, 2),
280
- dropZone = _React$useState0[0],
281
- setDropZone = _React$useState0[1];
343
+ var _React$useState1 = React__default["default"].useState(null),
344
+ _React$useState10 = slicedToArray._slicedToArray(_React$useState1, 2),
345
+ dropZone = _React$useState10[0],
346
+ setDropZone = _React$useState10[1];
282
347
  React__default["default"].useEffect(function () {
283
348
  var storedDropZone = localStorage.getItem("val-menu-drop-zone-default");
284
349
  if (storedDropZone) {
@@ -291,10 +356,10 @@ var ValNextProvider = function ValNextProvider(props) {
291
356
  var initTheme = React__default["default"].useMemo(function () {
292
357
  return initSessionTheme(props.config);
293
358
  }, [props.config]);
294
- var _React$useState1 = React__default["default"].useState(false),
295
- _React$useState10 = slicedToArray._slicedToArray(_React$useState1, 2),
296
- spaLoaded = _React$useState10[0],
297
- setSpaLoaded = _React$useState10[1];
359
+ var _React$useState11 = React__default["default"].useState(false),
360
+ _React$useState12 = slicedToArray._slicedToArray(_React$useState11, 2),
361
+ spaLoaded = _React$useState12[0],
362
+ setSpaLoaded = _React$useState12[1];
298
363
  React__default["default"].useEffect(function () {
299
364
  var listener = function listener() {
300
365
  setSpaLoaded(true);
@@ -334,6 +399,7 @@ var ValNextProvider = function ValNextProvider(props) {
334
399
  }, [cssUtils.valPrefixedClass]);
335
400
  return /*#__PURE__*/jsxRuntime.jsxs(ValOverlayContext.ValOverlayProvider, {
336
401
  draftMode: draftMode,
402
+ suspend: suspendActive,
337
403
  store: valStore,
338
404
  children: [props.children, dropZone !== null && !spaLoaded && mountOverlay && initTheme !== null && /*#__PURE__*/jsxRuntime.jsxs(React__default["default"].Fragment, {
339
405
  children: [/*#__PURE__*/jsxRuntime.jsx("style", {
@@ -447,6 +513,18 @@ function isValStudioPath(pathname) {
447
513
  return pathname.startsWith("/val");
448
514
  }
449
515
 
516
+ // Same guards as the mountOverlay effect: suspending where the overlay can't
517
+ // mount would only ever stall into the waitForLoad timeout. Browser-only.
518
+ function shouldEnableVal() {
519
+ if (location.search === "?message_onready=true") {
520
+ return false;
521
+ }
522
+ if (isValStudioPath(location.pathname)) {
523
+ return false;
524
+ }
525
+ return hasValEnableCookie(document.cookie);
526
+ }
527
+
450
528
  // function ValIcon() {
451
529
  // return (
452
530
  // <svg
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./ValNextProvider-6103cb74.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./ValNextProvider-6103cb74.cjs.dev.js");
7
+ }