@plasmicapp/react-web 1.0.37 → 1.0.39

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.
@@ -25,6 +25,10 @@ export declare function getStateSpecInPlasmicProxy(obj: any, path: ObjectPath):
25
25
  isImplicitStateArray: boolean;
26
26
  } | undefined;
27
27
  export declare function getCurrentInitialValue(obj: any, path: ObjectPath): any;
28
+ /** Whether the runtime guard has detected instability in this initializer.
29
+ * Canvas edits clear the diagnostic when the initializer hash changes.
30
+ */
31
+ export declare function hasUnstableStateInitializer(obj: any, path: ObjectPath): boolean;
28
32
  export declare function resetToInitialValue(obj: any, path: ObjectPath): void;
29
33
  export declare function shallowEqual<T>(a1: T[], a2: T[]): boolean;
30
34
  /**
@@ -1,4 +1,4 @@
1
1
  export { default as get } from "dlv";
2
- export { generateOnMutateForSpec, generateStateOnChangeProp, generateStateOnChangePropForCodeComponents, generateStateValueProp, getCurrentInitialValue, getStateCellsInPlasmicProxy, getStateSpecInPlasmicProxy, initializeCodeComponentStates, initializePlasmicStates, is$StateProxy, isPlasmicStateProxy, resetToInitialValue, set, } from "./helpers";
2
+ export { generateOnMutateForSpec, generateStateOnChangeProp, generateStateOnChangePropForCodeComponents, generateStateValueProp, getCurrentInitialValue, getStateCellsInPlasmicProxy, getStateSpecInPlasmicProxy, hasUnstableStateInitializer, initializeCodeComponentStates, initializePlasmicStates, is$StateProxy, isPlasmicStateProxy, resetToInitialValue, set, } from "./helpers";
3
3
  export { $State, $StateSpec, InitFunc } from "./types";
4
4
  export { useDollarState } from "./valtio";
@@ -46,22 +46,20 @@ export interface StateCell<T> {
46
46
  node: StateSpecNode<any>;
47
47
  path: ObjectPath;
48
48
  initFunc?: InitFunc<T>;
49
- listeners: (() => void)[];
50
49
  initFuncHash: string;
51
50
  overrideEnv?: NoUndefinedField<DollarStateEnv>;
51
+ pendingInit?: boolean;
52
+ unsettledResetCount?: number;
53
+ rejectedInitProbe?: {
54
+ value: T;
55
+ };
56
+ warnedUnstableInitFunc?: boolean;
52
57
  }
53
58
  export interface Internal$State {
54
- registrationsQueue: {
55
- node: StateSpecNode<any>;
56
- path: ObjectPath;
57
- f: InitFunc<any>;
58
- overrideEnv?: NoUndefinedField<DollarStateEnv>;
59
- }[];
60
59
  stateValues: Record<string, any>;
61
60
  env: NoUndefinedField<DollarStateEnv>;
62
61
  rootSpecTree: StateSpecNode<any>;
63
62
  specTreeLeaves: StateSpecNode<any>[];
64
- specs: $StateSpec<any>[];
65
63
  stateInitializationEnv: {
66
64
  stack: string[];
67
65
  visited: Set<string>;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasmicapp/react-web",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "Runtime library for rendering Plasmic-generated React components — variants, slots, overrides, and styling.",
5
5
  "homepage": "https://www.plasmic.app",
6
6
  "repository": {
@@ -102,13 +102,13 @@
102
102
  "clone": "^2.1.2",
103
103
  "dlv": "^1.1.3",
104
104
  "valtio": "^1.6.4",
105
- "@plasmicapp/auth-react": "0.0.33",
106
- "@plasmicapp/data-sources": "1.0.28",
107
- "@plasmicapp/data-sources-context": "0.1.25",
108
- "@plasmicapp/host": "2.0.18",
109
- "@plasmicapp/loader-splits": "1.0.78",
110
- "@plasmicapp/prepass": "1.0.29",
111
- "@plasmicapp/query": "0.1.87"
105
+ "@plasmicapp/auth-react": "0.0.34",
106
+ "@plasmicapp/data-sources": "1.0.29",
107
+ "@plasmicapp/data-sources-context": "0.1.26",
108
+ "@plasmicapp/host": "2.0.19",
109
+ "@plasmicapp/loader-splits": "1.0.79",
110
+ "@plasmicapp/prepass": "1.0.30",
111
+ "@plasmicapp/query": "0.1.88"
112
112
  },
113
113
  "devDependencies": {
114
114
  "@babel/core": "^7.29.0",
@@ -121,11 +121,10 @@
121
121
  "@rollup/plugin-commonjs": "^25.0.2",
122
122
  "@rollup/plugin-json": "^6.1.0",
123
123
  "@rollup/plugin-node-resolve": "^15.1.0",
124
- "@types/classnames": "^2.3.4",
125
124
  "@types/clone": "^2.1.4",
126
125
  "@types/dlv": "^1.1.5",
127
- "@types/react": "^18",
128
- "@types/react-dom": "^18",
126
+ "@types/react": "18.3.27",
127
+ "@types/react-dom": "18.3.7",
129
128
  "react": "18.3.1",
130
129
  "react-dom": "18.3.1",
131
130
  "rollup": "^3.26.1",
@@ -1110,7 +1110,6 @@ function ensureStateCell(target, property, path, node) {
1110
1110
  var stateCell = proxyObjToStateCell.get(target);
1111
1111
  if (!(property in stateCell)) {
1112
1112
  stateCell[property] = {
1113
- listeners: [],
1114
1113
  initialValue: UNINITIALIZED,
1115
1114
  path: path,
1116
1115
  node: node,
@@ -1168,7 +1167,6 @@ function subscribeToValtio($$state, statePath, node) {
1168
1167
  function initializeStateValue($$state, initialStateCell, proxyRoot) {
1169
1168
  var _a;
1170
1169
  var initialStateName = initialStateCell.node.getSpec().path;
1171
- var stateAccess = new Set();
1172
1170
  $$state.stateInitializationEnv.visited.add(initialStateName);
1173
1171
  $$state.stateInitializationEnv.stack.push(initialStateName);
1174
1172
  var $state = create$StateProxy($$state, function (internalStateCell) { return ({
@@ -1190,7 +1188,6 @@ function initializeStateValue($$state, initialStateCell, proxyRoot) {
1190
1188
  throw new UnknownError("Internal error: cycle not found");
1191
1189
  }
1192
1190
  var stateCell = getStateCellFrom$StateRoot(proxyRoot, internalStateCell.path);
1193
- stateAccess.add({ stateCell: stateCell });
1194
1191
  if (spec.valueProp) {
1195
1192
  return $$state.env.$props[spec.valueProp];
1196
1193
  }
@@ -1203,14 +1200,6 @@ function initializeStateValue($$state, initialStateCell, proxyRoot) {
1203
1200
  throw new InvalidOperation("Cannot update state values during initialization");
1204
1201
  },
1205
1202
  }); });
1206
- stateAccess.forEach(function (_a) {
1207
- var stateCell = _a.stateCell;
1208
- stateCell.listeners.push(function () {
1209
- var _a;
1210
- var newValue = invokeInitFunc(initialStateCell.node.getSpec().initFunc, __assign({ $state: $state }, ((_a = initialStateCell.overrideEnv) !== null && _a !== void 0 ? _a : $$state.env)));
1211
- set(proxyRoot, initialStateCell.path, newValue);
1212
- });
1213
- });
1214
1203
  var initialValue = invokeInitFunc(initialStateCell.initFunc, __assign({ $state: $state }, ((_a = initialStateCell.overrideEnv) !== null && _a !== void 0 ? _a : $$state.env)));
1215
1204
  var initialSpec = initialStateCell.node.getSpec();
1216
1205
  // Try to clone initialValue. It can fail if it's a PlasmicUndefinedDataProxy
@@ -1395,6 +1384,83 @@ function extractDollarStateParametersBackwardCompatible() {
1395
1384
  function invokeInitFunc(initFunc, env) {
1396
1385
  return initFunc(env);
1397
1386
  }
1387
+ function initFuncEnv($$state, stateCell, $state) {
1388
+ var _a;
1389
+ return __assign({ $state: $state }, ((_a = stateCell.overrideEnv) !== null && _a !== void 0 ? _a : $$state.env));
1390
+ }
1391
+ // Pure check with no effect on the reset budget; the layout scan decides.
1392
+ function initValueChanged($$state, stateCell, $state) {
1393
+ try {
1394
+ return !deepEqual(invokeInitFunc(stateCell.initFunc, initFuncEnv($$state, stateCell, $state)), stateCell.initialValue);
1395
+ }
1396
+ catch (_a) {
1397
+ return false;
1398
+ }
1399
+ }
1400
+ // Bound consecutive resets without a settled evaluation, even on slow renders.
1401
+ var MAX_UNSETTLED_RESETS = 5;
1402
+ function warnUnstableInitFunc(stateCell, reason) {
1403
+ if (stateCell.warnedUnstableInitFunc) {
1404
+ return;
1405
+ }
1406
+ stateCell.warnedUnstableInitFunc = true;
1407
+ console.warn("Plasmic: the initial value of state \"".concat(stateCell.path.join("."), "\" ").concat(reason, ", so it is kept at its current value instead of being reset. To set a random or time-based value, run an interaction from a Side Effect component instead."));
1408
+ }
1409
+ /**
1410
+ * Whether `stateCell` should be reset to what `initFunc` now returns. An
1411
+ * initFunc that returns a new value every time it runs would reset on every
1412
+ * render, and each reset renders again, so the loop never ends. We refuse to
1413
+ * reset in two cases:
1414
+ *
1415
+ * - Two back-to-back calls disagree, indicating an unstable initializer.
1416
+ * - Too many resets occur without a settled evaluation. This also catches
1417
+ * values that are stable within a render but drift between renders.
1418
+ *
1419
+ * This is a circuit breaker, not a proof of determinism: legitimate feedback
1420
+ * chains can also exceed the budget, and unstable functions can return equal
1421
+ * values by chance. Initializers must be pure and deterministic for fixed inputs.
1422
+ *
1423
+ * Rejected probes never change the installed initial value used by preview
1424
+ * reset. A rejected value that repeats on a later render can reopen the budget.
1425
+ */
1426
+ function shouldReInitialize(stateCell, initFunc, env) {
1427
+ var _a;
1428
+ var newInit;
1429
+ var repeats;
1430
+ try {
1431
+ newInit = invokeInitFunc(initFunc, env);
1432
+ if (deepEqual(newInit, stateCell.initialValue)) {
1433
+ stateCell.unsettledResetCount = undefined;
1434
+ stateCell.rejectedInitProbe = undefined;
1435
+ return false;
1436
+ }
1437
+ repeats = deepEqual(invokeInitFunc(initFunc, env), newInit);
1438
+ }
1439
+ catch (_b) {
1440
+ // initFunc can throw, e.g. if it tries to access loading $queries. Swallow here
1441
+ // since we only care whether the init value changed, not error handling.
1442
+ return false;
1443
+ }
1444
+ var reason;
1445
+ if (!repeats) {
1446
+ reason = "is not deterministic";
1447
+ }
1448
+ else {
1449
+ var rejectedInitProbe = stateCell.rejectedInitProbe;
1450
+ var reopened = rejectedInitProbe && deepEqual(newInit, rejectedInitProbe.value);
1451
+ stateCell.unsettledResetCount = reopened
1452
+ ? 1
1453
+ : ((_a = stateCell.unsettledResetCount) !== null && _a !== void 0 ? _a : 0) + 1;
1454
+ if (stateCell.unsettledResetCount > MAX_UNSETTLED_RESETS) {
1455
+ reason = "keeps changing";
1456
+ }
1457
+ }
1458
+ stateCell.rejectedInitProbe = reason ? { value: newInit } : undefined;
1459
+ if (reason) {
1460
+ warnUnstableInitFunc(stateCell, reason);
1461
+ }
1462
+ return !reason;
1463
+ }
1398
1464
  function useDollarState(specs) {
1399
1465
  var rest = [];
1400
1466
  for (var _i = 1; _i < arguments.length; _i++) {
@@ -1402,6 +1468,10 @@ function useDollarState(specs) {
1402
1468
  }
1403
1469
  var _a = extractDollarStateParametersBackwardCompatible.apply(void 0, __spreadArray([], __read(rest), false)), env = _a.env, opts = _a.opts;
1404
1470
  var _b = __read(React__default.useState(), 2), setState = _b[1];
1471
+ // Set for the whole render pass and cleared by the layout effect, which applies
1472
+ // registrations. One that arrives outside a render must schedule a render to be applied.
1473
+ var rendering = React__default.useRef(false);
1474
+ rendering.current = true;
1405
1475
  var mountedRef = React__default.useRef(false);
1406
1476
  var isMounted = React__default.useCallback(function () { return mountedRef.current; }, []);
1407
1477
  React__default.useEffect(function () {
@@ -1426,14 +1496,11 @@ function useDollarState(specs) {
1426
1496
  specTreeLeaves: getSpecTreeLeaves(rootSpecTree),
1427
1497
  stateValues: proxy({}),
1428
1498
  env: envFieldsAreNonNill(env),
1429
- specs: [],
1430
- registrationsQueue: [],
1431
1499
  stateInitializationEnv: { stack: [], visited: new Set() },
1432
1500
  initializedLeafPaths: new Set(),
1433
1501
  };
1434
1502
  })()).current;
1435
1503
  $$state.env = envFieldsAreNonNill(env);
1436
- $$state.specs = specs;
1437
1504
  var create$State = React__default.useCallback(function () {
1438
1505
  var $state = Object.assign(create$StateProxy($$state, function (stateCell) {
1439
1506
  var spec = stateCell.node.getSpec();
@@ -1459,24 +1526,21 @@ function useDollarState(specs) {
1459
1526
  },
1460
1527
  };
1461
1528
  }), __assign({ registerInitFunc: function (pathStr, f, repetitionIndex, overrideEnv) {
1462
- var _a = findStateCell($$state.rootSpecTree, pathStr, repetitionIndex), node = _a.node, realPath = _a.realPath;
1529
+ var realPath = findStateCell($$state.rootSpecTree, pathStr, repetitionIndex).realPath;
1463
1530
  var stateCell = getStateCellFrom$StateRoot($state, realPath);
1464
- var innerEnv = overrideEnv
1531
+ // The first initializer always applies, even if unstable, like the
1532
+ // lazy initialization of a spec initFunc.
1533
+ stateCell.pendingInit || (stateCell.pendingInit = !stateCell.initFunc);
1534
+ stateCell.initFunc = f;
1535
+ stateCell.overrideEnv = overrideEnv
1465
1536
  ? envFieldsAreNonNill(overrideEnv)
1466
- : $$state.env;
1467
- if (!deepEqual(stateCell.initialValue, f(__assign({ $state: $state }, innerEnv)))) {
1468
- $$state.registrationsQueue.push({
1469
- node: node,
1470
- path: realPath,
1471
- f: f,
1472
- overrideEnv: overrideEnv
1473
- ? envFieldsAreNonNill(overrideEnv)
1474
- : undefined,
1475
- });
1476
- if (!pendingUpdate.current) {
1477
- pendingUpdate.current = true;
1478
- forceUpdate();
1479
- }
1537
+ : undefined;
1538
+ if (!rendering.current &&
1539
+ !pendingUpdate.current &&
1540
+ (stateCell.pendingInit ||
1541
+ initValueChanged($$state, stateCell, $state))) {
1542
+ pendingUpdate.current = true;
1543
+ forceUpdate();
1480
1544
  }
1481
1545
  } }, ((opts === null || opts === void 0 ? void 0 : opts.inCanvas)
1482
1546
  ? {
@@ -1497,6 +1561,9 @@ function useDollarState(specs) {
1497
1561
  }
1498
1562
  stateCell.initFunc = newSpec.initFunc;
1499
1563
  stateCell.initFuncHash = (_b = newSpec.initFuncHash) !== null && _b !== void 0 ? _b : "";
1564
+ stateCell.unsettledResetCount = undefined;
1565
+ stateCell.warnedUnstableInitFunc = undefined;
1566
+ stateCell.rejectedInitProbe = undefined;
1500
1567
  var init = spec.valueProp
1501
1568
  ? $$state.env.$props[spec.valueProp]
1502
1569
  : spec.initFunc
@@ -1532,47 +1599,24 @@ function useDollarState(specs) {
1532
1599
  });
1533
1600
  }
1534
1601
  }
1535
- var reInitializeState = function (stateCell) {
1536
- var _a, _b;
1537
- var newInit = initializeStateValue($$state, stateCell, $state);
1538
- var spec = stateCell.node.getSpec();
1539
- if (spec.onChangeProp) {
1540
- (_b = (_a = $$state.env.$props)[spec.onChangeProp]) === null || _b === void 0 ? void 0 : _b.call(_a, newInit);
1541
- }
1542
- };
1543
1602
  useIsomorphicLayoutEffect(function () {
1544
- // For each spec with an initFunc, evaluate it and see if
1545
- // the init value has changed. If so, reset its state.
1546
- var resetSpecs = [];
1547
- getStateCells($state, $$state.rootSpecTree).forEach(function (stateCell) {
1548
- var _a;
1549
- if (stateCell.initFunc) {
1550
- try {
1551
- var newInit = invokeInitFunc(stateCell.initFunc, __assign({ $state: $state }, ((_a = stateCell.overrideEnv) !== null && _a !== void 0 ? _a : envFieldsAreNonNill(env))));
1552
- if (!deepEqual(newInit, stateCell.initialValue)) {
1553
- resetSpecs.push({ stateCell: stateCell });
1554
- }
1555
- }
1556
- catch (_b) {
1557
- // Exception may be thrown from initFunc -- for example, if it tries to access $queries
1558
- // that are still loading. We swallow those here, since we're only interested in
1559
- // checking if the init value has changed, not in handling these errors.
1560
- }
1561
- }
1603
+ rendering.current = false;
1604
+ // Scan every cell before resetting any, so each initFunc sees the same
1605
+ // pre-reset state.
1606
+ var resetCells = getStateCells($state, $$state.rootSpecTree).filter(function (stateCell) {
1607
+ return stateCell.pendingInit ||
1608
+ (stateCell.initFunc &&
1609
+ shouldReInitialize(stateCell, stateCell.initFunc, initFuncEnv($$state, stateCell, $state)));
1562
1610
  });
1563
- resetSpecs.forEach(function (_a) {
1564
- var stateCell = _a.stateCell;
1565
- reInitializeState(stateCell);
1611
+ resetCells.forEach(function (stateCell) {
1612
+ var _a, _b;
1613
+ stateCell.pendingInit = undefined;
1614
+ var newInit = initializeStateValue($$state, stateCell, $state);
1615
+ var spec = stateCell.node.getSpec();
1616
+ if (spec.onChangeProp) {
1617
+ (_b = (_a = $$state.env.$props)[spec.onChangeProp]) === null || _b === void 0 ? void 0 : _b.call(_a, newInit);
1618
+ }
1566
1619
  });
1567
- }, [env.$props, $state, $$state, reInitializeState]);
1568
- useIsomorphicLayoutEffect(function () {
1569
- while ($$state.registrationsQueue.length) {
1570
- var _a = $$state.registrationsQueue.shift(), path = _a.path, f = _a.f, overrideEnv = _a.overrideEnv;
1571
- var stateCell = getStateCellFrom$StateRoot($state, path);
1572
- stateCell.initFunc = f;
1573
- stateCell.overrideEnv = overrideEnv;
1574
- reInitializeState(stateCell);
1575
- }
1576
1620
  });
1577
1621
  // immediately initialize exposed non-private states
1578
1622
  useIsomorphicLayoutEffect(function () {
@@ -1683,11 +1727,15 @@ function getStateCells($state, root) {
1683
1727
  try {
1684
1728
  for (var _c = __values(root.edges().entries()), _d = _c.next(); !_d.done; _d = _c.next()) {
1685
1729
  var _e = __read(_d.value, 2), key = _e[0], child = _e[1];
1686
- if (typeof key === "string" && key in $state) {
1730
+ if (typeof key !== "string") {
1731
+ continue;
1732
+ }
1733
+ // A leaf cell can exist without a local value, e.g. a valueProp state.
1734
+ if (key in stateCell) {
1735
+ stateCells.push(stateCell[key]);
1736
+ }
1737
+ else if (key in $state) {
1687
1738
  stateCells.push.apply(stateCells, __spreadArray([], __read(getStateCells($state[key], child)), false));
1688
- if (key in stateCell) {
1689
- stateCells.push(stateCell[key]);
1690
- }
1691
1739
  }
1692
1740
  }
1693
1741
  }
@@ -1736,6 +1784,16 @@ function getCurrentInitialValue(obj, path) {
1736
1784
  }
1737
1785
  return (_a = tryGetStateCellFrom$StateRoot(obj, path)) === null || _a === void 0 ? void 0 : _a.initialValue;
1738
1786
  }
1787
+ /** Whether the runtime guard has detected instability in this initializer.
1788
+ * Canvas edits clear the diagnostic when the initializer hash changes.
1789
+ */
1790
+ function hasUnstableStateInitializer(obj, path) {
1791
+ var _a;
1792
+ if (!isPlasmicStateProxy(obj)) {
1793
+ return false;
1794
+ }
1795
+ return !!((_a = tryGetStateCellFrom$StateRoot(obj, path)) === null || _a === void 0 ? void 0 : _a.warnedUnstableInitFunc);
1796
+ }
1739
1797
  function resetToInitialValue(obj, path) {
1740
1798
  var stateCell = tryGetStateCellFrom$StateRoot(obj, path);
1741
1799
  if (stateCell) {
@@ -1956,5 +2014,5 @@ function deepEqual(a, b) {
1956
2014
  // Using any while classnames package is not updated to have the correct types exported
1957
2015
  var classNames = classNames$1;
1958
2016
 
1959
- export { PlasmicIcon, PlasmicPageGuard, PlasmicSlot, Stack, Trans, classNames, createPlasmicElementProxy, createStyleTokensProvider, createUseGlobalVariants, createUseScreenVariants, createUseStyleTokens, deriveRenderOpts, ensureGlobalVariants, generateOnMutateForSpec, generateStateOnChangeProp, generateStateOnChangePropForCodeComponents, generateStateValueProp, getCurrentInitialValue, getStateCellsInPlasmicProxy, getStateSpecInPlasmicProxy, hasVariant, initializeCodeComponentStates, initializePlasmicStates, is$StateProxy, isPlasmicStateProxy, makeFragment, mergeVariantsWithStates, omit, pick, renderPlasmicSlot, resetToInitialValue, set, useDollarState, useTrigger, withPlasmicPageGuard, wrapWithClassName };
2017
+ export { PlasmicIcon, PlasmicPageGuard, PlasmicSlot, Stack, Trans, classNames, createPlasmicElementProxy, createStyleTokensProvider, createUseGlobalVariants, createUseScreenVariants, createUseStyleTokens, deriveRenderOpts, ensureGlobalVariants, generateOnMutateForSpec, generateStateOnChangeProp, generateStateOnChangePropForCodeComponents, generateStateValueProp, getCurrentInitialValue, getStateCellsInPlasmicProxy, getStateSpecInPlasmicProxy, hasUnstableStateInitializer, hasVariant, initializeCodeComponentStates, initializePlasmicStates, is$StateProxy, isPlasmicStateProxy, makeFragment, mergeVariantsWithStates, omit, pick, renderPlasmicSlot, resetToInitialValue, set, useDollarState, useTrigger, withPlasmicPageGuard, wrapWithClassName };
1960
2018
  //# sourceMappingURL=index.js.map