@ispb/react-lazy 0.0.4 → 0.0.5
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/dist/async.d.ts +44 -0
- package/dist/async.js +71 -0
- package/dist/async.js.map +1 -0
- package/dist/components.d.ts +9 -0
- package/dist/components.js +36 -0
- package/dist/components.js.map +1 -0
- package/dist/hoc.d.ts +18 -0
- package/dist/hoc.js +13 -0
- package/dist/hoc.js.map +1 -0
- package/dist/hooks.d.ts +18 -0
- package/dist/hooks.js +146 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +4 -0
- package/dist/internal.js +20 -0
- package/dist/internal.js.map +1 -0
- package/dist/observable.d.ts +22 -0
- package/dist/observable.js +56 -0
- package/dist/observable.js.map +1 -0
- package/dist/state.d.ts +39 -0
- package/{src/state.ts → dist/state.js} +9 -48
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +4 -1
- package/.yarnrc.yml +0 -8
- package/src/async.tsx +0 -124
- package/src/components.tsx +0 -46
- package/src/hoc.tsx +0 -37
- package/src/hooks.ts +0 -155
- package/src/index.tsx +0 -9
- package/src/internal.ts +0 -21
- package/src/observable.tsx +0 -83
- package/src/types.tsx +0 -75
- package/tsconfig.json +0 -27
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAyC3C,MAAM,UAAU,YAAY,CAAI,OAAqB;IACjD,MAAM,OAAO,GAAG,WAAW,CAAiB,OAAO,CAAC,MAAM,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACtI,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO;gBACH,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,KAAK;gBAClB,SAAS,EAAE,KAAK;gBAChB,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,KAAK;aACpB,CAAA;QACL,CAAC;aACI,CAAC;YACF,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACjC,OAAO;oBACH,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,IAAI;oBACjB,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,IAAI;oBACjB,UAAU,EAAE,KAAK;oBACjB,KAAK,EAAE,OAAO,CAAC,KAAK;iBACvB,CAAA;YACL,CAAC;iBACI,CAAC;gBACF,OAAO;oBACH,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,IAAI;oBACjB,SAAS,EAAE,IAAI;oBACf,WAAW,EAAE,KAAK;oBAClB,UAAU,EAAE,IAAI;oBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,KAAK,EAAE,OAAO,CAAC,KAAK;iBACvB,CAAA;YACL,CAAC;QACL,CAAC;IACL,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO;YACH,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,KAAK;YAClB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,IAAI;YACjB,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,OAAO,CAAC,KAAK;SACvB,CAAA;IACL,CAAC;SACI,CAAC;QACF,OAAO;YACH,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,KAAK;YAClB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,KAAK;YAClB,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;SACvB,CAAA;IACL,CAAC;AACL,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export type LazyLoading = {
|
|
3
|
+
readonly status: "loading";
|
|
4
|
+
};
|
|
5
|
+
export type LazyFulfilled<D> = {
|
|
6
|
+
readonly status: "fulfilled";
|
|
7
|
+
readonly value: D;
|
|
8
|
+
};
|
|
9
|
+
export type LazyRejected = {
|
|
10
|
+
readonly status: "rejected";
|
|
11
|
+
readonly reason: unknown;
|
|
12
|
+
readonly retry?: (() => void) | undefined;
|
|
13
|
+
};
|
|
14
|
+
export type LazySettled<D> = LazyFulfilled<D> | LazyRejected;
|
|
15
|
+
export type LazyEvent<D> = LazySettled<D> | LazyLoading;
|
|
16
|
+
export type OnLoading = (props: LoadingProps) => ReactNode;
|
|
17
|
+
export type OnReloading = (props: ReloadingProps) => ReactNode;
|
|
18
|
+
export type OnError = (props: ErrorProps) => ReactNode;
|
|
19
|
+
type LazyMeta = string;
|
|
20
|
+
export interface LoadingProps {
|
|
21
|
+
/**
|
|
22
|
+
* The message to display.
|
|
23
|
+
*/
|
|
24
|
+
readonly message?: LazyMeta | undefined;
|
|
25
|
+
}
|
|
26
|
+
export interface ReloadingProps {
|
|
27
|
+
/**
|
|
28
|
+
* Whether or not the data is currently reloading.
|
|
29
|
+
*/
|
|
30
|
+
readonly reloading: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The message to display.
|
|
33
|
+
*/
|
|
34
|
+
readonly message?: LazyMeta | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The children.
|
|
37
|
+
*/
|
|
38
|
+
readonly children: ReactNode;
|
|
39
|
+
}
|
|
40
|
+
export interface ErrorProps {
|
|
41
|
+
/**
|
|
42
|
+
* The error.
|
|
43
|
+
*/
|
|
44
|
+
readonly reason: unknown;
|
|
45
|
+
/**
|
|
46
|
+
* The message to display.
|
|
47
|
+
*/
|
|
48
|
+
readonly message?: LazyMeta | undefined;
|
|
49
|
+
}
|
|
50
|
+
export interface LazyOptions {
|
|
51
|
+
readonly onLoading?: OnLoading | undefined;
|
|
52
|
+
readonly onReloading?: OnReloading | undefined;
|
|
53
|
+
readonly onError?: OnError | undefined;
|
|
54
|
+
readonly defaultMessage?: LazyMeta | undefined;
|
|
55
|
+
readonly loadingMessage?: LazyMeta | undefined;
|
|
56
|
+
readonly reloadingMessage?: LazyMeta | undefined;
|
|
57
|
+
readonly errorMessage?: LazyMeta | undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Overrides for lazy options.
|
|
61
|
+
*/
|
|
62
|
+
export type LazyOverrides = Partial<LazyOptions>;
|
|
63
|
+
export type ExtractLazy<T> = T extends LazyFulfilled<infer D> ? D : never;
|
|
64
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.tsx"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ispb/react-lazy",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"watch": "tsc --watch"
|
|
10
10
|
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
11
14
|
"exports": {
|
|
12
15
|
"default": "./dist/index.js",
|
|
13
16
|
"types": "./dist/index.d.ts"
|
package/.yarnrc.yml
DELETED
package/src/async.tsx
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { ReactNode, useCallback, useEffect, useState } from "react"
|
|
3
|
-
import { ValueOrFactory, callOrGet } from "value-or-factory"
|
|
4
|
-
import { Lazy } from "./components.js"
|
|
5
|
-
import { LazyHOCOptions, lazified } from "./hoc.js"
|
|
6
|
-
import { useIsFirstMount } from "./internal.js"
|
|
7
|
-
import { LazyState } from "./state.js"
|
|
8
|
-
import { LazyEvent, LazyOverrides } from "./types.js"
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Options for the async hook.
|
|
12
|
-
* @typeParam D The data type.
|
|
13
|
-
*/
|
|
14
|
-
export interface AsyncLazyOptions<D> {
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* A promise or a function that returns a promise. This MUST be memoized - the function will re-run every time a new value is received.
|
|
18
|
-
*/
|
|
19
|
-
readonly promise: ValueOrFactory<PromiseLike<D>>
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Don't execute immediately.
|
|
23
|
-
*/
|
|
24
|
-
readonly defer?: AsyncLazyDefer<D> | undefined
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface AsyncLazyDefer<D> {
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The initial value to provide.
|
|
32
|
-
*/
|
|
33
|
-
readonly initial: D
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export type AsyncLazyEvent<D> = LazyEvent<D> & { readonly retry: Retry }
|
|
38
|
-
|
|
39
|
-
export function useAsyncLazy<D>(input: AsyncLazyOptions<D> | (() => PromiseLike<D>)): AsyncLazyEvent<D> {
|
|
40
|
-
const options = typeof input === "function" ? { promise: input } : input
|
|
41
|
-
const [event, setEvent] = useState<LazyEvent<D>>(options.defer === undefined ? { status: "loading" } : { status: "fulfilled", value: options.defer.initial })
|
|
42
|
-
const run = useCallback(() => {
|
|
43
|
-
callOrGet(options.promise).then(value => {
|
|
44
|
-
setEvent({
|
|
45
|
-
status: "fulfilled",
|
|
46
|
-
value,
|
|
47
|
-
})
|
|
48
|
-
}, reason => {
|
|
49
|
-
setEvent({
|
|
50
|
-
status: "rejected",
|
|
51
|
-
reason,
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
}, [
|
|
55
|
-
options.promise
|
|
56
|
-
])
|
|
57
|
-
const retry = useCallback((suppressReload = false) => {
|
|
58
|
-
if (!suppressReload) {
|
|
59
|
-
setEvent({
|
|
60
|
-
status: "loading"
|
|
61
|
-
})
|
|
62
|
-
}
|
|
63
|
-
run()
|
|
64
|
-
}, [
|
|
65
|
-
run
|
|
66
|
-
])
|
|
67
|
-
const isFirstMount = useIsFirstMount()
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (isFirstMount) {
|
|
70
|
-
if (options.defer !== undefined) {
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
setEvent({
|
|
76
|
-
status: "loading"
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
run()
|
|
80
|
-
}, [
|
|
81
|
-
run,
|
|
82
|
-
])
|
|
83
|
-
return {
|
|
84
|
-
...event,
|
|
85
|
-
retry
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export type AsyncLazyState<D> = LazyState<D> & { readonly retry: Retry }
|
|
90
|
-
|
|
91
|
-
export interface AsyncifiedOptions<D, P> extends AsyncLazyOptions<D>, LazyHOCOptions<AsyncLazyState<D>, P> {
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function asyncified<I extends {}, D extends {}, P extends {}>(factory: (props: I) => AsyncifiedOptions<D, P>) {
|
|
95
|
-
return lazified((props: I) => {
|
|
96
|
-
const options = factory(props)
|
|
97
|
-
const event = useAsyncLazy(options)
|
|
98
|
-
return {
|
|
99
|
-
event,
|
|
100
|
-
passthrough: state => callOrGet(options.passthrough, { ...state, retry: event.retry }),
|
|
101
|
-
overrides: options.overrides,
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export type Retry = (suppressReload?: boolean | undefined) => void
|
|
107
|
-
|
|
108
|
-
export interface AsyncifiedProps<D> extends AsyncLazyOptions<D> {
|
|
109
|
-
|
|
110
|
-
readonly children: ValueOrFactory<ReactNode, [D, AsyncLazyState<D>]>
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* The lazy overrides.
|
|
114
|
-
*/
|
|
115
|
-
readonly overrides?: LazyOverrides | undefined
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export const Asyncified = <D,>(props: AsyncifiedProps<D>) => {
|
|
120
|
-
const event = useAsyncLazy(props)
|
|
121
|
-
return <Lazy event={event}
|
|
122
|
-
overrides={props.overrides}
|
|
123
|
-
children={(value, state) => callOrGet(props.children, value, { ...state, retry: event.retry })} />
|
|
124
|
-
}
|
package/src/components.tsx
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { PropsWithChildren, ReactNode, useContext } from "react"
|
|
3
|
-
import { LazyContext } from "./hooks.js"
|
|
4
|
-
import { LazyState, useLazyState } from "./state.js"
|
|
5
|
-
import { LazyEvent, LazyOverrides } from "./types.js"
|
|
6
|
-
|
|
7
|
-
export interface LazyProps<D> {
|
|
8
|
-
|
|
9
|
-
readonly event: LazyEvent<D>
|
|
10
|
-
readonly overrides?: LazyOverrides | undefined
|
|
11
|
-
readonly children: ReactNode | ((value: D, state: LazyState<D>) => ReactNode)
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function Lazy<D>(props: LazyProps<D>): ReactNode {
|
|
16
|
-
const context = useContext(LazyContext)
|
|
17
|
-
const options = { ...context, ...props.overrides }
|
|
18
|
-
const state = useLazyState(props.event)
|
|
19
|
-
if (state.isLoading && !state.isSettled) {
|
|
20
|
-
if (options.onLoading === undefined) {
|
|
21
|
-
return null
|
|
22
|
-
}
|
|
23
|
-
return options.onLoading({
|
|
24
|
-
message: options.loadingMessage ?? options.defaultMessage
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
const onReloading = options.onReloading ?? ((props: PropsWithChildren) => props.children)
|
|
28
|
-
return onReloading({
|
|
29
|
-
reloading: state.isLoading,
|
|
30
|
-
message: options.reloadingMessage ?? options.defaultMessage,
|
|
31
|
-
children: (() => {
|
|
32
|
-
if (state.isRejected) {
|
|
33
|
-
if (options.onError === undefined) {
|
|
34
|
-
throw state.reason
|
|
35
|
-
}
|
|
36
|
-
return options.onError({
|
|
37
|
-
reason: state.reason,
|
|
38
|
-
message: options.errorMessage ?? options.defaultMessage,
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
return typeof props.children === "function" ? props.children(state.value, state) : props.children
|
|
43
|
-
}
|
|
44
|
-
})()
|
|
45
|
-
})
|
|
46
|
-
}
|
package/src/hoc.tsx
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { ComponentType, createElement } from "react"
|
|
3
|
-
import { callOrGet, ValueOrFactory } from "value-or-factory"
|
|
4
|
-
import { Lazy } from "./components.js"
|
|
5
|
-
import { LazyState } from "./state.js"
|
|
6
|
-
import { LazyEvent, LazyOverrides } from "./types.js"
|
|
7
|
-
|
|
8
|
-
export interface LazyBuilder<D, P> extends LazyHOCOptions<LazyState<D>, P> {
|
|
9
|
-
|
|
10
|
-
readonly event: LazyEvent<D>
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function lazified<I extends {}, D extends {}, P extends {}>(build: (props: I) => LazyBuilder<D, P>) {
|
|
15
|
-
return (component: ComponentType<D & P>) => {
|
|
16
|
-
return (props: I) => {
|
|
17
|
-
const built = build(props)
|
|
18
|
-
return <Lazy event={built.event}
|
|
19
|
-
overrides={built.overrides}
|
|
20
|
-
children={(value, state) => createElement(component, { ...callOrGet(built.passthrough, state), ...value })} />
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface LazyHOCOptions<S, P> {
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Properties to pass through to the component.
|
|
29
|
-
*/
|
|
30
|
-
readonly passthrough: ValueOrFactory<P, [S]>
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Overrides for lazy settings.
|
|
34
|
-
*/
|
|
35
|
-
readonly overrides?: LazyOverrides | undefined
|
|
36
|
-
|
|
37
|
-
}
|
package/src/hooks.ts
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import pDefer from "p-defer"
|
|
2
|
-
import { createContext, useEffect, useMemo, useState } from "react"
|
|
3
|
-
import { Observable, Subject } from "rxjs"
|
|
4
|
-
import { useIsFirstMount } from "./internal.js"
|
|
5
|
-
import { ExtractLazy, LazyEvent, LazyFulfilled, LazyLoading, LazyOverrides, LazyRejected } from "./types.js"
|
|
6
|
-
|
|
7
|
-
export const LazyContext = createContext<LazyOverrides>({})
|
|
8
|
-
|
|
9
|
-
export function isLoading<T>(event: LazyEvent<T>): event is LazyLoading {
|
|
10
|
-
if (event.status === "loading") {
|
|
11
|
-
return true
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
return false
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
export function isFulfilled<T>(event: LazyEvent<T>): event is LazyFulfilled<T> {
|
|
18
|
-
if (event.status === "fulfilled") {
|
|
19
|
-
return true
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
return false
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
export function isRejected<T>(event: LazyEvent<T>): event is LazyRejected {
|
|
26
|
-
if (event.status === "rejected") {
|
|
27
|
-
return true
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
return false
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function useLazyFlatten<O>(event: LazyEvent<LazyEvent<O>>,) {
|
|
35
|
-
return useLazyChain(event, event => event)
|
|
36
|
-
}
|
|
37
|
-
export function useLazyChain<I, O>(event: LazyEvent<I>, map: (value: I) => LazyEvent<O>) {
|
|
38
|
-
return useMemo(() => {
|
|
39
|
-
if (event.status === "fulfilled") {
|
|
40
|
-
return map(event.value)
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
return event
|
|
44
|
-
}
|
|
45
|
-
}, [
|
|
46
|
-
event
|
|
47
|
-
])
|
|
48
|
-
}
|
|
49
|
-
export function useLazyMap<I, O>(event: LazyEvent<I>, map: (value: I) => O) {
|
|
50
|
-
return useMemo(() => {
|
|
51
|
-
if (event.status === "fulfilled") {
|
|
52
|
-
return {
|
|
53
|
-
status: "fulfilled" as const,
|
|
54
|
-
value: map(event.value)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
return event
|
|
59
|
-
}
|
|
60
|
-
}, [
|
|
61
|
-
event
|
|
62
|
-
])
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function useObservableAsPromise<T>(observable: Observable<T>) {
|
|
66
|
-
const [promise, setPromise] = useState(() => pDefer<T>())
|
|
67
|
-
const isFirstMount = useIsFirstMount()
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (!isFirstMount) {
|
|
70
|
-
setPromise(pDefer<T>())
|
|
71
|
-
}
|
|
72
|
-
}, [
|
|
73
|
-
observable
|
|
74
|
-
])
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
const sub = observable.subscribe({
|
|
77
|
-
next: value => {
|
|
78
|
-
promise.resolve(value)
|
|
79
|
-
},
|
|
80
|
-
error: reason => {
|
|
81
|
-
promise.reject(reason)
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
return () => {
|
|
85
|
-
sub.unsubscribe()
|
|
86
|
-
}
|
|
87
|
-
}, [
|
|
88
|
-
promise
|
|
89
|
-
])
|
|
90
|
-
return promise.promise
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function useLazyAsPromise<T>(event: LazyEvent<T>) {
|
|
94
|
-
const [promise, setPromise] = useState(() => pDefer<T>())
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
if (event.status === "fulfilled") {
|
|
97
|
-
promise.resolve(event.value)
|
|
98
|
-
}
|
|
99
|
-
else if (event.status === "rejected") {
|
|
100
|
-
promise.reject(event.reason)
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
setPromise(pDefer<T>())
|
|
104
|
-
}
|
|
105
|
-
}, [
|
|
106
|
-
event
|
|
107
|
-
])
|
|
108
|
-
return promise.promise
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function useLazyAsObservable<T>(event: LazyEvent<T>) {
|
|
112
|
-
const subject = useMemo(() => new Subject<T>(), [])
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
if (event.status === "fulfilled") {
|
|
115
|
-
subject.next(event.value)
|
|
116
|
-
}
|
|
117
|
-
else if (event.status === "rejected") {
|
|
118
|
-
subject.error(event.reason)
|
|
119
|
-
}
|
|
120
|
-
}, [
|
|
121
|
-
event
|
|
122
|
-
])
|
|
123
|
-
return subject
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function useLazyCombine<T extends Record<string, LazyEvent<unknown>>>(lazies: T): LazyEvent<{ [K in keyof T]: ExtractLazy<T[K]> }> {
|
|
127
|
-
const entries = Object.entries(lazies)
|
|
128
|
-
if (entries.map(entry => entry[1]).some(isLoading)) {
|
|
129
|
-
return {
|
|
130
|
-
status: "loading" as const,
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
const failed = entries.map(entry => entry[1]).filter(isRejected).at(0)
|
|
135
|
-
if (failed !== undefined) {
|
|
136
|
-
return {
|
|
137
|
-
status: "rejected" as const,
|
|
138
|
-
reason: failed
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
return {
|
|
143
|
-
status: "fulfilled",
|
|
144
|
-
value: Object.fromEntries(
|
|
145
|
-
entries.map(([key, value]) => {
|
|
146
|
-
return [
|
|
147
|
-
key,
|
|
148
|
-
value.status === "fulfilled" ? value.value : undefined,
|
|
149
|
-
] as const
|
|
150
|
-
})
|
|
151
|
-
) as { [K in keyof T]: ExtractLazy<T[K]> }
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
package/src/index.tsx
DELETED
package/src/internal.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useRef } from "react"
|
|
2
|
-
|
|
3
|
-
export function useIsFirstMount() {
|
|
4
|
-
const isFirst = useRef(true)
|
|
5
|
-
if (isFirst.current) {
|
|
6
|
-
isFirst.current = false
|
|
7
|
-
return true
|
|
8
|
-
}
|
|
9
|
-
return isFirst.current
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function usePrevious<T>(value: { readonly current: T } | undefined) {
|
|
13
|
-
const previous = useRef(value?.current)
|
|
14
|
-
const first = useIsFirstMount()
|
|
15
|
-
if (!first) {
|
|
16
|
-
if (value !== undefined) {
|
|
17
|
-
previous.current = value.current
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return previous.current
|
|
21
|
-
}
|
package/src/observable.tsx
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { ReactNode, useEffect, useState } from "react"
|
|
3
|
-
import { Observable, ObservedValueOf } from "rxjs"
|
|
4
|
-
import { Lazy } from "./components.js"
|
|
5
|
-
import { LazyHOCOptions, lazified } from "./hoc.js"
|
|
6
|
-
import { useLazyFlatten } from "./hooks.js"
|
|
7
|
-
import { useIsFirstMount } from "./internal.js"
|
|
8
|
-
import { LazyState } from "./state.js"
|
|
9
|
-
import { LazyEvent, LazyOverrides } from "./types.js"
|
|
10
|
-
|
|
11
|
-
export type ObservableLazyInput = Observable<any>// | Record<string, ObservableInput<any>>
|
|
12
|
-
export type ObservableLazyOutput<X extends ObservableLazyInput> = X extends Observable<any> ? ObservedValueOf<X> : { [K in keyof X]: ObservedValueOf<X[K]> }
|
|
13
|
-
|
|
14
|
-
export interface ObservableLazyOptions<D> {
|
|
15
|
-
|
|
16
|
-
readonly of: Observable<D>
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function useObservableLazyWrapped<D>(options: ObservableLazyOptions<LazyEvent<D>>) {
|
|
21
|
-
return useLazyFlatten(useObservableLazy(options))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function useObservableLazy<D>(options: ObservableLazyOptions<D>) {
|
|
25
|
-
const [event, setEvent] = useState<LazyEvent<D>>({ status: "loading" as const })
|
|
26
|
-
const isFirstMount = useIsFirstMount()
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
if (!isFirstMount) {
|
|
29
|
-
setEvent({
|
|
30
|
-
status: "loading"
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
const sub = options.of.subscribe({
|
|
34
|
-
next: value => {
|
|
35
|
-
setEvent({
|
|
36
|
-
status: "fulfilled",
|
|
37
|
-
value
|
|
38
|
-
})
|
|
39
|
-
},
|
|
40
|
-
error: reason => {
|
|
41
|
-
setEvent({
|
|
42
|
-
status: "rejected",
|
|
43
|
-
reason
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
return () => {
|
|
48
|
-
sub.unsubscribe()
|
|
49
|
-
}
|
|
50
|
-
}, [
|
|
51
|
-
options.of
|
|
52
|
-
])
|
|
53
|
-
return event
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface ObservingOptions<D, P> extends ObservableLazyOptions<D>, LazyHOCOptions<LazyState<D>, P> {
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function observing<I extends {}, D extends {}, P extends {}>(factory: (props: I) => ObservingOptions<D, P>) {
|
|
60
|
-
return lazified((props: I) => {
|
|
61
|
-
const options = factory(props)
|
|
62
|
-
const event = useObservableLazy(options)
|
|
63
|
-
return {
|
|
64
|
-
event,
|
|
65
|
-
passthrough: options.passthrough,
|
|
66
|
-
overrides: options.overrides,
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface ObservingProps<D> extends ObservableLazyOptions<D> {
|
|
72
|
-
|
|
73
|
-
readonly children: (value: D, state: LazyState<D>) => ReactNode
|
|
74
|
-
readonly overrides?: LazyOverrides | undefined
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export const Observing = <D,>(props: ObservingProps<D>) => {
|
|
79
|
-
const event = useObservableLazy(props)
|
|
80
|
-
return <Lazy event={event}
|
|
81
|
-
overrides={props.overrides}
|
|
82
|
-
children={props.children} />
|
|
83
|
-
}
|
package/src/types.tsx
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react"
|
|
2
|
-
|
|
3
|
-
export type LazyLoading = { readonly status: "loading" }
|
|
4
|
-
export type LazyFulfilled<D> = { readonly status: "fulfilled", readonly value: D }
|
|
5
|
-
export type LazyRejected = { readonly status: "rejected", readonly reason: unknown, readonly retry?: (() => void) | undefined }
|
|
6
|
-
export type LazySettled<D> = LazyFulfilled<D> | LazyRejected
|
|
7
|
-
export type LazyEvent<D> = LazySettled<D> | LazyLoading
|
|
8
|
-
|
|
9
|
-
export type OnLoading = (props: LoadingProps) => ReactNode
|
|
10
|
-
export type OnReloading = (props: ReloadingProps) => ReactNode
|
|
11
|
-
export type OnError = (props: ErrorProps) => ReactNode
|
|
12
|
-
|
|
13
|
-
type LazyMeta = string
|
|
14
|
-
|
|
15
|
-
export interface LoadingProps {
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The message to display.
|
|
19
|
-
*/
|
|
20
|
-
readonly message?: LazyMeta | undefined
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ReloadingProps {
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Whether or not the data is currently reloading.
|
|
28
|
-
*/
|
|
29
|
-
readonly reloading: boolean
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The message to display.
|
|
33
|
-
*/
|
|
34
|
-
readonly message?: LazyMeta | undefined
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The children.
|
|
38
|
-
*/
|
|
39
|
-
readonly children: ReactNode
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface ErrorProps {
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The error.
|
|
47
|
-
*/
|
|
48
|
-
readonly reason: unknown
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The message to display.
|
|
52
|
-
*/
|
|
53
|
-
readonly message?: LazyMeta | undefined
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface LazyOptions {
|
|
58
|
-
|
|
59
|
-
readonly onLoading?: OnLoading | undefined
|
|
60
|
-
readonly onReloading?: OnReloading | undefined
|
|
61
|
-
readonly onError?: OnError | undefined
|
|
62
|
-
|
|
63
|
-
readonly defaultMessage?: LazyMeta | undefined
|
|
64
|
-
readonly loadingMessage?: LazyMeta | undefined
|
|
65
|
-
readonly reloadingMessage?: LazyMeta | undefined
|
|
66
|
-
readonly errorMessage?: LazyMeta | undefined
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Overrides for lazy options.
|
|
72
|
-
*/
|
|
73
|
-
export type LazyOverrides = Partial<LazyOptions>
|
|
74
|
-
|
|
75
|
-
export type ExtractLazy<T> = T extends LazyFulfilled<infer D> ? D : never
|
package/tsconfig.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"jsx": "react-jsx",
|
|
4
|
-
"strict": true,
|
|
5
|
-
"alwaysStrict": true,
|
|
6
|
-
"allowUnreachableCode": false,
|
|
7
|
-
"allowUnusedLabels": false,
|
|
8
|
-
"noImplicitAny": true,
|
|
9
|
-
"noImplicitThis": true,
|
|
10
|
-
"noImplicitOverride": true,
|
|
11
|
-
"noUnusedLocals": true,
|
|
12
|
-
"noUnusedParameters": true,
|
|
13
|
-
"noPropertyAccessFromIndexSignature": true,
|
|
14
|
-
"noUncheckedIndexedAccess": true,
|
|
15
|
-
"noFallthroughCasesInSwitch": true,
|
|
16
|
-
"useUnknownInCatchVariables": true,
|
|
17
|
-
"exactOptionalPropertyTypes": true,
|
|
18
|
-
"moduleResolution": "nodenext",
|
|
19
|
-
"module": "nodenext",
|
|
20
|
-
"target": "esnext",
|
|
21
|
-
"declaration": true,
|
|
22
|
-
"sourceMap": true,
|
|
23
|
-
"skipLibCheck": true,
|
|
24
|
-
"rootDir": "src",
|
|
25
|
-
"outDir": "dist"
|
|
26
|
-
}
|
|
27
|
-
}
|