@khanacademy/wonder-blocks-core 4.3.2 → 4.4.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,11 @@
1
1
  # @khanacademy/wonder-blocks-core
2
2
 
3
+ ## 4.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6ee20af9: Add `useOnline` hook to encapsulate navigator.onLine and the offline/online events
8
+
3
9
  ## 4.3.2
4
10
 
5
11
  ### Patch Changes
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 as useContext$1, useRef } from 'react';
4
+ import { 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) {
@@ -267,7 +267,9 @@ class WithSSRPlaceholder extends React.Component {
267
267
  }
268
268
 
269
269
  {
270
- console.log(`We got a render state we don't understand: "${JSON.stringify(renderState)}"`);
270
+ var _JSON$stringify;
271
+
272
+ console.log(`We got a render state we don't understand: "${(_JSON$stringify = JSON.stringify(renderState)) != null ? _JSON$stringify : ""}"`);
271
273
  return this._maybeRender(RenderState.Root);
272
274
  }
273
275
  }
@@ -438,6 +440,21 @@ const useForceUpdate = () => {
438
440
  return forceUpdate;
439
441
  };
440
442
 
443
+ const useOnline = () => {
444
+ const forceUpdate = useForceUpdate();
445
+ useEffect$1(() => {
446
+ const handleChange = () => forceUpdate();
447
+
448
+ window.addEventListener("online", handleChange);
449
+ window.addEventListener("offline", handleChange);
450
+ return () => {
451
+ window.removeEventListener("online", handleChange);
452
+ window.removeEventListener("offline", handleChange);
453
+ };
454
+ }, [forceUpdate]);
455
+ return navigator.onLine;
456
+ };
457
+
441
458
  const {
442
459
  useContext,
443
460
  useEffect,
@@ -470,4 +487,4 @@ RenderStateRoot.defaultProps = {
470
487
  throwIfNested: true
471
488
  };
472
489
 
473
- export { IDProvider, RenderStateRoot, server as Server, Text, UniqueIDProvider, View, WithSSRPlaceholder, addStyle, useForceUpdate, useUniqueIdWithMock, useUniqueIdWithoutMock };
490
+ export { IDProvider, RenderStateRoot, server as Server, Text, UniqueIDProvider, View, WithSSRPlaceholder, addStyle, useForceUpdate, useOnline, useUniqueIdWithMock, useUniqueIdWithoutMock };
package/dist/index.js CHANGED
@@ -82,7 +82,7 @@ module.exports =
82
82
  /******/
83
83
  /******/
84
84
  /******/ // Load entry module and return exports
85
- /******/ return __webpack_require__(__webpack_require__.s = 16);
85
+ /******/ return __webpack_require__(__webpack_require__.s = 18);
86
86
  /******/ })
87
87
  /************************************************************************/
