@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.
package/README.internal CHANGED
@@ -3,34 +3,18 @@ and type definitions used by generated blackbox presentational code.
3
3
 
4
4
  If you want to use this for yourself, then first build the output:
5
5
 
6
- yarn build
6
+ pnpm --filter @plasmicapp/react-web build
7
7
 
8
- There are two ways to use this package.
8
+ For fast local iteration in a pnpm consumer, use the workspace's link scripts:
9
9
 
10
+ pnpm local-link:setup @plasmicapp/react-web ~/path/to/consumer
11
+ pnpm local-link:build @plasmicapp/react-web
10
12
 
11
- Usage 1 - via yarn link
12
- =======================
13
+ Restart the consumer after rebuilding. When finished, restore registry
14
+ dependencies before deleting its `node_modules`:
13
15
 
14
- Then create a link to this:
16
+ pnpm local-link:teardown ~/path/to/consumer
15
17
 
16
- yarn link
17
-
18
- Then, from the package where you want to use this package, do:
19
-
20
- yarn link @plasmicapp/react-web
21
-
22
- This basically symlinks a folder in your consumer node_modules folder that links back
23
- to the output from `yarn build`. If you update any file here, be sure to run `yarn build`
24
- again so your updates are reflected in consuming packages.
25
-
26
- Usage 2 - via package.json
27
- ==========================
28
-
29
- Then create a link to this:
30
-
31
- yarn add link:<path to @plasmicapp/react-web directory>
32
-
33
- This avoids the problem of multiple `yarn link` that may conflict with each other.
34
-
35
- plasmic/wab uses this approach. So you don't have to do anything except for `yarn build` to
36
- use the latest @plasmicapp/react-web package for plasmic/wab.
18
+ Avoid raw package-manager links: they can resolve React and other peer dependencies
19
+ from this monorepo instead of the consumer. See the root `CONTRIBUTING.md` for the
20
+ full local-link and Verdaccio workflows.
package/dist/all.d.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import * as React$1 from 'react';
3
- import React__default, { AriaAttributes, DOMAttributes as DOMAttributes$1, AriaRole, CSSProperties as CSSProperties$1, ReactNode, ReactElement, FocusEvent, KeyboardEvent as KeyboardEvent$1, SyntheticEvent } from 'react';
4
- import { AriaCheckboxProps } from '@react-types/checkbox';
5
- import { AriaSwitchProps } from '@react-types/switch';
3
+ import React__default, { AriaAttributes, DOMAttributes as DOMAttributes$1, AriaRole, CSSProperties as CSSProperties$1, ReactNode, ReactElement, FocusEvent, KeyboardEvent as KeyboardEvent$1, MouseEvent, SyntheticEvent } from 'react';
6
4
 
