@khanacademy/wonder-blocks-core 3.1.5 → 4.2.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # @khanacademy/wonder-blocks-core
2
+
3
+ ## 4.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0aed8723: Adds `throwIfNested` required prop to `RenderStateRoot`.
8
+
9
+ ## 4.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 45588e5f: Fix an issue with `useUniqueIdWithMock`/`useUniqueIdWithoutMock`
14
+ rerender more than was needed. The fix introduces `<RenderStateRoot>`
15
+ which must be an ancestor to all components uses these hooks.
16
+ - 875b7893: Nesting of `RenderStateRoot`s inside each other can result in extra renders
17
+ and potentially incorrect behavior. `RenderStateRoot` now throws if it
18
+ appears as a descendent of another `RenderStateRoot`.
package/dist/es/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import _extends from '@babel/runtime/helpers/extends';
2
2
  import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
3
- import { Component, createElement, createContext } from 'react';
3
+ import * as React from 'react';
4
+ import { useContext as useContext$1, useRef } from 'react';
4
5
  import { StyleSheet, css } from 'aphrodite';
5
6
 
6
7
  function flatten(list) {
@@ -76,9 +77,9 @@ function processStyleList(style) {
76
77
  };
77
78
  }
78
79
 
79
- const _excluded = ["children", "style", "tag", "testId"];
80
+ const _excluded$2 = ["children", "style", "tag", "testId"];
80
81
  const isHeaderRegex = /^h[1-6]$/;