88
88
  /******/ ([
@@ -101,7 +101,7 @@ module.exports = require("react");
101
101
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
102
102
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
103
103
 
104
- const RenderState = __webpack_require__(18)({
104
+ const RenderState = __webpack_require__(20)({
105
105
  Root: "root",
106
106
  Initial: "initial",
107
107
  Standard: "standard"
@@ -136,12 +136,13 @@ module.exports = require("aphrodite");
136
136
 
137
137
  "use strict";
138
138
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return addStyle; });
139
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
140
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
141
- /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
142
- /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
143
- /* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
144
- function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
139
+ /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8);
140
+ /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__);
141
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
142
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
143
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
144
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_2__);
145
+ /* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
145
146
 
146
147
 
147
148
 
@@ -161,8 +162,8 @@ function addStyle(Component, defaultStyle) {
161
162
  const {
162
163
  className: aphroditeClassName,
163
164
  style: inlineStyles
164
- } = Object(_util_js__WEBPACK_IMPORTED_MODULE_2__[/* processStyleList */ "a"])([reset, defaultStyle, style]);
165
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](Component, _extends({}, otherProps, {
165
+ } = Object(_util_js__WEBPACK_IMPORTED_MODULE_3__[/* processStyleList */ "a"])([reset, defaultStyle, style]);
166
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](Component, _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default()({}, otherProps, {
166
167
  className: [aphroditeClassName, className].filter(Boolean).join(" "),
167
168
  style: inlineStyles
168
169
  }));
@@ -176,7 +177,7 @@ function addStyle(Component, defaultStyle) {
176
177
  * they appear in https://github.com/necolas/normalize.css/blob/master/normalize.css.
177
178
  */
178
179
 
179
- const overrides = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
180
+ const overrides = aphrodite__WEBPACK_IMPORTED_MODULE_2__["StyleSheet"].create({
180
181
  button: {
181
182
  margin: 0,
182
183
  // Safari adds 2px left/right margins
@@ -282,24 +283,27 @@ UniqueIDFactory._factoryUniquenessCounter = 0;
282
283
  /**
283
284
  * Defer or change rendering until the component did mount.
284
285
  *
285
- * The purpose of this component is to disable or modify serverside rendering
286
+ * The purpose of this component is to disable or modify server-side rendering
286
287
  * of certain components. Disabling rendering on the server, by itself, would
287
- * not be sufficient, since the initial render of the component must match
288
- * what is rendered on the server. Therefore, this component also disables
289
- * rendering the first time around on the client.
288
+ * not be sufficient, since the initial render of the component must match what
289
+ * is rendered on the server. Therefore, this component also disables rendering
290
+ * the first time around on the client.
290
291
  *
291
- * If `WithSSRPlaceholder` components are nested within one another,
292
- * the root `WithSSRPlaceholder` component will handle the initial
293
- * render, but nested `WithSSRPlaceholder` components will delegate to
294
- * the root one, meaning that we don't cascade delayed rendering down
295
- * the component tree. This will also be the case across portal
296
- * boundaries.
292
+ * If `WithSSRPlaceholder` components are nested within one another, the root
293
+ * `WithSSRPlaceholder` component will handle the initial render, but nested
294
+ * `WithSSRPlaceholder` components will delegate to the root one, meaning that
295
+ * we don't cascade delayed rendering down the component tree. This will also be
296
+ * the case across portal boundaries.
297
297
  *
298
- * Example:
298
+ * ## Usage
299
299
  *
300
300
  * ```js
301
+ * import {WithSSRPlaceholder} from "@khanacademy/wonder-blocks-core";
302
+ *
301
303
  * <WithSSRPlaceholder placeholder={() => <div>Renders on the server!</div>}>
302
- * {() => <div>Only renders on the client (after rehydration).</div>}
304
+ * {() => (
305
+ * <div>This is rendered only by the client, for all renders after the rehydration render</div>
306
+ * )}
303
307
  * </WithSSRPlaceholder>
304
308
  * ```
305
309
  */
@@ -401,11 +405,13 @@ class WithSSRPlaceholder extends react__WEBPACK_IMPORTED_MODULE_0__["Component"]
401
405
 
402
406
 
403
407
  {
408
+ var _JSON$stringify;
409
+
404
410
  // Let's log this case so we can debug it easily.
405
411
  // Then fall through to the root case.
406
412
 
407
413
  /* eslint-disable-next-line no-console */
408
- console.log(`We got a render state we don't understand: "${JSON.stringify(renderState)}"`); // We "fallthrough" to the root case. This is more obvious
414
+ console.log(`We got a render state we don't understand: "${(_JSON$stringify = JSON.stringify(renderState)) != null ? _JSON$stringify : ""}"`); // We "fallthrough" to the root case. This is more obvious
409
415
  // and maintainable code than just ignoring the no-fallthrough
410
416
  // lint rule.
411
417
 
@@ -429,7 +435,7 @@ class WithSSRPlaceholder extends react__WEBPACK_IMPORTED_MODULE_0__["Component"]
429
435
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
430
436
  /* harmony import */ var _with_ssr_placeholder_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
431
437
  /* harmony import */ var _util_unique_id_factory_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
432
- /* harmony import */ var _util_ssr_id_factory_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
438
+ /* harmony import */ var _util_ssr_id_factory_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
433
439
 
434
440
 
435
441
 
@@ -450,6 +456,18 @@ class WithSSRPlaceholder extends react__WEBPACK_IMPORTED_MODULE_0__["Component"]
450
456
  * unique. Therefore, `get("test")` will always equal `get("test")`, and
451
457
  * `get("test2")` will always equal `get("test2")`, but `get("test")` will
452
458
  * never equal `get("test2")`.
459
+ *
460
+ * ## Usage
461
+ *
462
+ * ```jsx
463
+ * import {UniqueIDProvider} from "@khanacademy/wonder-blocks-core";
464
+ *
465
+ * <UniqueIDProvider mockOnFirstRender={false} scope="field">
466
+ * {(ids) => (
467
+ * <>The id returned for "my-identifier": {ids.get("my-identifier")}</>
468
+ * )}
469
+ * </UniqueIDProvider>
470
+ * ```
453
471
  */
454
472
  class UniqueIDProvider extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
455
473
  _performRender(firstRender) {
@@ -495,6 +513,57 @@ class UniqueIDProvider extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
495
513
  /* 7 */
496
514
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
497
515
 
516
+ "use strict";
517
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useForceUpdate; });
518
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
519
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
520
+
521
+ /**
522
+ * Hook for forcing a component to update on demand.
523
+ *
524
+ * This is for use inside other hooks that do some advanced
525
+ * trickery with storing state outside of React's own state
526
+ * mechanisms. As such this should never be called directly
527
+ * outside of a hook, and more often than not, is the wrong
528
+ * choice for whatever you are trying to do. If in doubt,
529
+ * don't use it.
530
+ *
531
+ * @returns {() => void} A function that forces the component to update.
532
+ */
533
+
534
+ const useForceUpdate = () => {
535
+ const [, setState] = react__WEBPACK_IMPORTED_MODULE_0__["useState"](false);
536
+ const forceUpdate = react__WEBPACK_IMPORTED_MODULE_0__["useCallback"](() => setState(state => !state), []);
537
+ return forceUpdate;
538
+ };
539
+
540
+ /***/ }),
541
+ /* 8 */
542
+ /***/ (function(module, exports) {
543
+
544
+ function _extends() {
545
+ module.exports = _extends = Object.assign ? Object.assign.bind() : function (target) {
546
+ for (var i = 1; i < arguments.length; i++) {
547
+ var source = arguments[i];
548
+
549
+ for (var key in source) {
550
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
551
+ target[key] = source[key];
552
+ }
553
+ }
554
+ }
555
+
556
+ return target;
557
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports;
558
+ return _extends.apply(this, arguments);
559
+ }
560
+
561
+ module.exports = _extends, module.exports.__esModule = true, module.exports["default"] = module.exports;
562
+
563
+ /***/ }),
564
+ /* 9 */
565
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
566
+
498
567
  "use strict";
499
568
  /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return processStyleList; });
500
569
  /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
@@ -573,10 +642,10 @@ function processStyleList(style) {
573
642
  className: aphrodite__WEBPACK_IMPORTED_MODULE_0__["css"].apply(void 0, stylesheetStyles)
574
643
  };
575
644
  }
576
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(17)))
645
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(19)))
577
646
 
