@khanacademy/wonder-blocks-core 8.0.0 → 10.0.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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # @khanacademy/wonder-blocks-core
2
2
 
3
+ ## 10.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - b6009b77: Deprecate the ID provider and unique ID utilities
8
+
9
+ ### Minor Changes
10
+
11
+ - 897686bc: - Add the `Id` component for cases where `useId` cannot be used directly
12
+
13
+ ### Patch Changes
14
+
15
+ - 56d961f1: - Migrate Wonder Blocks components off old id providers and onto new `Id` component
16
+
17
+ ## 9.0.0
18
+
19
+ ### Major Changes
20
+
21
+ - f4abd572: - Remove `RenderState.Root` from exported enum
22
+ - Change `useRenderState` to only return `RenderState.Initial` or `RenderState.Standard`
23
+
3
24
  ## 8.0.0
4
25
 
5
26
  ### Major Changes
@@ -22,6 +22,9 @@ type Props = {
22
22
  testId?: string;
23
23
  };
24
24
  /**
25
+ * @deprecated This component is deprecated and will be removed in an
26
+ * upcoming release. Migrate existing code to use `useId` or the `Id` component.
27
+ *
25
28
  * This is a wrapper that returns an identifier. If the `id` prop is set, the
26
29
  * component will return the same id to be consumed by its children. Otherwise,
27
30
  * a unique id will be provided. This is beneficial for accessibility purposes,
@@ -48,7 +51,6 @@ type Props = {
48
51
  * )}
49
52
  * </IDProvider>
50
53
  * ```
51
- *
52
54
  */