81
- const styles = StyleSheet.create({
82
+ const styles$1 = StyleSheet.create({
82
83
  text: {
83
84
  // Disable subpixel antialiasing on Mac desktop for consistency of
84
85
  // rendering with mobile and Sketch (neither of which support it).
@@ -106,7 +107,7 @@ const styles = StyleSheet.create({
106
107
  * - An array combining the above
107
108
  */
108
109
 
109
- class Text extends Component {
110
+ class Text extends React.Component {
110
111
  render() {
111
112
  const _this$props = this.props,
112
113
  {
@@ -115,11 +116,11 @@ class Text extends Component {
115
116
  tag: Tag,
116
117
  testId
117
118
  } = _this$props,
118
- otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
119
+ otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
119
120
 
120
121
  const isHeader = isHeaderRegex.test(Tag);
121
- const styleAttributes = processStyleList([styles.text, isHeader && styles.header, style]);
122
- return /*#__PURE__*/createElement(Tag, _extends({}, otherProps, {
122
+ const styleAttributes = processStyleList([styles$1.text, isHeader && styles$1.header, style]);
123
+ return /*#__PURE__*/React.createElement(Tag, _extends({}, otherProps, {
123
124
  style: styleAttributes.style,
124
125
  className: styleAttributes.className,
125
126
  "data-test-id": testId
@@ -149,7 +150,7 @@ function addStyle(Component, defaultStyle) {
149
150
  className: aphroditeClassName,
150
151
  style: inlineStyles
151
152
  } = processStyleList([reset, defaultStyle, style]);
152
- return /*#__PURE__*/createElement(Component, _extends({}, otherProps, {
153
+ return /*#__PURE__*/React.createElement(Component, _extends({}, otherProps, {
153
154
  className: [aphroditeClassName, className].filter(Boolean).join(" "),
154
155
  style: inlineStyles
155
156
  }));
@@ -174,8 +175,8 @@ const overrides = StyleSheet.create({
174
175
  }
175
176
  });
176
177
 
177
- const _excluded$2 = ["testId", "tag"];
178
- const styles$1 = StyleSheet.create({
178
+ const _excluded = ["testId", "tag"];
179
+ const styles = StyleSheet.create({
179
180
  // https://github.com/facebook/css-layout#default-values
180
181
  default: {
181
182
  alignItems: "stretch",
@@ -193,11 +194,11 @@ const styles$1 = StyleSheet.create({
193
194
  minWidth: 0
194
195
  }
195
196
  });
196
- const StyledDiv = addStyle("div", styles$1.default);
197
- const StyledArticle = addStyle("article", styles$1.default);
198
- const StyledAside = addStyle("aside", styles$1.default);
199
- const StyledNav = addStyle("nav", styles$1.default);
200
- const StyledSection = addStyle("section", styles$1.default);
197
+ const StyledDiv = addStyle("div", styles.default);
198
+ const StyledArticle = addStyle("article", styles.default);
199
+ const StyledAside = addStyle("aside", styles.default);
200
+ const StyledNav = addStyle("nav", styles.default);
201
+ const StyledSection = addStyle("section", styles.default);
201
202
  /**
202
203
  * View is a building block for constructing other components. `View` roughly
203
204
  * maps to `div` and `Text` roughly maps to `span`. You can override which tag
@@ -212,14 +213,14 @@ const StyledSection = addStyle("section", styles$1.default);
212
213
  * - An array combining the above
213
214
  */
214
215
 
215
- class View extends Component {
216
+ class View extends React.Component {
216
217
  render() {
217
218
  const _this$props = this.props,
218
219
  {
219
220
  testId,
220
221
  tag
221
222
  } = _this$props,
222
- restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
223
+ restProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
223
224
 
224
225
  const props = _extends({}, restProps, {
225
226
  "data-test-id": testId
@@ -227,19 +228,19 @@ class View extends Component {
227
228
 
228
229
  switch (tag) {
229
230
  case "article":
230
- return /*#__PURE__*/createElement(StyledArticle, props);
231
+ return /*#__PURE__*/React.createElement(StyledArticle, props);
231
232
 
232
233
  case "aside":
233
- return /*#__PURE__*/createElement(StyledAside, props);
234
+ return /*#__PURE__*/React.createElement(StyledAside, props);
234
235
 
235
236
  case "nav":
236
- return /*#__PURE__*/createElement(StyledNav, props);
237
+ return /*#__PURE__*/React.createElement(StyledNav, props);
237
238
 
238
239
  case "section":
239
- return /*#__PURE__*/createElement(StyledSection, props);
240
+ return /*#__PURE__*/React.createElement(StyledSection, props);
240
241
 
241
242
  case "div":
242
- return /*#__PURE__*/createElement(StyledDiv, props);
243
+ return /*#__PURE__*/React.createElement(StyledDiv, props);
243
244
 
244
245
  default:
245
246
  throw Error(`${tag} is not an allowed value for the 'tag' prop`);
@@ -251,11 +252,11 @@ View.defaultProps = {
251
252
  tag: "div"
252
253
  };
253
254
 
254
- /**
255
- * We use render functions so that we don't do any work unless we need to.
256
- * This avoids rendering but not mounting potentially complex component trees.
257
- */
258
-
255
+ const RenderState = require("flow-enums-runtime")({
256
+ Root: "root",
257
+ Initial: "initial",
258
+ Standard: "standard"
259
+ });
259
260
  /**
260
261
  * This is the context that tracks who is doing what in our SSR component tree.
261
262
  *
@@ -271,7 +272,14 @@ View.defaultProps = {
271
272
  * standard:
272
273
  * means that we're all now doing non-SSR rendering
273
274
  */
274
- const RenderStateContext = /*#__PURE__*/createContext("root");
275
+
276
+ const RenderStateContext = /*#__PURE__*/React.createContext(RenderState.Root);
277
+
278
+ /**
279
+ * We use render functions so that we don't do any work unless we need to.
280
+ * This avoids rendering but not mounting potentially complex component trees.
281
+ */
282
+
275
283
  /**
276
284
  * Defer or change rendering until the component did mount.
277
285
  *
@@ -296,8 +304,7 @@ const RenderStateContext = /*#__PURE__*/createContext("root");
296
304
  * </WithSSRPlaceholder>
297
305
  * ```
298
306
  */
299
-
300
- class WithSSRPlaceholder extends Component {
307
+ class WithSSRPlaceholder extends React.Component {
301
308
  constructor(...args) {
302
309
  super(...args);
303
310
  this.state = {
@@ -333,8 +340,8 @@ class WithSSRPlaceholder extends Component {
333
340
  if (mounted) {
334
341
  // This is our second non-SSR render, so let's tell everyone to
335
342
  // do their thing.
336
- return /*#__PURE__*/createElement(RenderStateContext.Provider, {
337
- value: "standard"
343
+ return /*#__PURE__*/React.createElement(RenderStateContext.Provider, {
344
+ value: RenderState.Standard
338
345
  }, children());
339
346
  } // OK, this is the very first render.
340
347
  // If we have a placeholder, we render it, and ensure that any
@@ -343,8 +350,8 @@ class WithSSRPlaceholder extends Component {
343
350
 
344
351
 
345
352
  if (placeholder) {
346
- return /*#__PURE__*/createElement(RenderStateContext.Provider, {
347
- value: "initial"
353
+ return /*#__PURE__*/React.createElement(RenderStateContext.Provider, {
354
+ value: RenderState.Initial
348
355
  }, placeholder());
349
356
  } // Otherwise, we return nothing.
350
357
 
@@ -359,33 +366,10 @@ class WithSSRPlaceholder extends Component {
359
366
  } = this.props;
360
367
 
361
368
  switch (renderState) {
362
- // There are edge cases where for some reason, we get an unknown
363
- // context value here. So far it seems to be when we're nested in a
364
- // v1 WithSSRPlaceholder equivalent component, or in some older
365
- // React v16 situations where we're nested in the provider of a
366
- // different context.
367
- //
368
- // We ignore this from coverage. It's a maintenance case to help
369
- // us catch code changes that affect the control flow unexpectedly,
370
- // but it's not something we need to write a test case for.
371
- //
372
-
373
- /* istanbul ignore next */
374
- default:
375
- // Let's log this case so we can debug it easily.
376
- // Then fall through to the root case.
377
-
378
- /* eslint-disable-next-line no-console */
379
- console.log(`We got a render state we don't understand: "${JSON.stringify(renderState)}"`); // We "fallthrough" to the root case. This is more obvious
380
- // and maintainable code than just ignoring the no-fallthrough
381
- // lint rule.
382
-
383
- return this._maybeRender("root");
384
-
385
- case "root":
369
+ case RenderState.Root:
386
370
  return this._renderAsRootComponent();
387
371
 
388
- case "initial":
372
+ case RenderState.Initial:
389
373
  // We're not the root component, so we just have to either
390
374
  // render our placeholder or nothing.
391
375
  // The second render is going to be triggered for us.
@@ -396,15 +380,42 @@ class WithSSRPlaceholder extends Component {
396
380
 
397
381
  return null;
398
382
 
399
- case "standard":
383
+ case RenderState.Standard:
400
384
  // We have covered the SSR render, we're now rendering with
401
385
  // standard rendering semantics.
402
386
  return children();
387
+ } // There are edge cases where for some reason, we get an unknown
388
+ // context value here. So far it seems to be when we're nested in a
389
+ // v1 WithSSRPlaceholder equivalent component, or in some older
390
+ // React v16 situations where we're nested in the provider of a
391
+ // different context.
392
+ //
393
+ // We ignore this from coverage. It's a maintenance case to help
394
+ // us catch code changes that affect the control flow unexpectedly,
395
+ // but it's not something we need to write a test case for.
396
+ //
397
+ // Flow will assert exhaustiveness of the switch because Flow enums
398
+ // rock.
399
+ //
400
+
401
+ /* istanbul ignore next */
402
+
403
+
404
+ {
405
+ // Let's log this case so we can debug it easily.
406
+ // Then fall through to the root case.
407
+
408
+ /* eslint-disable-next-line no-console */
409
+ console.log(`We got a render state we don't understand: "${JSON.stringify(renderState)}"`); // We "fallthrough" to the root case. This is more obvious
410
+ // and maintainable code than just ignoring the no-fallthrough
411
+ // lint rule.
412
+
413
+ return this._maybeRender(RenderState.Root);
403
414
  }
404
415
  }
405
416
 
406
417
  render() {
407
- return /*#__PURE__*/createElement(RenderStateContext.Consumer, null, value => this._maybeRender(value));
418
+ return /*#__PURE__*/React.createElement(RenderStateContext.Consumer, null, value => this._maybeRender(value));
408
419
  }
409
420
 
410
421
  }
@@ -510,7 +521,7 @@ var SsrIDFactory$1 = SsrIDFactory.Default;
510
521
  * `get("test2")` will always equal `get("test2")`, but `get("test")` will
511
522
  * never equal `get("test2")`.
512
523
  */
513
- class UniqueIDProvider extends Component {
524
+ class UniqueIDProvider extends React.Component {
514
525
  _performRender(firstRender) {
515
526
  const {
516
527
  children,
@@ -543,7 +554,7 @@ class UniqueIDProvider extends Component {
543
554
  // Here we use the WithSSRPlaceholder component to control
544
555
  // when we render and whether we provide a mock or real
545
556
  // identifier factory.
546
- return /*#__PURE__*/createElement(WithSSRPlaceholder, {
557
+ return /*#__PURE__*/React.createElement(WithSSRPlaceholder, {
547
558
  placeholder: () => this._performRender(true)
548
559
  }, () => this._performRender(false));
549
560
  }
@@ -564,7 +575,7 @@ class UniqueIDProvider extends Component {
564
575
  * e.g. It uses the same generated id to connect a Dialog with its main title, or form label
565
576
  * with the associated input element, etc.
566
577
  */
567
- class IDProvider extends Component {
578
+ class IDProvider extends React.Component {
568
579
  renderChildren(ids) {
569
580
  const {
570
581
  id,
@@ -590,7 +601,7 @@ class IDProvider extends Component {
590
601
  // need it.
591
602
  return this.renderChildren();
592
603
  } else {
593
- return /*#__PURE__*/createElement(UniqueIDProvider, {
604
+ return /*#__PURE__*/React.createElement(UniqueIDProvider, {
594
605
  scope: scope,
595
606
  mockOnFirstRender: true
596
607
  }, ids => this.renderChildren(ids));
@@ -600,237 +611,109 @@ class IDProvider extends Component {
600
611
  }
601
612
  IDProvider.defaultId = "wb-id";
602
613
 
603
- let _Symbol$iterator;
614
+ let serverSide = false;
615
+ var server = {
616
+ /**
617
+ * Check if we are running in server-side mode.
618
+ *
619
+ * @returns {boolean} `true` if we are in server-side mode; otherwise,
620
+ * `false`
621
+ */
622
+ isServerSide: () => serverSide,
623
+
624
+ /**
625
+ * Set server-side mode to true.
626
+ */
627
+ setServerSide: () => {
628
+ serverSide = true;
629
+ }
630
+ };
604
631
 
605
632
  /**
606
- * Utility for finding the scroll ancestors of a child
633
+ * Returns a unique identifier factory. If the parent component hasn't
634
+ * been mounted yet, the global SsrIDFactory will be returned until the
635
+ * component becomes mounted.
607
636
  *
608
- * Inspired by https://github.com/olahol/scrollparent.js
609
- * with modifications to make an iterator that returns a sequence of all scroll
610
- * ancestors.
611
- *
612
- * Also modified for our standards (and commented a bit).
637
+ * @param {string} [scope] optional string to prefix generated ids with.
638
+ * @returns {IIdentifierFactory}
613
639
  */
614
- const getElementStyle = function getElementStyle(node, prop) {
615
- return getComputedStyle(node).getPropertyValue(prop);
616
- };
640
+ const useUniqueIdWithMock = scope => {
641
+ const renderState = useContext$1(RenderStateContext);
642
+ const idFactory = useRef(null);
617
643
 
618
- const getElementOverflow = function getElementOverflow(node) {
619
- return getElementStyle(node, "overflow") + getElementStyle(node, "overflow-y") + getElementStyle(node, "overflow-x");
620
- };
621
-
622
- const canScroll = function canScroll(node) {
623
- return /(auto|scroll)/.test(getElementOverflow(node));
624
- }; // NOTE(somewhatabstract): Flow includes the @@iterator value in the Iterator
625
- // interface definition, but it doesn't pick up on our computed property
626
- // defining it (tried handling this in other ways, but it just won't work).
627
- // So, we need this and the additional FlowFixMe a few lines down on the
628
- // iterator property itself.
629
- // $FlowFixMe[prop-missing]
630
-
631
-
632
- _Symbol$iterator = Symbol.iterator;
633
-
634
- class ScrollAncestorsIterator {
635
- constructor(element) {
636
- this.done = false;
637
-
638
- if (!(element instanceof HTMLElement)) {
639
- this.done = true;
640
- } else {
641
- this.parentElement = element.parentElement;
642
- }
643
- } //$FlowFixMe: Computed property keys are not allowed by flow at the moment
644
-
645
-
646
- [_Symbol$iterator]() {
647
- return this;
644
+ if (renderState === RenderState.Root) {
645
+ throw new Error("Components using useUniqueIdWithMock() should be descendants of <RenderStateRoot>");
648
646
  }
649
647
 
650
- next() {
651
- if (this.done) {
652
- return {
653
- done: true
654
- };
655
- } // Climb the DOM looking for the next scroll candidate.
656
-
657
-
658
- let scrollCandidate;
659
-
660
- do {
661
- scrollCandidate = this.parentElement;
662
- this.parentElement = this.parentElement && this.parentElement.parentElement;
663
- } while (scrollCandidate && !canScroll(scrollCandidate));
664
-
665
- if (!scrollCandidate) {
666
- // If we don't have a scroll candidate, we'll definitely be done
667
- // iterating by the next call to next().
668
- // So let's remember that.
669
- this.done = true; // If we don't have a documentElement, we are actually done right
670
- // now, rather than on the next call.
671
-
672
- if (!document.documentElement) {
673
- return {
674
- done: true
675
- };
676
- } // Otherwise, as we have a documentElement, this is our penultimate
677
- // iteration .
678
-
679
-
680
- return {
681
- done: false,
682
- value: document.documentElement
683
- };
684
- } // We found a scroll ancestor, so let's return that.
685
-
686
-
687
- return {
688
- done: false,
689
- value: scrollCandidate
690
- };
648
+ if (renderState === RenderState.Initial) {
649
+ return SsrIDFactory$1;
691
650
  }
692
651
 
693
- }
694
-
695
- function enumerateScrollAncestors(element) {
696
- return Object.defineProperty({}, Symbol.iterator, {
697
- value: () => new ScrollAncestorsIterator(element),
698
- writable: true
699
- });
700
- }
701
-
702
- function getAxisIntersection(intersectingRect, boundsRect, axis) {
703
- const start = rect => axis === "horizontal" ? rect.left : rect.top;
704
-
705
- const end = rect => axis === "horizontal" ? rect.right : rect.bottom;
706
-
707
- if (end(intersectingRect) <= start(boundsRect)) {
708
- return "before";
709
- } else if (start(intersectingRect) >= end(boundsRect)) {
710
- return "after";
652
+ if (!idFactory.current) {
653
+ idFactory.current = new UniqueIDFactory(scope);
711
654
  }
712
655
 
713
- return "within";
714
- }
715
-
716
- function UndeterminedIntersection() {
717
- return {
718
- horizontal: null,
719
- vertical: null
720
- };
721
- }
722
-
723
- function FullIntersection() {
724
- return {
725
- horizontal: "within",
726
- vertical: "within"
727
- };
728
- }
656
+ return idFactory.current;
657
+ };
729
658
  /**
730
- * Determine if an element intersects a single other element.
659
+ * Returns a unique identifier factory. If the parent component hasn't
660
+ * been mounted yet, null will be returned.
731
661
  *
732
- * It is assumed that the element provided as `boundsElement` is an element that
733
- * could obscure the given element, `element`.
662
+ * @param {string} [scope] optional string to prefix generated ids with.
663
+ * @returns {?IIdentifierFactory}
734
664
  */
735
665
 
666
+ const useUniqueIdWithoutMock = scope => {
667
+ const renderState = useContext$1(RenderStateContext);
668
+ const idFactory = useRef(null);
736
669
 
737
- function getElementIntersectionAgainstParent(intersectingRect, boundsElement) {
738
- // We need to check that it matters if we're out of bounds. If the parent
739
- // element isn't clipping or otherwise hiding things outside its bounds,
740
- // then checking against bounds isn't going to be much use.
741
- // So, let's get the style for the element and use the overflow values.
742
- const style = boundsElement.currentStyle || window.getComputedStyle(boundsElement);
743
- const boundingRect = boundsElement.getBoundingClientRect();
744
- const boundsRect = {
745
- top: boundingRect.top,
746
- bottom: boundingRect.bottom,
747
- left: boundingRect.left,
748
- right: boundingRect.right
749
- }; // In webapp we set height: 100% on html, body and overflow-y: scroll on body.
750
- // This results in the height reported by getBoundingClientRect being the height
751
- // of the viewport instead of the height of the page. We use the scrollHeight
752
- // of the body to corect the bounds.
753
- // TODO(kevinb): screenshot test this
754
-
755
- if (boundsElement === document.body) {
756
- boundsRect.bottom = boundsRect.top + boundsElement.scrollHeight;
757
- } // We assume we're within this specific bounds element if it's overflow is
758
- // visible.
759
-
760
-
761
- const horizontal = style.overflowX === "visible" ? "within" : getAxisIntersection(intersectingRect, boundsRect, "horizontal"); // We assume we're within this specific bounds element if it's overflow is
762
- // visible.
763
-
764
- const vertical = style.overflowY === "visible" ? "within" : getAxisIntersection(intersectingRect, boundsRect, "vertical");
765
- return {
766
- horizontal,
767
- vertical
768
- };
769
- }
770
- /**
771
- * Determine if a given element intersects with the visible bounds of its
772
- * scroll parents, or the bounds of a specific element.
773
- */
774
-
775
-
776
- function getElementIntersection(element, boundsElement) {
777
- if (!element) {
778
- // An non-existant element is definitely not visible.
779
- return UndeterminedIntersection();
670
+ if (renderState === RenderState.Root) {
671
+ throw new Error("Components using useUniqueIdWithoutMock() should be descendants of <RenderStateRoot>");
780
672
  }
781
673
 
782
- const {
783
- top,
784
- left,
785
- bottom,
786
- right
787
- } = element.getBoundingClientRect();
788
- const intersectingRect = {
789
- top,
790
- left,
791
- bottom,
792
- right
793
- }; // If we're looking against a single boundary element, then we just do that.
794
-
795
- if (boundsElement) {
796
- return getElementIntersectionAgainstParent(intersectingRect, boundsElement);
674
+ if (renderState === RenderState.Initial) {
675
+ return null;
797
676
  }
798
677
 
799
- if (element instanceof Element) {
800
- // Otherwise, we enumerate the scroll parents and test against those.
801
- // If one of them is hiding our candidate element, then we will return.
802
- for (const scrollParent of enumerateScrollAncestors(element)) {
803
- const intersection = getElementIntersectionAgainstParent(intersectingRect, scrollParent); // If the intersectingRect is before or after the parent in one or both
804
- // dimensions, then return our intersection result. Otherwise, we'll
805
- // keep on searching up our parents.
806
-
807
- if (intersection.vertical !== "within" || intersection.horizontal !== "within") {
808
- // Stop looking, we've found something that is hiding the element.
809
- return intersection;
810
- }
811
- }
812
- } // If we got here, the element is within the bounds of its parents.
813
-
814
-
815
- return FullIntersection();
816
- }
678
+ if (!idFactory.current) {
679
+ idFactory.current = new UniqueIDFactory(scope);
680
+ }
817
681
 
818
- let serverSide = false;
819
- var server = {
820
- /**
821
- * Check if we are running in server-side mode.
822
- *
823
- * @returns {boolean} `true` if we are in server-side mode; otherwise,
824
- * `false`
825
- */
826
- isServerSide: () => serverSide,
682
+ return idFactory.current;
683
+ };
827
684
 
828
- /**
829
- * Set server-side mode to true.
830
- */
831
- setServerSide: () => {
832
- serverSide = true;
685
+ const {
686
+ useContext,
687
+ useEffect,
688
+ useState
689
+ } = React;
690
+ const RenderStateRoot = ({
691
+ children,
692
+ throwIfNested
693
+ }) => {
694
+ const [firstRender, setFirstRender] = useState(true);
695
+ const contextValue = useContext(RenderStateContext);
696
+ useEffect(() => {
697
+ setFirstRender(false);
698
+ }, []); // This effect will only run once.
699
+
700
+ if (contextValue !== RenderState.Root) {
701
+ if (throwIfNested) {
702
+ throw new Error("There's already a <RenderStateRoot> above this instance in " + "the render tree. This instance should be removed.");
703
+ } // Avoid rendering multiple providers if this RenderStateRoot
704
+ // is nested inside another one.
705
+
706
+
707
+ return children;
833
708
  }
709
+
710
+ const value = firstRender ? RenderState.Initial : RenderState.Standard;
711
+ return /*#__PURE__*/React.createElement(RenderStateContext.Provider, {
712
+ value: value
713
+ }, children);
714
+ };
715
+ RenderStateRoot.defaultProps = {
716
+ throwIfNested: true
834
717
  };
835
718
 
836
- export { IDProvider, server as Server, Text, UniqueIDProvider, View, WithSSRPlaceholder, addStyle, getElementIntersection };
719
+ export { IDProvider, RenderStateRoot, server as Server, Text, UniqueIDProvider, View, WithSSRPlaceholder, addStyle, useUniqueIdWithMock, useUniqueIdWithoutMock };