578
647
  /***/ }),
579
- /* 8 */
648
+ /* 10 */
580
649
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
581
650
 
582
651
  "use strict";
@@ -601,7 +670,7 @@ SsrIDFactory.Default = new SsrIDFactory();
601
670
  /* harmony default export */ __webpack_exports__["a"] = (SsrIDFactory.Default);
602
671
 
603
672
  /***/ }),
604
- /* 9 */
673
+ /* 11 */
605
674
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
606
675
 
607
676
  "use strict";
@@ -609,7 +678,7 @@ SsrIDFactory.Default = new SsrIDFactory();
609
678
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return useUniqueIdWithoutMock; });
610
679
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
611
680
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
612
- /* harmony import */ var _util_ssr_id_factory_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
681
+ /* harmony import */ var _util_ssr_id_factory_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
613
682
  /* harmony import */ var _util_unique_id_factory_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
614
683
  /* harmony import */ var _components_render_state_context_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1);
615
684
 
@@ -671,23 +740,24 @@ const useUniqueIdWithoutMock = scope => {
671
740
  };
672
741
 
673
742
  /***/ }),
674
- /* 10 */
743
+ /* 12 */
675
744
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
676
745
 
677
746
  "use strict";
678
747
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Text; });
679
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
680
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
681
- /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
682
- /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
683
- /* harmony import */ var _util_util_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
684
- function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
748
+ /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8);
749
+ /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__);
750
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
751
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
752
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
753
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_2__);
754
+ /* harmony import */ var _util_util_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
685
755
 