7
5
  declare global {
8
6
  interface Window {
@@ -13596,6 +13594,10 @@ declare function getStateSpecInPlasmicProxy(obj: any, path: ObjectPath): {
13596
13594
  isImplicitStateArray: boolean;
13597
13595
  } | undefined;
13598
13596
  declare function getCurrentInitialValue(obj: any, path: ObjectPath): any;
13597
+ /** Whether the runtime guard has detected instability in this initializer.
13598
+ * Canvas edits clear the diagnostic when the initializer hash changes.
13599
+ */
13600
+ declare function hasUnstableStateInitializer(obj: any, path: ObjectPath): boolean;
13599
13601
  declare function resetToInitialValue(obj: any, path: ObjectPath): void;
13600
13602
  /**
13601
13603
  * Forked from https://github.com/lukeed/dset
@@ -13975,6 +13977,34 @@ declare function Trans({ transKey, children }: TransProps): React__default.React
13975
13977
 
13976
13978
 
13977
13979
 
13980
+ type ValidationState = 'valid' | 'invalid';
13981
+
13982
+ type ValidationError = string | string[];
13983
+
13984
+ interface Validation<T = unknown> {
13985
+ /** Whether user input is required on the input before form submission. */
13986
+ isRequired?: boolean;
13987
+ /** Whether the input value is invalid. */
13988
+ isInvalid?: boolean;
13989
+ /** @deprecated Use `isInvalid` instead. */
13990
+ validationState?: ValidationState;
13991
+ /**
13992
+ * Whether to use native HTML form validation to prevent form submission
13993
+ * when the value is missing or invalid, or mark the field as required
13994
+ * or invalid via ARIA.
13995
+ *
13996
+ * @default 'aria'
13997
+ */
13998
+ validationBehavior?: 'aria' | 'native';
13999
+ /**
14000
+ * A function that returns an error message if a given value is invalid.
14001
+ * Validation errors are displayed to the user when the form is submitted
14002
+ * if `validationBehavior="native"`. For realtime validation, use the `isInvalid`
14003
+ * prop instead.
14004
+ */
14005
+ validate?: (value: T) => ValidationError | true | null | undefined;
14006
+ }
14007
+
13978
14008
  interface InputBase {
13979
14009
  /** Whether the input is disabled. */
13980
14010
  isDisabled?: boolean;
@@ -14019,6 +14049,14 @@ interface AriaLabelingProps {
14019
14049
  'aria-details'?: string;
14020
14050
  }
14021
14051
 
14052
+ interface AriaValidationProps {
14053
+ // https://www.w3.org/TR/wai-aria-1.2/#aria-errormessage
14054
+ /**
14055
+ * Identifies the element that provides an error message for the object.
14056
+ */
14057
+ 'aria-errormessage'?: string;
14058
+ }
14059
+
14022
14060
  // A set of common DOM props that are allowed on any component
14023
14061
  // Ensure this is synced with DOMPropNames in filterDOMProps
14024
14062
  interface DOMProps {
@@ -14039,6 +14077,20 @@ interface FocusableDOMProps extends DOMProps {
14039
14077
  excludeFromTabOrder?: boolean;
14040
14078
  }
14041
14079
 
14080
+ interface InputDOMProps {
14081
+ /**
14082
+ * The name of the input element, used when submitting an HTML form. See
14083
+ * [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname).
14084
+ */
14085
+ name?: string;
14086
+ /**
14087
+ * The `<form>` element to associate the input with.
14088
+ * The value of this attribute must be the id of a `<form>` in the same document.
14089
+ * See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form).
14090
+ */
14091
+ form?: string;
14092
+ }
14093
+
14042
14094
  /** Any focusable element, including both HTML and SVG elements. */
14043
14095
  interface FocusableElement extends Element, HTMLOrSVGElement {}
14044
14096
 
@@ -14277,6 +14329,31 @@ interface FocusEvents<Target = Element> {
14277
14329
  onFocusChange?: (isFocused: boolean) => void;
14278
14330
  }
14279
14331
 
14332
+ interface PressEvents {
14333
+ /** Handler that is called when the press is released over the target. */
14334
+ onPress?: (e: PressEvent) => void;
14335
+ /** Handler that is called when a press interaction starts. */
14336
+ onPressStart?: (e: PressEvent) => void;
14337
+ /**
14338
+ * Handler that is called when a press interaction ends, either
14339
+ * over the target or when the pointer leaves the target.
14340
+ */
14341
+ onPressEnd?: (e: PressEvent) => void;
14342
+ /** Handler that is called when the press state changes. */
14343
+ onPressChange?: (isPressed: boolean) => void;
14344
+ /**
14345
+ * Handler that is called when a press is released over the target, regardless of
14346
+ * whether it started on the target or not.
14347
+ */
14348
+ onPressUp?: (e: PressEvent) => void;
14349
+ /**
14350
+ * **Not recommended – use `onPress` instead.** `onClick` is an alias for `onPress`
14351
+ * provided for compatibility with other libraries. `onPress` provides
14352
+ * additional event details for non-mouse interactions.
14353
+ */
14354
+ onClick?: (e: MouseEvent<FocusableElement>) => void;
14355
+ }
14356
+
14280
14357
  interface FocusableProps<Target = Element> extends FocusEvents<Target>, KeyboardEvents {
14281
14358
  /** Whether the element should receive focus on render. */
14282
14359
  autoFocus?: boolean;
@@ -14437,6 +14514,50 @@ declare function useButton<P extends PlumeButtonProps, C extends AnyPlasmicClass
14437
14514
  };
14438
14515
  };
14439
14516
 
14517
+ interface ToggleStateOptions extends InputBase {
14518
+ /**
14519
+ * Whether the element should be selected (uncontrolled).
14520
+ */
14521
+ defaultSelected?: boolean;
14522
+ /**
14523
+ * Whether the element should be selected (controlled).
14524
+ */
14525
+ isSelected?: boolean;
14526
+ /**
14527
+ * Handler that is called when the element's selection state changes.
14528
+ */
14529
+ onChange?: (isSelected: boolean) => void;
14530
+ }
14531
+ interface ToggleProps extends ToggleStateOptions, Validation<boolean>, FocusableProps {
14532
+ /**
14533
+ * The label for the element.
14534
+ */
14535
+ children?: ReactNode;
14536
+ /**
14537
+ * The value of the input element, used when submitting an HTML form. See
14538
+ * [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefvalue).
14539
+ */
14540
+ value?: string;
14541
+ }
14542
+
14543
+ interface AriaToggleProps extends ToggleProps, FocusableDOMProps, AriaLabelingProps, AriaValidationProps, InputDOMProps, PressEvents {
14544
+ /**
14545
+ * Identifies the element (or elements) whose contents or presence are controlled by the current
14546
+ * element.
14547
+ */
14548
+ 'aria-controls'?: string;
14549
+ }
14550
+
14551
+ interface CheckboxProps$1 extends ToggleProps {
14552
+ /**
14553
+ * Indeterminism is presentational only.
14554
+ * The indeterminate visual representation remains regardless of user interaction.
14555
+ */
14556
+ isIndeterminate?: boolean;
14557
+ }
14558
+ interface AriaCheckboxProps extends CheckboxProps$1, InputDOMProps, AriaToggleProps {
14559
+ }
14560
+
14440
14561
  interface StyleProps {
14441
14562
  className?: string;
14442
14563
  style?: React$1.CSSProperties;
@@ -15156,6 +15277,16 @@ interface ListState<T> {
15156
15277
 
15157
15278
  declare const SelectContext: React$1.Context<ListState<any> | undefined>;
15158
15279
 
15280
+ interface SwitchProps$1 extends ToggleProps {
15281
+ }
15282
+ interface AriaSwitchProps extends SwitchProps$1, InputDOMProps, AriaToggleProps {
15283
+ /**
15284
+ * Identifies the element (or elements) whose contents or presence are controlled by the current
15285
+ * element.
15286
+ */
15287
+ 'aria-controls'?: string;
15288
+ }
15289
+
15159
15290
  type SwitchRef = React$1.Ref<SwitchRefValue>;
15160
15291
  interface SwitchRefValue extends SwitchState {
15161
15292
  getRoot: () => HTMLElement | null;
@@ -15260,4 +15391,4 @@ interface TriggeredOverlayContextValue {
15260
15391
  }
15261
15392
  declare const TriggeredOverlayContext: React$1.Context<TriggeredOverlayContextValue | undefined>;
15262
15393
 
15263
- export { $State, $StateSpec, BaseButtonProps, BaseMenuButtonProps, BaseMenuGroupProps, BaseMenuItemProps, BaseMenuProps, BaseSelectOptionGroupProps, BaseSelectOptionProps, BaseSelectProps, BaseTextInputProps, BaseTriggeredOverlayProps, ButtonRef, CheckboxProps, CheckboxRef, CheckboxRefValue, DropdownMenu, Flex, HTMLElementRefOf, HtmlAnchorOnlyProps, HtmlButtonOnlyProps, InitFunc, MenuButtonRef, MenuButtonRefValue, MenuRef, MenuRefValue, MultiChoiceArg, ParamsRecord, PlasmicDataSourceContextProvider, PlasmicHead, PlasmicIcon, PlasmicImg, PlasmicLink, PlasmicPageGuard, PlasmicPageProps, PlasmicRootProvider, PlasmicSlot, PlasmicTranslator, PlumeButtonProps, PlumeTextInputProps, SelectContext, SelectOptionRef, SelectRef, SelectRefValue, SingleBooleanChoiceArg, SingleChoiceArg, Stack, StrictProps, SwitchProps, SwitchRef, SwitchRefValue, TextInputRef, TextInputRefValue, Trans, TriggeredOverlayConfig, TriggeredOverlayContext, TriggeredOverlayRef, classNames, createPlasmicElementProxy, createStyleTokensProvider, createUseGlobalVariants, createUseScreenVariants, createUseStyleTokens, deriveRenderOpts, ensureGlobalVariants, genTranslatableString, generateOnMutateForSpec, generateStateOnChangeProp, generateStateOnChangePropForCodeComponents, generateStateValueProp, dlv as get, getCurrentInitialValue, getDataProps, getStateCellsInPlasmicProxy, getStateSpecInPlasmicProxy, hasVariant, initializeCodeComponentStates, initializePlasmicStates, is$StateProxy, isPlasmicStateProxy, makeFragment, mergeVariantsWithStates, omit, pick, plasmicHeadMeta, renderPlasmicSlot, resetToInitialValue, set, setPlumeStrictMode, useButton, useCheckbox, useCurrentUser, useDollarState, useIsSSR, useMenu, useMenuButton, useMenuGroup, useMenuItem, usePlasmicTranslator, useSelect, useSelectOption, useSelectOptionGroup, useSwitch, useTextInput, useTrigger, useTriggeredOverlay, withPlasmicPageGuard, wrapWithClassName };
15394
+ export { $State, $StateSpec, BaseButtonProps, BaseMenuButtonProps, BaseMenuGroupProps, BaseMenuItemProps, BaseMenuProps, BaseSelectOptionGroupProps, BaseSelectOptionProps, BaseSelectProps, BaseTextInputProps, BaseTriggeredOverlayProps, ButtonRef, CheckboxProps, CheckboxRef, CheckboxRefValue, DropdownMenu, Flex, HTMLElementRefOf, HtmlAnchorOnlyProps, HtmlButtonOnlyProps, InitFunc, MenuButtonRef, MenuButtonRefValue, MenuRef, MenuRefValue, MultiChoiceArg, ParamsRecord, PlasmicDataSourceContextProvider, PlasmicHead, PlasmicIcon, PlasmicImg, PlasmicLink, PlasmicPageGuard, PlasmicPageProps, PlasmicRootProvider, PlasmicSlot, PlasmicTranslator, PlumeButtonProps, PlumeTextInputProps, SelectContext, SelectOptionRef, SelectRef, SelectRefValue, SingleBooleanChoiceArg, SingleChoiceArg, Stack, StrictProps, SwitchProps, SwitchRef, SwitchRefValue, TextInputRef, TextInputRefValue, Trans, TriggeredOverlayConfig, TriggeredOverlayContext, TriggeredOverlayRef, classNames, createPlasmicElementProxy, createStyleTokensProvider, createUseGlobalVariants, createUseScreenVariants, createUseStyleTokens, deriveRenderOpts, ensureGlobalVariants, genTranslatableString, generateOnMutateForSpec, generateStateOnChangeProp, generateStateOnChangePropForCodeComponents, generateStateValueProp, dlv as get, getCurrentInitialValue, getDataProps, getStateCellsInPlasmicProxy, getStateSpecInPlasmicProxy, hasUnstableStateInitializer, hasVariant, initializeCodeComponentStates, initializePlasmicStates, is$StateProxy, isPlasmicStateProxy, makeFragment, mergeVariantsWithStates, omit, pick, plasmicHeadMeta, renderPlasmicSlot, resetToInitialValue, set, setPlumeStrictMode, useButton, useCheckbox, useCurrentUser, useDollarState, useIsSSR, useMenu, useMenuButton, useMenuGroup, useMenuItem, usePlasmicTranslator, useSelect, useSelectOption, useSelectOptionGroup, useSwitch, useTextInput, useTrigger, useTriggeredOverlay, withPlasmicPageGuard, wrapWithClassName };
package/dist/index.cjs.js CHANGED
@@ -2276,7 +2276,6 @@ function ensureStateCell(target, property, path, node) {
2276
2276
  var stateCell = proxyObjToStateCell.get(target);
2277
2277
  if (!(property in stateCell)) {
2278
2278
  stateCell[property] = {
2279
- listeners: [],
2280
2279
  initialValue: UNINITIALIZED,
2281
2280
  path: path,
2282
2281
  node: node,
@@ -2334,7 +2333,6 @@ function subscribeToValtio($$state, statePath, node) {
2334
2333
  function initializeStateValue($$state, initialStateCell, proxyRoot) {
2335
2334
  var _a;
2336
2335
  var initialStateName = initialStateCell.node.getSpec().path;
2337
- var stateAccess = new Set();
2338
2336
  $$state.stateInitializationEnv.visited.add(initialStateName);
2339
2337
  $$state.stateInitializationEnv.stack.push(initialStateName);
2340
2338
  var $state = create$StateProxy($$state, function (internalStateCell) { return ({
@@ -2356,7 +2354,6 @@ function initializeStateValue($$state, initialStateCell, proxyRoot) {
2356
2354
  throw new UnknownError("Internal error: cycle not found");
2357
2355
  }
2358
2356
  var stateCell = getStateCellFrom$StateRoot(proxyRoot, internalStateCell.path);
2359
- stateAccess.add({ stateCell: stateCell });
2360
2357
  if (spec.valueProp) {
2361
2358
  return $$state.env.$props[spec.valueProp];
2362
2359
  }
@@ -2369,14 +2366,6 @@ function initializeStateValue($$state, initialStateCell, proxyRoot) {
2369
2366
  throw new InvalidOperation("Cannot update state values during initialization");
2370
2367
  },
2371
2368
  }); });
2372
- stateAccess.forEach(function (_a) {
2373
- var stateCell = _a.stateCell;
2374
- stateCell.listeners.push(function () {
2375
- var _a;
2376
- var newValue = invokeInitFunc(initialStateCell.node.getSpec().initFunc, __assign({ $state: $state }, ((_a = initialStateCell.overrideEnv) !== null && _a !== void 0 ? _a : $$state.env)));
2377
- set(proxyRoot, initialStateCell.path, newValue);
2378
- });
2379
- });
2380
2369
  var initialValue = invokeInitFunc(initialStateCell.initFunc, __assign({ $state: $state }, ((_a = initialStateCell.overrideEnv) !== null && _a !== void 0 ? _a : $$state.env)));
2381
2370
  var initialSpec = initialStateCell.node.getSpec();
2382
2371
  // Try to clone initialValue. It can fail if it's a PlasmicUndefinedDataProxy
@@ -2561,6 +2550,83 @@ function extractDollarStateParametersBackwardCompatible() {
2561
2550
  function invokeInitFunc(initFunc, env) {
2562
2551
  return initFunc(env);
2563
2552
  }
2553
+ function initFuncEnv($$state, stateCell, $state) {
2554
+ var _a;
2555
+ return __assign({ $state: $state }, ((_a = stateCell.overrideEnv) !== null && _a !== void 0 ? _a : $$state.env));
2556
+ }
2557
+ // Pure check with no effect on the reset budget; the layout scan decides.
2558
+ function initValueChanged($$state, stateCell, $state) {
2559
+ try {
2560
+ return !deepEqual(invokeInitFunc(stateCell.initFunc, initFuncEnv($$state, stateCell, $state)), stateCell.initialValue);
2561
+ }
2562
+ catch (_a) {
2563
+ return false;
2564
+ }
2565
+ }
2566
+ // Bound consecutive resets without a settled evaluation, even on slow renders.
2567
+ var MAX_UNSETTLED_RESETS = 5;
2568
+ function warnUnstableInitFunc(stateCell, reason) {
2569
+ if (stateCell.warnedUnstableInitFunc) {
2570
+ return;
2571
+ }
2572
+ stateCell.warnedUnstableInitFunc = true;
2573
+ 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."));
2574
+ }
2575
+ /**
2576
+ * Whether `stateCell` should be reset to what `initFunc` now returns. An
2577
+ * initFunc that returns a new value every time it runs would reset on every
2578
+ * render, and each reset renders again, so the loop never ends. We refuse to
2579
+ * reset in two cases:
2580
+ *
2581
+ * - Two back-to-back calls disagree, indicating an unstable initializer.
2582
+ * - Too many resets occur without a settled evaluation. This also catches
2583
+ * values that are stable within a render but drift between renders.
2584
+ *
2585
+ * This is a circuit breaker, not a proof of determinism: legitimate feedback
2586
+ * chains can also exceed the budget, and unstable functions can return equal
2587
+ * values by chance. Initializers must be pure and deterministic for fixed inputs.
2588
+ *
2589
+ * Rejected probes never change the installed initial value used by preview
2590
+ * reset. A rejected value that repeats on a later render can reopen the budget.
2591
+ */
2592
+ function shouldReInitialize(stateCell, initFunc, env) {
2593
+ var _a;
2594
+ var newInit;
2595
+ var repeats;
2596
+ try {
2597
+ newInit = invokeInitFunc(initFunc, env);
2598
+ if (deepEqual(newInit, stateCell.initialValue)) {
2599
+ stateCell.unsettledResetCount = undefined;
2600
+ stateCell.rejectedInitProbe = undefined;
2601
+ return false;
2602
+ }
2603
+ repeats = deepEqual(invokeInitFunc(initFunc, env), newInit);
2604
+ }
2605
+ catch (_b) {
2606
+ // initFunc can throw, e.g. if it tries to access loading $queries. Swallow here
2607
+ // since we only care whether the init value changed, not error handling.
2608
+ return false;
2609
+ }
2610
+ var reason;
2611
+ if (!repeats) {
2612
+ reason = "is not deterministic";
2613
+ }
2614
+ else {
2615
+ var rejectedInitProbe = stateCell.rejectedInitProbe;
2616
+ var reopened = rejectedInitProbe && deepEqual(newInit, rejectedInitProbe.value);
2617
+ stateCell.unsettledResetCount = reopened
2618
+ ? 1
2619
+ : ((_a = stateCell.unsettledResetCount) !== null && _a !== void 0 ? _a : 0) + 1;
2620
+ if (stateCell.unsettledResetCount > MAX_UNSETTLED_RESETS) {
2621
+ reason = "keeps changing";
2622
+ }
2623
+ }
2624
+ stateCell.rejectedInitProbe = reason ? { value: newInit } : undefined;
2625
+ if (reason) {
2626
+ warnUnstableInitFunc(stateCell, reason);
2627
+ }
2628
+ return !reason;
2629
+ }
2564
2630
  function useDollarState(specs) {
2565
2631
  var rest = [];
2566
2632
  for (var _i = 1; _i < arguments.length; _i++) {
@@ -2568,6 +2634,10 @@ function useDollarState(specs) {
2568
2634
  }
2569
2635
  var _a = extractDollarStateParametersBackwardCompatible.apply(void 0, __spreadArray([], __read(rest), false)), env = _a.env, opts = _a.opts;
2570
2636
  var _b = __read(React.useState(), 2), setState = _b[1];
2637
+ // Set for the whole render pass and cleared by the layout effect, which applies
2638
+ // registrations. One that arrives outside a render must schedule a render to be applied.
2639
+ var rendering = React.useRef(false);
2640
+ rendering.current = true;
2571
2641
  var mountedRef = React.useRef(false);
2572
2642
  var isMounted = React.useCallback(function () { return mountedRef.current; }, []);
2573
2643
  React.useEffect(function () {
@@ -2592,14 +2662,11 @@ function useDollarState(specs) {
2592
2662
  specTreeLeaves: getSpecTreeLeaves(rootSpecTree),
2593
2663
  stateValues: valtio.proxy({}),
2594
2664
  env: envFieldsAreNonNill(env),
2595
- specs: [],
2596
- registrationsQueue: [],
2597
2665
  stateInitializationEnv: { stack: [], visited: new Set() },
2598
2666
  initializedLeafPaths: new Set(),
2599
2667
  };
2600
2668
  })()).current;
2601
2669
  $$state.env = envFieldsAreNonNill(env);
2602
- $$state.specs = specs;
2603
2670
  var create$State = React.useCallback(function () {
2604
2671
  var $state = Object.assign(create$StateProxy($$state, function (stateCell) {
2605
2672
  var spec = stateCell.node.getSpec();
@@ -2625,24 +2692,21 @@ function useDollarState(specs) {
2625
2692
  },
2626
2693
  };
2627
2694
  }), __assign({ registerInitFunc: function (pathStr, f, repetitionIndex, overrideEnv) {
2628
- var _a = findStateCell($$state.rootSpecTree, pathStr, repetitionIndex), node = _a.node, realPath = _a.realPath;
2695
+ var realPath = findStateCell($$state.rootSpecTree, pathStr, repetitionIndex).realPath;
2629
2696
  var stateCell = getStateCellFrom$StateRoot($state, realPath);
2630
- var innerEnv = overrideEnv
2697
+ // The first initializer always applies, even if unstable, like the
2698
+ // lazy initialization of a spec initFunc.
2699
+ stateCell.pendingInit || (stateCell.pendingInit = !stateCell.initFunc);
2700
+ stateCell.initFunc = f;
2701
+ stateCell.overrideEnv = overrideEnv
2631
2702
  ? envFieldsAreNonNill(overrideEnv)
2632
- : $$state.env;
2633
- if (!deepEqual(stateCell.initialValue, f(__assign({ $state: $state }, innerEnv)))) {
2634
- $$state.registrationsQueue.push({
2635
- node: node,
2636
- path: realPath,
2637
- f: f,
2638
- overrideEnv: overrideEnv
2639
- ? envFieldsAreNonNill(overrideEnv)
2640
- : undefined,
2641
- });
2642
- if (!pendingUpdate.current) {
2643
- pendingUpdate.current = true;
2644
- forceUpdate();
2645
- }
2703
+ : undefined;
2704
+ if (!rendering.current &&
2705
+ !pendingUpdate.current &&
2706
+ (stateCell.pendingInit ||
2707
+ initValueChanged($$state, stateCell, $state))) {
2708
+ pendingUpdate.current = true;
2709
+ forceUpdate();
2646
2710
  }
2647
2711
  } }, ((opts === null || opts === void 0 ? void 0 : opts.inCanvas)
2648
2712
  ? {
@@ -2663,6 +2727,9 @@ function useDollarState(specs) {
2663
2727
  }
2664
2728
  stateCell.initFunc = newSpec.initFunc;
2665
2729
  stateCell.initFuncHash = (_b = newSpec.initFuncHash) !== null && _b !== void 0 ? _b : "";
2730
+ stateCell.unsettledResetCount = undefined;
2731
+ stateCell.warnedUnstableInitFunc = undefined;
2732
+ stateCell.rejectedInitProbe = undefined;
2666
2733
  var init = spec.valueProp
2667
2734
  ? $$state.env.$props[spec.valueProp]
2668
2735
  : spec.initFunc
@@ -2698,47 +2765,24 @@ function useDollarState(specs) {
2698
2765
  });
2699
2766
  }
2700
2767
  }
2701
- var reInitializeState = function (stateCell) {
2702
- var _a, _b;
2703
- var newInit = initializeStateValue($$state, stateCell, $state);
2704
- var spec = stateCell.node.getSpec();
2705
- if (spec.onChangeProp) {
2706
- (_b = (_a = $$state.env.$props)[spec.onChangeProp]) === null || _b === void 0 ? void 0 : _b.call(_a, newInit);
2707
- }
2708
- };
2709
2768
  useIsomorphicLayoutEffect(function () {
2710
- // For each spec with an initFunc, evaluate it and see if
2711
- // the init value has changed. If so, reset its state.
2712
- var resetSpecs = [];
2713
- getStateCells($state, $$state.rootSpecTree).forEach(function (stateCell) {
2714
- var _a;
2715
- if (stateCell.initFunc) {
2716
- try {
2717
- var newInit = invokeInitFunc(stateCell.initFunc, __assign({ $state: $state }, ((_a = stateCell.overrideEnv) !== null && _a !== void 0 ? _a : envFieldsAreNonNill(env))));
2718
- if (!deepEqual(newInit, stateCell.initialValue)) {
2719
- resetSpecs.push({ stateCell: stateCell });
2720
- }
2721
- }
2722
- catch (_b) {
2723
- // Exception may be thrown from initFunc -- for example, if it tries to access $queries
2724
- // that are still loading. We swallow those here, since we're only interested in
2725
- // checking if the init value has changed, not in handling these errors.
2726
- }
2727
- }
2769
+ rendering.current = false;
2770
+ // Scan every cell before resetting any, so each initFunc sees the same
2771
+ // pre-reset state.
2772
+ var resetCells = getStateCells($state, $$state.rootSpecTree).filter(function (stateCell) {
2773
+ return stateCell.pendingInit ||
2774
+ (stateCell.initFunc &&
2775
+ shouldReInitialize(stateCell, stateCell.initFunc, initFuncEnv($$state, stateCell, $state)));
2728
2776
  });
2729
- resetSpecs.forEach(function (_a) {
2730
- var stateCell = _a.stateCell;
2731
- reInitializeState(stateCell);
2777
+ resetCells.forEach(function (stateCell) {
2778
+ var _a, _b;
2779
+ stateCell.pendingInit = undefined;
2780
+ var newInit = initializeStateValue($$state, stateCell, $state);
2781
+ var spec = stateCell.node.getSpec();
2782
+ if (spec.onChangeProp) {
2783
+ (_b = (_a = $$state.env.$props)[spec.onChangeProp]) === null || _b === void 0 ? void 0 : _b.call(_a, newInit);
2784
+ }
2732
2785
  });
2733
- }, [env.$props, $state, $$state, reInitializeState]);
2734
- useIsomorphicLayoutEffect(function () {
2735
- while ($$state.registrationsQueue.length) {
2736
- var _a = $$state.registrationsQueue.shift(), path = _a.path, f = _a.f, overrideEnv = _a.overrideEnv;
2737
- var stateCell = getStateCellFrom$StateRoot($state, path);
2738
- stateCell.initFunc = f;
2739
- stateCell.overrideEnv = overrideEnv;
2740
- reInitializeState(stateCell);
2741
- }
2742
2786
  });
2743
2787
  // immediately initialize exposed non-private states
2744
2788
  useIsomorphicLayoutEffect(function () {
@@ -2849,11 +2893,15 @@ function getStateCells($state, root) {
2849
2893
  try {
2850
2894
  for (var _c = __values(root.edges().entries()), _d = _c.next(); !_d.done; _d = _c.next()) {
2851
2895
  var _e = __read(_d.value, 2), key = _e[0], child = _e[1];
2852
- if (typeof key === "string" && key in $state) {
2896
+ if (typeof key !== "string") {
2897
+ continue;
2898
+ }
2899
+ // A leaf cell can exist without a local value, e.g. a valueProp state.
2900
+ if (key in stateCell) {
2901
+ stateCells.push(stateCell[key]);
2902
+ }
2903
+ else if (key in $state) {
2853
2904
  stateCells.push.apply(stateCells, __spreadArray([], __read(getStateCells($state[key], child)), false));
2854
- if (key in stateCell) {
2855
- stateCells.push(stateCell[key]);
2856
- }
2857
2905
  }
2858
2906
  }
2859
2907
  }
@@ -2902,6 +2950,16 @@ function getCurrentInitialValue(obj, path) {
2902
2950
  }
2903
2951
  return (_a = tryGetStateCellFrom$StateRoot(obj, path)) === null || _a === void 0 ? void 0 : _a.initialValue;
2904
2952
  }
2953
+ /** Whether the runtime guard has detected instability in this initializer.
2954
+ * Canvas edits clear the diagnostic when the initializer hash changes.
2955
+ */
2956
+ function hasUnstableStateInitializer(obj, path) {
2957
+ var _a;
2958
+ if (!isPlasmicStateProxy(obj)) {
2959
+ return false;
2960
+ }
2961
+ return !!((_a = tryGetStateCellFrom$StateRoot(obj, path)) === null || _a === void 0 ? void 0 : _a.warnedUnstableInitFunc);
2962
+ }
2905
2963
  function resetToInitialValue(obj, path) {
2906
2964
  var stateCell = tryGetStateCellFrom$StateRoot(obj, path);
2907
2965
  if (stateCell) {
@@ -3243,10 +3301,10 @@ function useCheckbox(plasmicClass, props, config, ref) {
3243
3301
  props: mergeProps(getStyleProps(props), {
3244
3302
  ref: rootRef,
3245
3303
  }),
3246
- wrapChildren: function (children) { return (React__namespace.createElement(React__namespace.Fragment, null,
3304
+ wrapChildren: function (renderedChildren) { return (React__namespace.createElement(React__namespace.Fragment, null,
3247
3305
  React__namespace.createElement(visuallyHidden.VisuallyHidden, null,
3248
3306
  React__namespace.createElement("input", __assign({}, inputProps, { ref: inputRef }))),
3249
- children)); },
3307
+ renderedChildren)); },
3250
3308
  },
3251
3309
  _a);
3252
3310
  var args = __assign(__assign({}, pick.apply(void 0, __spreadArray([props], __read(plasmicClass.internalArgProps), false))), (config.labelSlot ? (_b = {}, _b[config.labelSlot] = children, _b) : {}));
@@ -3596,10 +3654,7 @@ function useMenu(plasmicClass, props, config, ref) {
3596
3654
  var state = tree.useTreeState(ariaProps);
3597
3655
  var menuListRef = React__namespace.useRef(null);
3598
3656
  var menuProps = menu.useMenu(__assign(__assign({}, ariaProps), { autoFocus: triggerContext === null || triggerContext === void 0 ? void 0 : triggerContext.autoFocus }), state, menuListRef).menuProps;
3599
- var contextValue = React__namespace.useMemo(function () { return ({ state: state, menuProps: props }); }, [
3600
- state,
3601
- props,
3602
- ]);
3657
+ var contextValue = React__namespace.useMemo(function () { return ({ state: state, menuProps: props }); }, [state, props]);
3603
3658
  var variants = __assign({}, pick.apply(void 0, __spreadArray([props], __read(plasmicClass.internalVariantProps), false)));
3604
3659
  var overrides = (_a = {},
3605
3660
  _a[config.root] = {
@@ -4150,10 +4205,10 @@ function useSwitch(plasmicClass, props, config, ref) {
4150
4205
  props: mergeProps(getStyleProps(props), {
4151
4206
  ref: rootRef,
4152
4207
  }),
4153
- wrapChildren: function (children) { return (React__namespace.createElement(React__namespace.Fragment, null,
4208
+ wrapChildren: function (renderedChildren) { return (React__namespace.createElement(React__namespace.Fragment, null,
4154
4209
  React__namespace.createElement(visuallyHidden.VisuallyHidden, null,
4155
4210
  React__namespace.createElement("input", __assign({}, inputProps, { ref: inputRef }))),
4156
- children)); },
4211
+ renderedChildren)); },
4157
4212
  },
4158
4213
  _a);
4159
4214
  var args = __assign(__assign({}, pick.apply(void 0, __spreadArray([props], __read(plasmicClass.internalArgProps), false))), (config.labelSlot ? (_b = {}, _b[config.labelSlot] = children, _b) : {}));
@@ -4370,6 +4425,7 @@ exports.getCurrentInitialValue = getCurrentInitialValue;
4370
4425
  exports.getDataProps = getDataProps;
4371
4426
  exports.getStateCellsInPlasmicProxy = getStateCellsInPlasmicProxy;
4372
4427
  exports.getStateSpecInPlasmicProxy = getStateSpecInPlasmicProxy;
4428
+ exports.hasUnstableStateInitializer = hasUnstableStateInitializer;
4373
4429
  exports.hasVariant = hasVariant;
4374
4430
  exports.initializeCodeComponentStates = initializeCodeComponentStates;
4375
4431
  exports.initializePlasmicStates = initializePlasmicStates;