53
55
  export default class IDProvider extends React.Component<Props> {
54
56
  static defaultId: string;
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ type Props = {
3
+ /**
4
+ * An identifier to use.
5
+ *
6
+ * If this is omitted, an identifier is generated.
7
+ */
8
+ id?: string | undefined;
9
+ /**
10
+ * A function that to render children with the given identifier.
11
+ */
12
+ children: (id: string) => React.ReactNode;
13
+ };
14
+ /**
15
+ * `Id` is a component that provides an identifier to its children.
16
+ *
17
+ * It is useful for situations where the `useId` hook cannot be easily used,
18
+ * such as in class-based components.
19
+ *
20
+ * If an `id` prop is provided, that is passed through to the children;
21
+ * otherwise, a unique identifier is generated.
22
+ */
23
+ export declare const Id: ({ id, children }: Props) => React.JSX.Element;
24
+ export {};
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { RenderState } from "./render-state-context";
2
+ import { RenderStateInternal } from "./render-state-context";
3
3
  /**
4
4
  * We use render functions so that we don't do any work unless we need to.
5
5
  * This avoids rendering but not mounting potentially complex component trees.
@@ -56,7 +56,7 @@ export default class InitialFallback extends React.Component<Props, State> {
56
56
  componentDidMount(): void;
57
57
  _isTheRootComponent: boolean;
58
58
  _renderAsRootComponent(): React.ReactNode;
59
- _maybeRender(renderState: typeof RenderState[keyof typeof RenderState]): React.ReactNode;
59
+ _maybeRender(renderState: RenderStateInternal): React.ReactNode;
60
60
  render(): React.ReactNode;
61
61
  }
62
62
  export {};
@@ -1,7 +1,52 @@
1
1
  import * as React from "react";
2
+ /**
3
+ * The possible states of rendering.
4
+ *
5
+ * This is used to determine if we are rendering our initial, hydrateable state
6
+ * or not. Initial renders must be consistent between the server and client so
7
+ * that hydration will succeed.
8
+ *
9
+ * We use a render state like this instead of a simple check for being mounted
10
+ * or not, or some other way of each component knowing if it is rendering itself
11
+ * for the first time so that we can avoid cascading initial renders where each
12
+ * component has to render itself and its children multiple times to reach a
13
+ * stable state. Instead, we track the initial render from the root of the tree
14
+ * and switch everything accordingly so that there are fewer additional renders.
15
+ */
2
16
  export declare enum RenderState {
17
+ /**
18
+ * The initial render, either on the server or client.
19
+ */
20
+ Initial = "initial",
21
+ /**
22
+ * Any render after the initial render. Only occurs on the client.
23
+ */
24
+ Standard = "standard"
25
+ }
26
+ /**
27
+ * The internal states of rendering.
28
+ *
29
+ * This is different to the `RenderState` enum as this is internal to the
30
+ * Core package and solely for components that are going to provide new values
31
+ * to the render state context.
32
+ */
33
+ export declare enum RenderStateInternal {
34
+ /**
35
+ * This is the root state. It indicates that nothing has actually changed
36
+ * then context value that tracks this. This is used solely by components
37
+ * that control the rendering state to know that they are in charge of
38
+ * that process.
39
+ */
3
40
  Root = "root",
41
+ /**
42
+ * This indicates something has taken charge of the rendering state and
43
+ * components should render their initial render state that is hydrateable.
44
+ */
4
45
  Initial = "initial",
46
+ /**
47
+ * This indicates that things are now rendering after the initial render
48
+ * and components can render without worrying about hydration.
49
+ */
5
50
  Standard = "standard"
6
51
  }
7
52
  /**
@@ -19,5 +64,5 @@ export declare enum RenderState {
19
64
  * standard:
20
65
  * means that we're all now doing non-SSR rendering
21
66
  */
22
- declare const RenderStateContext: React.Context<RenderState>;
67
+ declare const RenderStateContext: React.Context<RenderStateInternal>;
23
68
  export { RenderStateContext };
@@ -34,6 +34,9 @@ type Props = {
34
34
  readonly scope?: string;
35
35
  };
36
36
  /**
37
+ * @deprecated This component is deprecated and will be removed in an
38
+ * upcoming release. Migrate existing code to use `useId` or the `Id` component.
39
+ *
37
40
  * The `UniqueIDProvider` component is how Wonder Blocks components obtain
38
41
  * unique identifiers. This component ensures that server-side rendering and
39
42
  * initial client rendering match while allowing the provision of unique
package/dist/es/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import _extends from '@babel/runtime/helpers/extends';
2
2
  import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
3
3
  import * as React from 'react';
4
- import { useContext, useRef, useEffect as useEffect$1 } from 'react';
4
+ import { useId, useContext as useContext$1, useRef, useEffect as useEffect$1 } from 'react';
5
5
  import { StyleSheet, css } from 'aphrodite';
6
6
 
7
7
  function flatten(list) {
@@ -175,12 +175,17 @@ const View = React.forwardRef(function View(props, ref) {
175
175
  });
176
176
 
177
177
  let RenderState = function (RenderState) {
178
- RenderState["Root"] = "root";
179
178
  RenderState["Initial"] = "initial";
180
179
  RenderState["Standard"] = "standard";
181
180
  return RenderState;
182
181
  }({});
183
- const RenderStateContext = React.createContext(RenderState.Root);
182
+ let RenderStateInternal = function (RenderStateInternal) {
183
+ RenderStateInternal["Root"] = "root";
184
+ RenderStateInternal["Initial"] = "initial";
185
+ RenderStateInternal["Standard"] = "standard";
186
+ return RenderStateInternal;
187
+ }({});
188
+ const RenderStateContext = React.createContext(RenderStateInternal.Root);
184
189
  RenderStateContext.displayName = "RenderStateContext";
185
190
 
186
191
  class InitialFallback extends React.Component {
@@ -209,12 +214,12 @@ class InitialFallback extends React.Component {
209
214
  this._isTheRootComponent = true;
210
215
  if (mounted) {
211
216
  return React.createElement(RenderStateContext.Provider, {
212
- value: RenderState.Standard
217
+ value: RenderStateInternal.Standard
213
218
  }, children());
214
219
  }
215
220
  if (fallback) {
216
221
  return React.createElement(RenderStateContext.Provider, {
217
- value: RenderState.Initial
222
+ value: RenderStateInternal.Initial
218
223
  }, fallback());
219
224
  }
220
225
  return null;
@@ -225,17 +230,17 @@ class InitialFallback extends React.Component {
225
230
  fallback
226
231
  } = this.props;
227
232
  switch (renderState) {
228
- case RenderState.Root:
233
+ case RenderStateInternal.Root:
229
234
  return this._renderAsRootComponent();
230
- case RenderState.Initial:
235
+ case RenderStateInternal.Initial:
231
236
  return fallback ? fallback() : null;
232
- case RenderState.Standard:
237
+ case RenderStateInternal.Standard:
233
238
  return children();
234
239
  }
235
240
  {
236
241
  var _JSON$stringify;
237
242
  console.log(`We got a render state we don't understand: "${(_JSON$stringify = JSON.stringify(renderState)) != null ? _JSON$stringify : ""}"`);
238
- return this._maybeRender(RenderState.Root);
243
+ return this._maybeRender(RenderStateInternal.Root);
239
244
  }
240
245
  }
241
246
  render() {
@@ -340,14 +345,26 @@ var Server = {
340
345
  }
341
346
  };
342
347
 
343
- const useRenderState = () => useContext(RenderStateContext);
348
+ const Id = ({
349
+ id,
350
+ children
351
+ }) => {
352
+ const generatedId = useId();
353
+ return React.createElement(React.Fragment, null, children(id != null ? id : generatedId));
354
+ };
355
+
356
+ const useRenderState = () => {
357
+ const rawRenderState = useContext$1(RenderStateContext);
358
+ if (rawRenderState === RenderStateInternal.Standard) {
359
+ return RenderState.Standard;
360
+ } else {
361
+ return RenderState.Initial;
362
+ }
363
+ };
344
364
 
345
365
  const useUniqueIdWithMock = scope => {
346
366
  const renderState = useRenderState();
347
367
  const idFactory = useRef(null);
348
- if (renderState === RenderState.Root) {
349
- throw new Error("Components using useUniqueIdWithMock() should be descendants of <RenderStateRoot>");
350
- }
351
368
  if (renderState === RenderState.Initial) {
352
369
  return SsrIDFactory$1;
353
370
  }
@@ -359,9 +376,6 @@ const useUniqueIdWithMock = scope => {
359
376
  const useUniqueIdWithoutMock = scope => {
360
377
  const renderState = useRenderState();
361
378
  const idFactory = useRef(null);
362
- if (renderState === RenderState.Root) {
363
- throw new Error("Components using useUniqueIdWithoutMock() should be descendants of <RenderStateRoot>");
364
- }
365
379
  if (renderState === RenderState.Initial) {
366
380
  return null;
367
381
  }
@@ -422,27 +436,28 @@ const usePreHydrationEffect = effect => {
422
436
 
423
437
  const {
424
438
  useEffect,
425
- useState
439
+ useState,
440
+ useContext
426
441
  } = React;
427
442
  const RenderStateRoot = ({
428
443
  children,
429
444
  throwIfNested: _throwIfNested = true
430
445
  }) => {
431
446
  const [firstRender, setFirstRender] = useState(true);
432
- const renderState = useRenderState();
447
+ const renderState = useContext(RenderStateContext);
433
448
  useEffect(() => {
434
449
  setFirstRender(false);
435
450
  }, []);
436
- if (renderState !== RenderState.Root) {
451
+ if (renderState !== RenderStateInternal.Root) {
437
452
  if (_throwIfNested) {
438
453
  throw new Error("There's already a <RenderStateRoot> above this instance in " + "the render tree. This instance should be removed.");
439
454
  }
440
455
  return React.createElement(React.Fragment, null, children);
441
456
  }
442
- const value = firstRender ? RenderState.Initial : RenderState.Standard;
457
+ const value = firstRender ? RenderStateInternal.Initial : RenderStateInternal.Standard;
443
458
  return React.createElement(RenderStateContext.Provider, {
444
459
  value: value
445
460
  }, children);
446
461
  };
447
462
 
448
- export { IDProvider, InitialFallback, RenderState, RenderStateRoot, Server, Text, UniqueIDProvider, View, addStyle, useForceUpdate, useIsMounted, useLatestRef, useOnMountEffect, useOnline, usePreHydrationEffect, useRenderState, useUniqueIdWithMock, useUniqueIdWithoutMock };
463
+ export { IDProvider, Id, InitialFallback, RenderState, RenderStateRoot, Server, Text, UniqueIDProvider, View, addStyle, useForceUpdate, useIsMounted, useLatestRef, useOnMountEffect, useOnline, usePreHydrationEffect, useRenderState, useUniqueIdWithMock, useUniqueIdWithoutMock };
@@ -1,2 +1,2 @@
1
1
  import { RenderState } from "../components/render-state-context";
2
- export declare const useRenderState: () => (typeof RenderState)[keyof typeof RenderState];
2
+ export declare const useRenderState: () => RenderState;
@@ -1,5 +1,8 @@
1
1
  import type { IIdentifierFactory } from "../util/types";
2
2
  /**
3
+ * @deprecated Use `useId` for your ID needs. If you are in a class-based
4
+ * component and cannot use hooks, then use the `Id` component.
5
+ *
3
6
  * Returns a unique identifier factory. If the parent component hasn't
4
7
  * been mounted yet, the global SsrIDFactory will be returned until the
5
8
  * component becomes mounted.
@@ -9,6 +12,9 @@ import type { IIdentifierFactory } from "../util/types";
9
12
  */
10
13
  export declare const useUniqueIdWithMock: (scope?: string) => IIdentifierFactory;
11
14
  /**
15
+ * @deprecated Use `useId` for your ID needs. If you are in a class-based
16
+ * component and cannot use hooks, then use the `Id` component.
17
+ *
12
18
  * Returns a unique identifier factory. If the parent component hasn't
13
19
  * been mounted yet, null will be returned.
14
20
  *
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { default as IDProvider } from "./components/id-provider";
6
6
  export { default as UniqueIDProvider } from "./components/unique-id-provider";
7
7
  export { default as addStyle } from "./util/add-style";
8
8
  export { default as Server } from "./util/server";
9
+ export { Id } from "./components/id";
9
10
  export { useUniqueIdWithMock, useUniqueIdWithoutMock, } from "./hooks/use-unique-id";
10
11
  export { useForceUpdate } from "./hooks/use-force-update";
11
12
  export { useIsMounted } from "./hooks/use-is-mounted";
package/dist/index.js CHANGED
@@ -202,12 +202,17 @@ const View = React__namespace.forwardRef(function View(props, ref) {
202
202
  });
203
203
 
204
204
  let RenderState = function (RenderState) {
205
- RenderState["Root"] = "root";
206
205
  RenderState["Initial"] = "initial";
207
206
  RenderState["Standard"] = "standard";
208
207
  return RenderState;
209
208
  }({});
210
- const RenderStateContext = React__namespace.createContext(RenderState.Root);
209
+ let RenderStateInternal = function (RenderStateInternal) {
210
+ RenderStateInternal["Root"] = "root";
211
+ RenderStateInternal["Initial"] = "initial";
212
+ RenderStateInternal["Standard"] = "standard";
213
+ return RenderStateInternal;
214
+ }({});
215
+ const RenderStateContext = React__namespace.createContext(RenderStateInternal.Root);
211
216
  RenderStateContext.displayName = "RenderStateContext";
212
217
 
213
218
  class InitialFallback extends React__namespace.Component {
@@ -236,12 +241,12 @@ class InitialFallback extends React__namespace.Component {
236
241
  this._isTheRootComponent = true;
237
242
  if (mounted) {
238
243
  return React__namespace.createElement(RenderStateContext.Provider, {
239
- value: RenderState.Standard
244
+ value: RenderStateInternal.Standard
240
245
  }, children());
241
246
  }
242
247
  if (fallback) {
243
248
  return React__namespace.createElement(RenderStateContext.Provider, {
244
- value: RenderState.Initial
249
+ value: RenderStateInternal.Initial
245
250
  }, fallback());
246
251
  }
247
252
  return null;
@@ -252,17 +257,17 @@ class InitialFallback extends React__namespace.Component {
252
257
  fallback
253
258
  } = this.props;
254
259
  switch (renderState) {
255
- case RenderState.Root:
260
+ case RenderStateInternal.Root:
256
261
  return this._renderAsRootComponent();
257
- case RenderState.Initial:
262
+ case RenderStateInternal.Initial:
258
263
  return fallback ? fallback() : null;
259
- case RenderState.Standard:
264
+ case RenderStateInternal.Standard:
260
265
  return children();
261
266
  }
262
267
  {
263
268
  var _JSON$stringify;
264
269
  console.log(`We got a render state we don't understand: "${(_JSON$stringify = JSON.stringify(renderState)) != null ? _JSON$stringify : ""}"`);
265
- return this._maybeRender(RenderState.Root);
270
+ return this._maybeRender(RenderStateInternal.Root);
266
271
  }
267
272
  }
268
273
  render() {
@@ -367,14 +372,26 @@ var Server = {
367
372
  }
368
373
  };
369
374
 
370
- const useRenderState = () => React.useContext(RenderStateContext);
375
+ const Id = ({
376
+ id,
377
+ children
378
+ }) => {
379
+ const generatedId = React.useId();
380
+ return React__namespace.createElement(React__namespace.Fragment, null, children(id != null ? id : generatedId));
381
+ };
382
+
383
+ const useRenderState = () => {
384
+ const rawRenderState = React.useContext(RenderStateContext);
385
+ if (rawRenderState === RenderStateInternal.Standard) {
386
+ return RenderState.Standard;
387
+ } else {
388
+ return RenderState.Initial;
389
+ }
390
+ };
371
391
 
372
392
  const useUniqueIdWithMock = scope => {
373
393
  const renderState = useRenderState();
374
394
  const idFactory = React.useRef(null);
375
- if (renderState === RenderState.Root) {
376
- throw new Error("Components using useUniqueIdWithMock() should be descendants of <RenderStateRoot>");
377
- }
378
395
  if (renderState === RenderState.Initial) {
379
396
  return SsrIDFactory$1;
380
397
  }
@@ -386,9 +403,6 @@ const useUniqueIdWithMock = scope => {
386
403
  const useUniqueIdWithoutMock = scope => {
387
404
  const renderState = useRenderState();
388
405
  const idFactory = React.useRef(null);
389
- if (renderState === RenderState.Root) {
390
- throw new Error("Components using useUniqueIdWithoutMock() should be descendants of <RenderStateRoot>");
391
- }
392
406
  if (renderState === RenderState.Initial) {
393
407
  return null;
394
408
  }
@@ -449,30 +463,32 @@ const usePreHydrationEffect = effect => {
449
463
 
450
464
  const {
451
465
  useEffect,
452
- useState
466
+ useState,
467
+ useContext
453
468
  } = React__namespace;
454
469
  const RenderStateRoot = ({
455
470
  children,
456
471
  throwIfNested: _throwIfNested = true
457
472
  }) => {
458
473
  const [firstRender, setFirstRender] = useState(true);
459
- const renderState = useRenderState();
474
+ const renderState = useContext(RenderStateContext);
460
475
  useEffect(() => {
461
476
  setFirstRender(false);
462
477
  }, []);
463
- if (renderState !== RenderState.Root) {
478
+ if (renderState !== RenderStateInternal.Root) {
464
479
  if (_throwIfNested) {
465
480
  throw new Error("There's already a <RenderStateRoot> above this instance in " + "the render tree. This instance should be removed.");
466
481
  }
467
482
  return React__namespace.createElement(React__namespace.Fragment, null, children);
468
483
  }
469
- const value = firstRender ? RenderState.Initial : RenderState.Standard;
484
+ const value = firstRender ? RenderStateInternal.Initial : RenderStateInternal.Standard;
470
485
  return React__namespace.createElement(RenderStateContext.Provider, {
471
486
  value: value
472
487
  }, children);
473
488
  };
474
489
 
475
490
  exports.IDProvider = IDProvider;
491
+ exports.Id = Id;
476
492
  exports.InitialFallback = InitialFallback;
477
493
  exports.RenderState = RenderState;
478
494
  exports.RenderStateRoot = RenderStateRoot;
@@ -80,6 +80,8 @@ export type TextViewSharedProps = {
80
80
  } & AriaProps & EventHandlers;
81
81
  /**
82
82
  * Interface implemented by types that can provide identifiers.
83
+ * @deprecated Use `useId` for your ID needs. If you are in a class-based
84
+ * component and cannot use hooks, then use the `Id` component.
83
85
  */
84
86
  export interface IIdentifierFactory {
85
87
  get(id: string): string;
@@ -3,6 +3,9 @@ import type { IIdentifierFactory } from "./types";
3
3
  * This is NOT for direct use. Instead, see the UniqueIDProvider component.
4
4
  *
5
5
  * Implements IIdentifierFactory to provide unique identifiers.
6
+ *
7
+ * @deprecated Use `useId` for your ID needs. If you are in a class-based
8
+ * component and cannot use hooks, then use the `Id` component.
6
9
  */
7
10
  export default class UniqueIDFactory implements IIdentifierFactory {
8
11
  _uniqueFactoryName: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-core",
3
- "version": "8.0.0",
3
+ "version": "10.0.0",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"