686
756
 
687
757
 
688
758
 
689
759
  const isHeaderRegex = /^h[1-6]$/;
690
- const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
760
+ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_2__["StyleSheet"].create({
691
761
  text: {
692
762
  // Disable subpixel antialiasing on Mac desktop for consistency of
693
763
  // rendering with mobile and Sketch (neither of which support it).
@@ -715,7 +785,7 @@ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
715
785
  * - An array combining the above
716
786
  */
717
787
 
718
- class Text extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
788
+ class Text extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
719
789
  render() {
720
790
  const {
721
791
  children,
@@ -725,8 +795,8 @@ class Text extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
725
795
  ...otherProps
726
796
  } = this.props;
727
797
  const isHeader = isHeaderRegex.test(Tag);
728
- const styleAttributes = Object(_util_util_js__WEBPACK_IMPORTED_MODULE_2__[/* processStyleList */ "a"])([styles.text, isHeader && styles.header, style]);
729
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](Tag, _extends({}, otherProps, {
798
+ const styleAttributes = Object(_util_util_js__WEBPACK_IMPORTED_MODULE_3__[/* processStyleList */ "a"])([styles.text, isHeader && styles.header, style]);
799
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](Tag, _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default()({}, otherProps, {
730
800
  style: styleAttributes.style,
731
801
  className: styleAttributes.className,
732
802
  "data-test-id": testId
@@ -739,7 +809,7 @@ Text.defaultProps = {
739
809
  };
740
810
 
741
811
  /***/ }),
742
- /* 11 */
812
+ /* 13 */
743
813
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
744
814
 
745
815
  "use strict";
@@ -777,9 +847,8 @@ const StyledNav = Object(_util_add_style_js__WEBPACK_IMPORTED_MODULE_2__[/* defa
777
847
  const StyledSection = Object(_util_add_style_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ "a"])("section", styles.default);
778
848
  /**
779
849
  * View is a building block for constructing other components. `View` roughly
780
- * maps to `div` and `Text` roughly maps to `span`. You can override which tag
781
- * is used to render the component (for semantic purposes) by specifying the
782
- * `tag` prop.
850
+ * maps to `div`. You can override which tag is used to render the component
851
+ * (for semantic purposes) by specifying the `tag` prop.
783
852
  *
784
853
  * These components can take styles (via the `style` prop) in a variety of
785
854
  * manners:
@@ -787,6 +856,20 @@ const StyledSection = Object(_util_add_style_js__WEBPACK_IMPORTED_MODULE_2__[/*
787
856
  * - An inline style object
788
857
  * - An `aphrodite` StyleSheet style
789
858
  * - An array combining the above
859
+ *
860
+ * `View` sets the following defaults:
861
+ *
862
+ * - `display: "flex"`
863
+ * - `flexDirection: "column"`
864
+ * - they each get their own stacking context.
865
+ *
866
+ * ### Usage
867
+ *
868
+ * ```jsx
869
+ * import {View} from "@khanacademy/wonder-blocks-core";
870
+ *
871
+ * <View>This is a View!</View>
872
+ * ```
790
873
  */
791
874
 
792
875
  class View extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
@@ -829,7 +912,7 @@ View.defaultProps = {
829
912
  };
830
913
 
831
914
  /***/ }),
832
- /* 12 */
915
+ /* 14 */
833
916
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
834
917
 
835
918
  "use strict";
@@ -841,18 +924,33 @@ View.defaultProps = {
841
924
 
842
925
 
843
926
  /**
844
- * This is a wrapper that returns an identifier. If the `id` prop is set, the component will
845
- * return the same id to be consumed by its children. Otherwise, a unique id will be provided.
846
- * This is beneficial for accessibility purposes, among other things.
927
+ * This is a wrapper that returns an identifier. If the `id` prop is set, the
928
+ * component will return the same id to be consumed by its children. Otherwise,
929
+ * a unique id will be provided. This is beneficial for accessibility purposes,
930
+ * among other things.
931
+ *
932
+ * The main difference with `UniqueIDProvider` is that `IDProvider` has a single
933
+ * responsibility, to return an identifier that can by used by the children that
934
+ * are rendered internally.
847
935
  *
848
- * The main difference with UniqueIDProvider is that IDProvider has a single responsibility,
849
- * to return an identifier that can by used by the children that are rendered internally.
936
+ * This way, the wrapped component will receive this custom ID and will use it
937
+ * to connect different elements.
850
938
  *
851
- * This way, the wrapped component will receive this custom ID and will use it to connect
852
- * different elements.
939
+ * e.g. It uses the same generated id to connect a Dialog with its main title,
940
+ * or form label with the associated input element, etc.
941
+ *
942
+ * ## Usage
943
+ *
944
+ * ```jsx
945
+ * import {IDProvider} from "@khanacademy/wonder-blocks-core";
946
+ *
947
+ * <IDProvider scope="field">
948
+ * {(uniqueId) => (
949
+ * Unique ID: {uniqueId}
950
+ * )}
951
+ * </IDProvider>
952
+ * ```
853
953
  *
854
- * e.g. It uses the same generated id to connect a Dialog with its main title, or form label
855
- * with the associated input element, etc.
856
954
  */
857
955
  class IDProvider extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
858
956
  renderChildren(ids) {
@@ -891,7 +989,7 @@ class IDProvider extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
891
989
  IDProvider.defaultId = "wb-id";
892
990
 
893
991
  /***/ }),
894
- /* 13 */
992
+ /* 15 */
895
993
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
896
994
 
897
995
  "use strict";
@@ -914,35 +1012,42 @@ let serverSide = false;
914
1012
  });
915
1013
 
916
1014
  /***/ }),
917
- /* 14 */
1015
+ /* 16 */
918
1016
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
919
1017
 
920
1018
  "use strict";
921
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useForceUpdate; });
1019
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useOnline; });
922
1020
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
923
1021
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
1022
+ /* harmony import */ var _use_force_update_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
1023
+
924
1024
 
