@teambit/react.ui.loader-fallback 0.0.0-5f312aa95ec8fc788d5968eb3a7bd69db85b7b87

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.
@@ -0,0 +1,2 @@
1
+ export { LoaderFallback, useFallback } from './loader-fallback';
2
+ export type { LoaderProps, useFallbackOptions } from './loader-fallback';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFallback = exports.LoaderFallback = void 0;
4
+ var loader_fallback_1 = require("./loader-fallback");
5
+ Object.defineProperty(exports, "LoaderFallback", { enumerable: true, get: function () { return loader_fallback_1.LoaderFallback; } });
6
+ Object.defineProperty(exports, "useFallback", { enumerable: true, get: function () { return loader_fallback_1.useFallback; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,qDAAgE;AAAvD,iHAAA,cAAc,OAAA;AAAE,8GAAA,WAAW,OAAA"}
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ export declare const RegularComponent: () => React.JSX.Element;
3
+ export declare const UndefinedComponent: () => React.JSX.Element;
4
+ export declare const ChangingComponent: () => React.JSX.Element;
5
+ export declare const LongChangingComponent: () => React.JSX.Element;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.LongChangingComponent = exports.ChangingComponent = exports.UndefinedComponent = exports.RegularComponent = void 0;
27
+ const react_1 = __importStar(require("react"));
28
+ const loader_fallback_1 = require("./loader-fallback");
29
+ const RegularComponent = () => {
30
+ return react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: Component, DefaultComponent: Fallback });
31
+ };
32
+ exports.RegularComponent = RegularComponent;
33
+ const UndefinedComponent = () => {
34
+ return react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: undefined, DefaultComponent: Fallback });
35
+ };
36
+ exports.UndefinedComponent = UndefinedComponent;
37
+ const ChangingComponent = () => {
38
+ const [current, setCurrent] = (0, react_1.useState)(() => Component);
39
+ (0, react_1.useEffect)(() => {
40
+ const intervalId = setInterval(() => {
41
+ setCurrent((x) => (x ? undefined : Component));
42
+ }, 2000);
43
+ return () => clearInterval(intervalId);
44
+ }, []);
45
+ return (react_1.default.createElement("div", { style: { width: 200, height: '3em' } },
46
+ react_1.default.createElement("div", { style: { fontSize: '0.8em' } }, "(this will not timeout, and show only the loader)"),
47
+ react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: current, DefaultComponent: Fallback })));
48
+ };
49
+ exports.ChangingComponent = ChangingComponent;
50
+ const LongChangingComponent = () => {
51
+ const [current, setCurrent] = (0, react_1.useState)(() => Component);
52
+ (0, react_1.useEffect)(() => {
53
+ const intervalId = setInterval(() => {
54
+ setCurrent((x) => (x ? undefined : Component));
55
+ }, 6000);
56
+ return () => clearInterval(intervalId);
57
+ }, []);
58
+ return (react_1.default.createElement("div", { style: { width: 200, height: '3em' } },
59
+ react_1.default.createElement("div", { style: { fontSize: '0.8em' } }, "(this will timeout, showing the fallback component)"),
60
+ react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: current, DefaultComponent: Fallback, timeout: 2000 })));
61
+ };
62
+ exports.LongChangingComponent = LongChangingComponent;
63
+ function Component() {
64
+ return react_1.default.createElement("div", { style: { color: '#2e945a' } }, "\u2713 actual component");
65
+ }
66
+ function Fallback() {
67
+ return react_1.default.createElement("div", null, "target is (undefined)");
68
+ }
69
+ //# sourceMappingURL=loader-fallback.compositions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-fallback.compositions.js","sourceRoot":"","sources":["../loader-fallback.compositions.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+CAAmD;AACnD,uDAAmD;AAE5C,MAAM,gBAAgB,GAAG,GAAG,EAAE;IACnC,OAAO,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,GAAI,CAAC;AAC3E,CAAC,CAAC;AAFW,QAAA,gBAAgB,oBAE3B;AAEK,MAAM,kBAAkB,GAAG,GAAG,EAAE;IACrC,OAAO,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,GAAI,CAAC;AAC3E,CAAC,CAAC;AAFW,QAAA,kBAAkB,sBAE7B;AAEK,MAAM,iBAAiB,GAAG,GAAG,EAAE;IACpC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAA4B,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAEnF,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,UAAU,CAAC,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QACjE,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,uCAAK,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE;QACvC,uCAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,wDAAyD;QAC1F,8BAAC,gCAAc,IAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,GAAI,CAC3D,CACP,CAAC;AACJ,CAAC,CAAC;AAjBW,QAAA,iBAAiB,qBAiB5B;AAEK,MAAM,qBAAqB,GAAG,GAAG,EAAE;IACxC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAA4B,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAEnF,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,UAAU,CAAC,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QACjE,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,uCAAK,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE;QACvC,uCAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,0DAA2D;QAC5F,8BAAC,gCAAc,IAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,GAAI,CAC1E,CACP,CAAC;AACJ,CAAC,CAAC;AAjBW,QAAA,qBAAqB,yBAiBhC;AAEF,SAAS,SAAS;IAChB,OAAO,uCAAK,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,8BAA0B,CAAC;AACpE,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,mEAAgC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ComponentType, ReactElement } from 'react';
2
+ import React from 'react';
3
+ export type LoaderProps = {
4
+ /** component to render */
5
+ Target: ComponentType | undefined;
6
+ /** component to render when Target is undefined */
7
+ DefaultComponent: ComponentType;
8
+ /** component to render when target is missing, for a grace period, until rendering the default */
9
+ Loader?: ComponentType;
10
+ /** cool-down period (in ms) to show Loader, before showing the default */
11
+ timeout?: number;
12
+ };
13
+ export declare function LoaderFallback({ Target, Loader, DefaultComponent, timeout }: LoaderProps): ReactElement<any, string | React.JSXElementConstructor<any>>;
14
+ export type useFallbackOptions = {
15
+ timeout?: number;
16
+ loader?: ReactElement;
17
+ };
18
+ export declare function useFallback(target: ReactElement | null | undefined, fallback: ReactElement, { timeout, loader }?: useFallbackOptions): ReactElement | null;
@@ -0,0 +1,45 @@
1
+ import { LoaderFallback } from './loader-fallback';
2
+
3
+ Safely render a component, with a default fallback when it is `undefined`.
4
+ The `LoaderFallback` component also provides a grace period, where it shows a loader before switching to the default.
5
+ Set `timeout = 0` to skip the grace period.
6
+
7
+ #### Example usage:
8
+
9
+ ```tsx
10
+ // as a hook:
11
+ const safeTarget = useFallback(Target && <Target />, <DefaultComponent />, { timeout: 10000, loader: <Loader /> });
12
+
13
+ // as a component:
14
+ <LoaderFallback Target={Target} DefaultComponent={DefaultComponent} timeout={10000} loader={Loader}>
15
+ ```
16
+
17
+ ### Logic is as follows:
18
+
19
+ 1. when component is `defined` -> render it
20
+ 1. when the initial value of the component is `undefined` -> show the default immediately
21
+ 1. when the component changes to be `undefined` -> show Loader for _x_ seconds
22
+ 1. then, after _x_ seconds - show the default.
23
+
24
+ <!-- live playground doesn't keep state when editing :( -->
25
+ <!-- Try it out:
26
+
27
+ ```tsx live
28
+ function Example() {
29
+ return (
30
+ <LoaderFallback
31
+ Target={RegularComponent} // comment this out
32
+ DefaultComponent={Fallback}
33
+ timeout={2000}
34
+ />
35
+ );
36
+
37
+ function RegularComponent() {
38
+ return <div>regular component</div>;
39
+ }
40
+
41
+ function Fallback() {
42
+ return <div>this shows when component is undefined</div>;
43
+ }
44
+ }
45
+ ``` -->
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.LoaderFallback = LoaderFallback;
27
+ exports.useFallback = useFallback;
28
+ const react_1 = __importStar(require("react"));
29
+ const base_ui_loaders_loader_ribbon_1 = require("@teambit/base-ui.loaders.loader-ribbon");
30
+ function LoaderFallback({ Target, Loader = LoaderComponent, DefaultComponent, timeout = 15000 }) {
31
+ return useFallback(Target && react_1.default.createElement(Target, null), react_1.default.createElement(DefaultComponent, null), { timeout, loader: react_1.default.createElement(Loader, null) });
32
+ }
33
+ function useFallback(target, fallback, { timeout = 15000, loader = react_1.default.createElement(LoaderComponent, null) } = {}) {
34
+ const [working, setWorking] = (0, react_1.useState)(!!target);
35
+ const hasTarget = !!target;
36
+ (0, react_1.useEffect)(() => {
37
+ if (timeout <= 0)
38
+ return () => { };
39
+ if (hasTarget) {
40
+ setWorking(true);
41
+ return () => { };
42
+ }
43
+ const tmId = setTimeout(() => setWorking(false), timeout);
44
+ return () => clearTimeout(tmId);
45
+ }, [hasTarget, timeout]);
46
+ if (target)
47
+ return target;
48
+ if (working && timeout > 0)
49
+ return loader;
50
+ return fallback;
51
+ }
52
+ function LoaderComponent() {
53
+ return react_1.default.createElement(base_ui_loaders_loader_ribbon_1.LoaderRibbon, { active: true, style: { position: 'fixed', top: 0, left: 0, right: 0 } });
54
+ }
55
+ //# sourceMappingURL=loader-fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-fallback.js","sourceRoot":"","sources":["../loader-fallback.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAeA,wCAEC;AAID,kCAsBC;AA1CD,+CAAmD;AACnD,0FAAsE;AAatE,SAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,gBAAgB,EAAE,OAAO,GAAG,KAAK,EAAe;IACjH,OAAO,WAAW,CAAC,MAAM,IAAI,8BAAC,MAAM,OAAG,EAAE,8BAAC,gBAAgB,OAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,8BAAC,MAAM,OAAG,EAAE,CAAC,CAAC;AAClG,CAAC;AAID,SAAgB,WAAW,CACzB,MAAuC,EACvC,QAAsB,EACtB,EAAE,OAAO,GAAG,KAAK,EAAE,MAAM,GAAG,8BAAC,eAAe,OAAG,KAAyB,EAAE;IAE1E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAE3B,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,OAAO,IAAI,CAAC;YAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;QAClC,IAAI,SAAS,EAAE,CAAC;YACd,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAEzB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,OAAO,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,8BAAC,4CAAY,IAAC,MAAM,QAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAI,CAAC;AAC1F,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const react_1 = __importDefault(require("react"));
16
+ const react_2 = require("@testing-library/react");
17
+ const loader_fallback_1 = require("./loader-fallback");
18
+ describe('loader-fallback', () => {
19
+ it('should render target, when defined', () => {
20
+ const { getByText } = (0, react_2.render)(react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: Component, DefaultComponent: Default, Loader: Loader, timeout: 10 }));
21
+ // throws if not found, same as expect
22
+ getByText('test target');
23
+ });
24
+ it('should render default, when target is undefined', () => {
25
+ const { getByText } = (0, react_2.render)(react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: undefined, DefaultComponent: Default, Loader: Loader, timeout: 10 }));
26
+ // throws if not found, same as expect
27
+ getByText('Target is undefined');
28
+ });
29
+ it('should render loader, when target becomes undefined', () => {
30
+ const { rerender, getByText } = (0, react_2.render)(react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: Component, DefaultComponent: Default, Loader: Loader, timeout: 10 }));
31
+ rerender(react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: undefined, DefaultComponent: Default, Loader: Loader, timeout: 10 }));
32
+ // throws if not found, same as expect
33
+ getByText('loading...');
34
+ });
35
+ it('should render DefaultComponent, after timeout, when target becomes undefined', () => __awaiter(void 0, void 0, void 0, function* () {
36
+ const { rerender, getByText } = (0, react_2.render)(react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: Component, DefaultComponent: Default, Loader: Loader, timeout: 10 }));
37
+ rerender(react_1.default.createElement(loader_fallback_1.LoaderFallback, { Target: undefined, DefaultComponent: Default, Loader: Loader, timeout: 10 }));
38
+ yield (0, react_2.waitFor)(() => getByText('Target is undefined'));
39
+ }));
40
+ });
41
+ function Component() {
42
+ return react_1.default.createElement("div", null, "test target");
43
+ }
44
+ function Default() {
45
+ return react_1.default.createElement("div", null, "Target is undefined");
46
+ }
47
+ function Loader() {
48
+ return react_1.default.createElement("div", null, "loading...");
49
+ }
50
+ //# sourceMappingURL=loader-fallback.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-fallback.spec.js","sourceRoot":"","sources":["../loader-fallback.spec.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,kDAA0B;AAC1B,kDAAyD;AACzD,uDAAmD;AAEnD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,EAAE,SAAS,EAAE,GAAG,IAAA,cAAM,EAC1B,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAI,CAC9F,CAAC;QAEF,sCAAsC;QACtC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,EAAE,SAAS,EAAE,GAAG,IAAA,cAAM,EAC1B,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAI,CAC9F,CAAC;QAEF,sCAAsC;QACtC,SAAS,CAAC,qBAAqB,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAA,cAAM,EACpC,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAI,CAC9F,CAAC;QAEF,QAAQ,CAAC,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAI,CAAC,CAAC;QAExG,sCAAsC;QACtC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAS,EAAE;QAC5F,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAA,cAAM,EACpC,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAI,CAC9F,CAAC;QAEF,QAAQ,CAAC,8BAAC,gCAAc,IAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAI,CAAC,CAAC;QAExG,MAAM,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACxD,CAAC,CAAA,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,SAAS,SAAS;IAChB,OAAO,yDAAsB,CAAC;AAChC,CAAC;AAED,SAAS,OAAO;IACd,OAAO,iEAA8B,CAAC;AACxC,CAAC;AAED,SAAS,MAAM;IACb,OAAO,wDAAqB,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,7 @@
1
+ import * as compositions_0 from '/home/circleci/Library/Caches/Bit/capsules/8891be5ad/teambit.react_ui_loader-fallback@5f312aa95ec8fc788d5968eb3a7bd69db85b7b87/dist/loader-fallback.compositions.js';
2
+ import * as overview_0 from '/home/circleci/Library/Caches/Bit/capsules/8891be5ad/teambit.react_ui_loader-fallback@5f312aa95ec8fc788d5968eb3a7bd69db85b7b87/dist/loader-fallback.docs.mdx';
3
+
4
+ export const compositions = [compositions_0];
5
+ export const overview = [overview_0];
6
+
7
+ export const compositions_metadata = {"compositions":[{"displayName":"Regular component","identifier":"RegularComponent"},{"displayName":"Undefined component","identifier":"UndefinedComponent"},{"displayName":"Changing component","identifier":"ChangingComponent"},{"displayName":"Long changing component","identifier":"LongChangingComponent"}]};
package/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { LoaderFallback, useFallback } from './loader-fallback';
2
+ export type { LoaderProps, useFallbackOptions } from './loader-fallback';
@@ -0,0 +1,57 @@
1
+ import type { ComponentType } from 'react';
2
+ import React, { useEffect, useState } from 'react';
3
+ import { LoaderFallback } from './loader-fallback';
4
+
5
+ export const RegularComponent = () => {
6
+ return <LoaderFallback Target={Component} DefaultComponent={Fallback} />;
7
+ };
8
+
9
+ export const UndefinedComponent = () => {
10
+ return <LoaderFallback Target={undefined} DefaultComponent={Fallback} />;
11
+ };
12
+
13
+ export const ChangingComponent = () => {
14
+ const [current, setCurrent] = useState<ComponentType | undefined>(() => Component);
15
+
16
+ useEffect(() => {
17
+ const intervalId = setInterval(() => {
18
+ setCurrent((x?: ComponentType) => (x ? undefined : Component));
19
+ }, 2000);
20
+
21
+ return () => clearInterval(intervalId);
22
+ }, []);
23
+
24
+ return (
25
+ <div style={{ width: 200, height: '3em' }}>
26
+ <div style={{ fontSize: '0.8em' }}>(this will not timeout, and show only the loader)</div>
27
+ <LoaderFallback Target={current} DefaultComponent={Fallback} />
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export const LongChangingComponent = () => {
33
+ const [current, setCurrent] = useState<ComponentType | undefined>(() => Component);
34
+
35
+ useEffect(() => {
36
+ const intervalId = setInterval(() => {
37
+ setCurrent((x?: ComponentType) => (x ? undefined : Component));
38
+ }, 6000);
39
+
40
+ return () => clearInterval(intervalId);
41
+ }, []);
42
+
43
+ return (
44
+ <div style={{ width: 200, height: '3em' }}>
45
+ <div style={{ fontSize: '0.8em' }}>(this will timeout, showing the fallback component)</div>
46
+ <LoaderFallback Target={current} DefaultComponent={Fallback} timeout={2000} />
47
+ </div>
48
+ );
49
+ };
50
+
51
+ function Component() {
52
+ return <div style={{ color: '#2e945a' }}>✓ actual component</div>;
53
+ }
54
+
55
+ function Fallback() {
56
+ return <div>target is (undefined)</div>;
57
+ }
@@ -0,0 +1,45 @@
1
+ import { LoaderFallback } from './loader-fallback';
2
+
3
+ Safely render a component, with a default fallback when it is `undefined`.
4
+ The `LoaderFallback` component also provides a grace period, where it shows a loader before switching to the default.
5
+ Set `timeout = 0` to skip the grace period.
6
+
7
+ #### Example usage:
8
+
9
+ ```tsx
10
+ // as a hook:
11
+ const safeTarget = useFallback(Target && <Target />, <DefaultComponent />, { timeout: 10000, loader: <Loader /> });
12
+
13
+ // as a component:
14
+ <LoaderFallback Target={Target} DefaultComponent={DefaultComponent} timeout={10000} loader={Loader}>
15
+ ```
16
+
17
+ ### Logic is as follows:
18
+
19
+ 1. when component is `defined` -> render it
20
+ 1. when the initial value of the component is `undefined` -> show the default immediately
21
+ 1. when the component changes to be `undefined` -> show Loader for _x_ seconds
22
+ 1. then, after _x_ seconds - show the default.
23
+
24
+ <!-- live playground doesn't keep state when editing :( -->
25
+ <!-- Try it out:
26
+
27
+ ```tsx live
28
+ function Example() {
29
+ return (
30
+ <LoaderFallback
31
+ Target={RegularComponent} // comment this out
32
+ DefaultComponent={Fallback}
33
+ timeout={2000}
34
+ />
35
+ );
36
+
37
+ function RegularComponent() {
38
+ return <div>regular component</div>;
39
+ }
40
+
41
+ function Fallback() {
42
+ return <div>this shows when component is undefined</div>;
43
+ }
44
+ }
45
+ ``` -->
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { render, waitFor } from '@testing-library/react';
3
+ import { LoaderFallback } from './loader-fallback';
4
+
5
+ describe('loader-fallback', () => {
6
+ it('should render target, when defined', () => {
7
+ const { getByText } = render(
8
+ <LoaderFallback Target={Component} DefaultComponent={Default} Loader={Loader} timeout={10} />
9
+ );
10
+
11
+ // throws if not found, same as expect
12
+ getByText('test target');
13
+ });
14
+
15
+ it('should render default, when target is undefined', () => {
16
+ const { getByText } = render(
17
+ <LoaderFallback Target={undefined} DefaultComponent={Default} Loader={Loader} timeout={10} />
18
+ );
19
+
20
+ // throws if not found, same as expect
21
+ getByText('Target is undefined');
22
+ });
23
+
24
+ it('should render loader, when target becomes undefined', () => {
25
+ const { rerender, getByText } = render(
26
+ <LoaderFallback Target={Component} DefaultComponent={Default} Loader={Loader} timeout={10} />
27
+ );
28
+
29
+ rerender(<LoaderFallback Target={undefined} DefaultComponent={Default} Loader={Loader} timeout={10} />);
30
+
31
+ // throws if not found, same as expect
32
+ getByText('loading...');
33
+ });
34
+
35
+ it('should render DefaultComponent, after timeout, when target becomes undefined', async () => {
36
+ const { rerender, getByText } = render(
37
+ <LoaderFallback Target={Component} DefaultComponent={Default} Loader={Loader} timeout={10} />
38
+ );
39
+
40
+ rerender(<LoaderFallback Target={undefined} DefaultComponent={Default} Loader={Loader} timeout={10} />);
41
+
42
+ await waitFor(() => getByText('Target is undefined'));
43
+ });
44
+ });
45
+
46
+ function Component() {
47
+ return <div>test target</div>;
48
+ }
49
+
50
+ function Default() {
51
+ return <div>Target is undefined</div>;
52
+ }
53
+
54
+ function Loader() {
55
+ return <div>loading...</div>;
56
+ }
@@ -0,0 +1,48 @@
1
+ import type { ComponentType, ReactElement } from 'react';
2
+ import React, { useEffect, useState } from 'react';
3
+ import { LoaderRibbon } from '@teambit/base-ui.loaders.loader-ribbon';
4
+
5
+ export type LoaderProps = {
6
+ /** component to render */
7
+ Target: ComponentType | undefined;
8
+ /** component to render when Target is undefined */
9
+ DefaultComponent: ComponentType;
10
+ /** component to render when target is missing, for a grace period, until rendering the default */
11
+ Loader?: ComponentType;
12
+ /** cool-down period (in ms) to show Loader, before showing the default */
13
+ timeout?: number;
14
+ };
15
+
16
+ export function LoaderFallback({ Target, Loader = LoaderComponent, DefaultComponent, timeout = 15000 }: LoaderProps) {
17
+ return useFallback(Target && <Target />, <DefaultComponent />, { timeout, loader: <Loader /> });
18
+ }
19
+
20
+ export type useFallbackOptions = { timeout?: number; loader?: ReactElement };
21
+
22
+ export function useFallback(
23
+ target: ReactElement | null | undefined,
24
+ fallback: ReactElement,
25
+ { timeout = 15000, loader = <LoaderComponent /> }: useFallbackOptions = {}
26
+ ): ReactElement | null {
27
+ const [working, setWorking] = useState(!!target);
28
+ const hasTarget = !!target;
29
+
30
+ useEffect(() => {
31
+ if (timeout <= 0) return () => {};
32
+ if (hasTarget) {
33
+ setWorking(true);
34
+ return () => {};
35
+ }
36
+
37
+ const tmId = setTimeout(() => setWorking(false), timeout);
38
+ return () => clearTimeout(tmId);
39
+ }, [hasTarget, timeout]);
40
+
41
+ if (target) return target;
42
+ if (working && timeout > 0) return loader;
43
+ return fallback;
44
+ }
45
+
46
+ function LoaderComponent() {
47
+ return <LoaderRibbon active style={{ position: 'fixed', top: 0, left: 0, right: 0 }} />;
48
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@teambit/react.ui.loader-fallback",
3
+ "version": "0.0.0-5f312aa95ec8fc788d5968eb3a7bd69db85b7b87",
4
+ "homepage": "https://bit.cloud/teambit/react/ui/loader-fallback",
5
+ "main": "dist/index.js",
6
+ "componentId": {
7
+ "scope": "teambit.react",
8
+ "name": "ui/loader-fallback",
9
+ "version": "5f312aa95ec8fc788d5968eb3a7bd69db85b7b87"
10
+ },
11
+ "dependencies": {
12
+ "core-js": "^3.0.0",
13
+ "@teambit/base-ui.loaders.loader-ribbon": "1.0.0"
14
+ },
15
+ "devDependencies": {
16
+ "@types/react": "^17.0.8",
17
+ "@types/mocha": "9.1.0",
18
+ "@types/node": "12.20.4",
19
+ "@types/react-dom": "^17.0.5",
20
+ "@types/jest": "^26.0.0",
21
+ "@babel/runtime": "7.20.0",
22
+ "@types/testing-library__jest-dom": "5.9.5"
23
+ },
24
+ "peerDependencies": {
25
+ "@testing-library/react": "^12.1.5",
26
+ "react": "^16.8.0 || ^17.0.0",
27
+ "react-dom": "^16.8.0 || ^17.0.0"
28
+ },
29
+ "license": "Apache-2.0",
30
+ "optionalDependencies": {},
31
+ "peerDependenciesMeta": {},
32
+ "private": false,
33
+ "engines": {
34
+ "node": ">=12.22.0"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/teambit/bit"
39
+ },
40
+ "keywords": [
41
+ "bit",
42
+ "components",
43
+ "collaboration",
44
+ "web",
45
+ "react",
46
+ "react-components",
47
+ "angular",
48
+ "angular-components"
49
+ ]
50
+ }
@@ -0,0 +1,29 @@
1
+ declare module '*.png' {
2
+ const value: any;
3
+ export = value;
4
+ }
5
+ declare module '*.svg' {
6
+ import type { FunctionComponent, SVGProps } from 'react';
7
+
8
+ export const ReactComponent: FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;
9
+ const src: string;
10
+ export default src;
11
+ }
12
+
13
+ // @TODO Gilad
14
+ declare module '*.jpg' {
15
+ const value: any;
16
+ export = value;
17
+ }
18
+ declare module '*.jpeg' {
19
+ const value: any;
20
+ export = value;
21
+ }
22
+ declare module '*.gif' {
23
+ const value: any;
24
+ export = value;
25
+ }
26
+ declare module '*.bmp' {
27
+ const value: any;
28
+ export = value;
29
+ }
@@ -0,0 +1,42 @@
1
+ declare module '*.module.css' {
2
+ const classes: { readonly [key: string]: string };
3
+ export default classes;
4
+ }
5
+ declare module '*.module.scss' {
6
+ const classes: { readonly [key: string]: string };
7
+ export default classes;
8
+ }
9
+ declare module '*.module.sass' {
10
+ const classes: { readonly [key: string]: string };
11
+ export default classes;
12
+ }
13
+
14
+ declare module '*.module.less' {
15
+ const classes: { readonly [key: string]: string };
16
+ export default classes;
17
+ }
18
+
19
+ declare module '*.less' {
20
+ const classes: { readonly [key: string]: string };
21
+ export default classes;
22
+ }
23
+
24
+ declare module '*.css' {
25
+ const classes: { readonly [key: string]: string };
26
+ export default classes;
27
+ }
28
+
29
+ declare module '*.sass' {
30
+ const classes: { readonly [key: string]: string };
31
+ export default classes;
32
+ }
33
+
34
+ declare module '*.scss' {
35
+ const classes: { readonly [key: string]: string };
36
+ export default classes;
37
+ }
38
+
39
+ declare module '*.mdx' {
40
+ const component: any;
41
+ export default component;
42
+ }