925
1025
  /**
926
- * Hook for forcing a component to update on demand.
1026
+ * Track the online status of the browser.
927
1027
  *
928
- * This is for use inside other hooks that do some advanced
929
- * trickery with storing state outside of React's own state
930
- * mechanisms. As such this should never be called directly
931
- * outside of a hook, and more often than not, is the wrong
932
- * choice for whatever you are trying to do. If in doubt,
933
- * don't use it.
1028
+ * This hook monitors the offline and online events, forcing the consuming
1029
+ * component to re-render when they fire.
934
1030
  *
935
- * @returns {() => void} A function that forces the component to update.
1031
+ * @returns {boolean} The current value of `navigator.onLine`.
936
1032
  */
937
1033
 
938
- const useForceUpdate = () => {
939
- const [, setState] = react__WEBPACK_IMPORTED_MODULE_0__["useState"](false);
940
- const forceUpdate = react__WEBPACK_IMPORTED_MODULE_0__["useCallback"](() => setState(state => !state), []);
941
- return forceUpdate;
1034
+ const useOnline = () => {
1035
+ const forceUpdate = Object(_use_force_update_js__WEBPACK_IMPORTED_MODULE_1__[/* useForceUpdate */ "a"])();
1036
+ Object(react__WEBPACK_IMPORTED_MODULE_0__["useEffect"])(() => {
1037
+ const handleChange = () => forceUpdate();
1038
+
1039
+ window.addEventListener("online", handleChange);
1040
+ window.addEventListener("offline", handleChange);
1041
+ return () => {
1042
+ window.removeEventListener("online", handleChange);
1043
+ window.removeEventListener("offline", handleChange);
1044
+ };
1045
+ }, [forceUpdate]);
1046
+ return navigator.onLine;
942
1047
  };
943
1048
 
944
1049
  /***/ }),
945
- /* 15 */
1050
+ /* 17 */
946
1051
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
947
1052
 
948
1053
  "use strict";
@@ -991,21 +1096,21 @@ RenderStateRoot.defaultProps = {
991
1096
  };
992
1097
 
993
1098
  /***/ }),
994
- /* 16 */
1099
+ /* 18 */
995
1100
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
996
1101
 
997
1102
  "use strict";
998
1103
  __webpack_require__.r(__webpack_exports__);
999
- /* harmony import */ var _components_text_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
1104
+ /* harmony import */ var _components_text_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12);
1000
1105
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Text", function() { return _components_text_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
1001
1106
 
1002
- /* harmony import */ var _components_view_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
1107
+ /* harmony import */ var _components_view_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(13);
1003
1108
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "View", function() { return _components_view_js__WEBPACK_IMPORTED_MODULE_1__["a"]; });
1004
1109
 
1005
1110
  /* harmony import */ var _components_with_ssr_placeholder_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
1006
1111
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "WithSSRPlaceholder", function() { return _components_with_ssr_placeholder_js__WEBPACK_IMPORTED_MODULE_2__["a"]; });
1007
1112
 
1008
- /* harmony import */ var _components_id_provider_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12);
1113
+ /* harmony import */ var _components_id_provider_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(14);
1009
1114
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "IDProvider", function() { return _components_id_provider_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
1010
1115
 
1011
1116
  /* harmony import */ var _components_unique_id_provider_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
@@ -1014,19 +1119,23 @@ __webpack_require__.r(__webpack_exports__);
1014
1119
  /* harmony import */ var _util_add_style_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3);
1015
1120
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "addStyle", function() { return _util_add_style_js__WEBPACK_IMPORTED_MODULE_5__["a"]; });
1016
1121
 
1017
- /* harmony import */ var _util_server_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(13);
1122
+ /* harmony import */ var _util_server_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(15);
1018
1123
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Server", function() { return _util_server_js__WEBPACK_IMPORTED_MODULE_6__["a"]; });
1019
1124
 
1020
- /* harmony import */ var _hooks_use_unique_id_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9);
1125
+ /* harmony import */ var _hooks_use_unique_id_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(11);
1021
1126
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useUniqueIdWithMock", function() { return _hooks_use_unique_id_js__WEBPACK_IMPORTED_MODULE_7__["a"]; });
1022
1127
 
1023
1128
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useUniqueIdWithoutMock", function() { return _hooks_use_unique_id_js__WEBPACK_IMPORTED_MODULE_7__["b"]; });
1024
1129
 
1025
- /* harmony import */ var _hooks_use_force_update_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(14);
1130
+ /* harmony import */ var _hooks_use_force_update_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(7);
1026
1131
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useForceUpdate", function() { return _hooks_use_force_update_js__WEBPACK_IMPORTED_MODULE_8__["a"]; });
1027
1132
 
1028
- /* harmony import */ var _components_render_state_root_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(15);
1029
- /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RenderStateRoot", function() { return _components_render_state_root_js__WEBPACK_IMPORTED_MODULE_9__["a"]; });
1133
+ /* harmony import */ var _hooks_use_online_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(16);
1134
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useOnline", function() { return _hooks_use_online_js__WEBPACK_IMPORTED_MODULE_9__["a"]; });
1135
+
1136
+ /* harmony import */ var _components_render_state_root_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(17);
1137
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RenderStateRoot", function() { return _components_render_state_root_js__WEBPACK_IMPORTED_MODULE_10__["a"]; });
1138
+
1030
1139
 
1031
1140
 
1032
1141
 
@@ -1040,7 +1149,7 @@ __webpack_require__.r(__webpack_exports__);
1040
1149
 
1041
1150
 
1042
1151
  /***/ }),
1043
- /* 17 */
1152
+ /* 19 */
1044
1153
  /***/ (function(module, exports) {
1045
1154
 
1046
1155
  var g;
@@ -1066,7 +1175,7 @@ module.exports = g;
1066
1175
 
1067
1176
 
1068
1177
  /***/ }),
1069
- /* 18 */
1178
+ /* 20 */
1070
1179
  /***/ (function(module, exports) {
1071
1180
 
1072
1181
  module.exports = require("flow-enums-runtime");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-core",
3
- "version": "4.3.2",
3
+ "version": "4.4.0",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -13,7 +13,7 @@
13
13
  "test": "echo \"Error: no test specified\" && exit 1"
14
14
  },
15
15
  "dependencies": {
16
- "@babel/runtime": "^7.16.3",
16
+ "@babel/runtime": "^7.18.6",
17
17
  "@khanacademy/wonder-blocks-spacing": "^3.0.5"
18
18
  },
19
19
  "peerDependencies": {
@@ -0,0 +1,16 @@
1
+ import {Meta} from "@storybook/addon-docs";
2
+
3
+ <Meta
4
+ title="Core / Overview"
5
+ parameters={{
6
+ chromatic: {
7
+ disableSnapshot: true,
8
+ },
9
+ }}
10
+ />
11
+
12
+ # Core
13
+
14
+ `wonder-blocks-core` provides building blocks and utilities for constructing
15
+ other wonder-blocks components. Many of these may be useful inside your
16
+ applications, as well.
@@ -0,0 +1,18 @@
1
+ import {Meta} from "@storybook/addon-docs";
2
+
3
+ <Meta
4
+ title="Core / Exports / useForceUpdate()"
5
+ parameters={{
6
+ chromatic: {
7
+ disableSnapshot: true,
8
+ },
9
+ }}
10
+ />
11
+
12
+ # useForceUpdate()
13
+
14
+ ```ts
15
+ function useForceUpdate(): () => void;
16
+ ```
17
+
18
+ The `useForceUpdate` hook returns a function that can be called to force a component to re-render. This is usually not needed as you should be using `useState` or `useReducer` to manage state and rendering in your component (along with `useCallback` and `useMemo` as necessary). However, there maybe times where caching is used to avoid state. In those cases, the `useForceUpdate` hook can be used to force a re-render upon cached data changing or some other triggering event.
@@ -0,0 +1,20 @@
1
+ import {Meta} from "@storybook/addon-docs";
2
+
3
+ <Meta
4
+ title="Core / Exports / useOnline()"
5
+ parameters={{
6
+ chromatic: {
7
+ disableSnapshot: true,
8
+ },
9
+ }}
10
+ />
11
+
12
+ # useOnline()
13
+
14
+ ```ts
15
+ function useOnline(): boolean;
16
+ ```
17
+
18
+ The `useOnline` hook returns the value of `navigator.onLine`. It also listens
19
+ to the `online` and `offline` events and triggers a render of the component on
20
+ those events.