react-chain-of-responsibility 0.4.3-main.202512240619.c88c248 → 0.4.3-main.202601010031.78b7d38
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/README.md +0 -79
- package/dist/react-chain-of-responsibility.d.mts +66 -3
- package/dist/react-chain-of-responsibility.d.ts +66 -3
- package/dist/react-chain-of-responsibility.js +17 -12
- package/dist/react-chain-of-responsibility.js.map +1 -1
- package/dist/react-chain-of-responsibility.mjs +143 -3
- package/dist/react-chain-of-responsibility.mjs.map +1 -1
- package/dist/react-chain-of-responsibility.preview.js +14 -13
- package/dist/react-chain-of-responsibility.preview.js.map +1 -1
- package/dist/react-chain-of-responsibility.preview.mjs +2 -8
- package/dist/react-chain-of-responsibility.preview.mjs.map +1 -1
- package/package.json +21 -36
- package/dist/chunk-U4UF7NZV.mjs +0 -150
- package/dist/chunk-U4UF7NZV.mjs.map +0 -1
- package/dist/index-Dm_KqEiI.d.mts +0 -66
- package/dist/index-Dm_KqEiI.d.ts +0 -66
- package/dist/react-chain-of-responsibility.fluentUI.d.mts +0 -17
- package/dist/react-chain-of-responsibility.fluentUI.d.ts +0 -17
- package/dist/react-chain-of-responsibility.fluentUI.js +0 -203
- package/dist/react-chain-of-responsibility.fluentUI.js.map +0 -1
- package/dist/react-chain-of-responsibility.fluentUI.mjs +0 -26
- package/dist/react-chain-of-responsibility.fluentUI.mjs.map +0 -1
|
@@ -59,6 +59,7 @@ function arePropsEqual(x, y) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// src/preview/createChainOfResponsibilityAsRenderCallback.tsx
|
|
62
|
+
var { createContext, Fragment, memo, useCallback, useContext, useMemo } = import_react.default;
|
|
62
63
|
var DO_NOT_CREATE_THIS_OBJECT_YOURSELF = Symbol();
|
|
63
64
|
var componentHandlerResultSchema = (0, import_valibot.custom)(
|
|
64
65
|
(value) => (0, import_valibot.safeParse)((0, import_valibot.object)({ render: (0, import_valibot.function_)() }), value).success && !!value && typeof value === "object" && DO_NOT_CREATE_THIS_OBJECT_YOURSELF in value,
|
|
@@ -69,10 +70,10 @@ function createComponentHandlerResult(render) {
|
|
|
69
70
|
}
|
|
70
71
|
function createChainOfResponsibility(options = {}) {
|
|
71
72
|
options = Object.freeze({ ...options });
|
|
72
|
-
const BuildContext =
|
|
73
|
+
const BuildContext = createContext(
|
|
73
74
|
Object.freeze({ enhancer: (next) => (request) => next(request) })
|
|
74
75
|
);
|
|
75
|
-
const RenderContext =
|
|
76
|
+
const RenderContext = createContext(
|
|
76
77
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
78
|
new Proxy({}, {
|
|
78
79
|
get() {
|
|
@@ -99,7 +100,7 @@ function createChainOfResponsibility(options = {}) {
|
|
|
99
100
|
return createComponentHandlerResult((overridingProps) => /* @__PURE__ */ import_react.default.createElement(TypedWrapperComponent, { bindProps, component, overridingProps }));
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
|
-
const WrapperComponent =
|
|
103
|
+
const WrapperComponent = memo(function WrapperComponent2({
|
|
103
104
|
bindProps,
|
|
104
105
|
component: Component,
|
|
105
106
|
overridingProps,
|
|
@@ -107,7 +108,7 @@ function createChainOfResponsibility(options = {}) {
|
|
|
107
108
|
wrapperProps
|
|
108
109
|
}) {
|
|
109
110
|
const { allowOverrideProps } = options;
|
|
110
|
-
const { originalProps: renderCallbackProps } =
|
|
111
|
+
const { originalProps: renderCallbackProps } = useContext(RenderContext);
|
|
111
112
|
if (overridingProps && !arePropsEqual(overridingProps, renderCallbackProps) && !allowOverrideProps) {
|
|
112
113
|
console.warn('react-chain-of-responsibility: "allowOverrideProps" must be set to true to override props');
|
|
113
114
|
}
|
|
@@ -126,8 +127,8 @@ function createChainOfResponsibility(options = {}) {
|
|
|
126
127
|
return WrapperComponent2 && wrapperProps ? /* @__PURE__ */ import_react.default.createElement(WrapperComponent2, { ...typeof wrapperProps === "function" ? wrapperProps(props) : wrapperProps }, child) : child;
|
|
127
128
|
});
|
|
128
129
|
const useBuildRenderCallback = () => {
|
|
129
|
-
const { enhancer } =
|
|
130
|
-
return
|
|
130
|
+
const { enhancer } = useContext(BuildContext);
|
|
131
|
+
return useCallback(
|
|
131
132
|
(request, buildOptions = {}) => {
|
|
132
133
|
const result = (
|
|
133
134
|
// Put the "fallbackComponent" as the last one in the chain.
|
|
@@ -152,14 +153,14 @@ function createChainOfResponsibility(options = {}) {
|
|
|
152
153
|
);
|
|
153
154
|
};
|
|
154
155
|
function BuildRenderCallback({ originalProps, render }) {
|
|
155
|
-
const context =
|
|
156
|
+
const context = useMemo(() => Object.freeze({ originalProps }), [originalProps]);
|
|
156
157
|
return /* @__PURE__ */ import_react.default.createElement(RenderContext.Provider, { value: context }, render());
|
|
157
158
|
}
|
|
158
159
|
function ChainOfResponsibilityProvider({ children, init, middleware }) {
|
|
159
160
|
if (!Array.isArray(middleware) || middleware.some((middleware2) => typeof middleware2 !== "function")) {
|
|
160
161
|
throw new Error('react-chain-of-responsibility: "middleware" prop must be an array of functions');
|
|
161
162
|
}
|
|
162
|
-
const fortifiedMiddleware =
|
|
163
|
+
const fortifiedMiddleware = useMemo(
|
|
163
164
|
() => Object.freeze(
|
|
164
165
|
middleware.map((fn) => (init2) => {
|
|
165
166
|
const enhancer2 = fn(init2);
|
|
@@ -183,8 +184,8 @@ function createChainOfResponsibility(options = {}) {
|
|
|
183
184
|
),
|
|
184
185
|
[middleware]
|
|
185
186
|
);
|
|
186
|
-
const { enhancer: parentEnhancer } =
|
|
187
|
-
const enhancer =
|
|
187
|
+
const { enhancer: parentEnhancer } = useContext(BuildContext);
|
|
188
|
+
const enhancer = useMemo(
|
|
188
189
|
() => (
|
|
189
190
|
// We are reversing because it is easier to read:
|
|
190
191
|
// - With reverse, [a, b, c] will become a(b(c(fn)))
|
|
@@ -195,15 +196,15 @@ function createChainOfResponsibility(options = {}) {
|
|
|
195
196
|
),
|
|
196
197
|
[init, fortifiedMiddleware, parentEnhancer]
|
|
197
198
|
);
|
|
198
|
-
const contextValue =
|
|
199
|
+
const contextValue = useMemo(() => Object.freeze({ enhancer }), [enhancer]);
|
|
199
200
|
return /* @__PURE__ */ import_react.default.createElement(BuildContext.Provider, { value: contextValue }, children);
|
|
200
201
|
}
|
|
201
202
|
function ChainOfResponsibilityProxy({ fallbackComponent, request, ...props }) {
|
|
202
203
|
var _a;
|
|
203
204
|
const result = (_a = useBuildRenderCallback()(request, { fallbackComponent })) == null ? void 0 : _a(props);
|
|
204
|
-
return result ? /* @__PURE__ */ import_react.default.createElement(
|
|
205
|
+
return result ? /* @__PURE__ */ import_react.default.createElement(Fragment, null, result) : null;
|
|
205
206
|
}
|
|
206
|
-
const MemoizedChainOfResponsibilityProvider =
|
|
207
|
+
const MemoizedChainOfResponsibilityProvider = memo(ChainOfResponsibilityProvider);
|
|
207
208
|
return Object.freeze({
|
|
208
209
|
Provider: MemoizedChainOfResponsibilityProvider,
|
|
209
210
|
Proxy: ChainOfResponsibilityProxy,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.preview.ts","../src/preview/createChainOfResponsibilityAsRenderCallback.tsx","../src/preview/private/arePropsEqual.ts"],"sourcesContent":["export {\n default as createChainOfResponsibility,\n type ChainOfResponsibility,\n type ComponentEnhancer,\n type ComponentHandler,\n type ComponentHandlerResult,\n type ComponentMiddleware,\n type ComponentRenderer,\n type CreateChainOfResponsibilityOptions,\n type InferenceHelper,\n type InferInit,\n type InferMiddleware,\n type InferProps,\n type InferProviderProps,\n type InferProxyProps,\n type InferRequest,\n type ProviderProps,\n type ProxyProps,\n type ReactComponentHandlerResult,\n type UseBuildRenderCallback,\n type UseBuildRenderCallbackOptions\n} from './preview/createChainOfResponsibilityAsRenderCallback.tsx';\n","import { applyMiddleware } from 'handler-chain';\nimport React, {\n createContext,\n Fragment,\n memo,\n useCallback,\n useContext,\n useMemo,\n type ComponentType,\n type PropsWithChildren,\n type ReactElement,\n type ReactNode\n} from 'react';\nimport { type SetOptional } from 'type-fest';\nimport { custom, function_, object, parse, safeParse } from 'valibot';\n\nimport arePropsEqual from './private/arePropsEqual.ts';\n\n// TODO: Related to https://github.com/microsoft/TypeScript/issues/17002.\n// typescript@5.2.2 has a bug, Array.isArray() is a type predicate but only works with mutable array, not readonly array.\ndeclare global {\n interface ArrayConstructor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n isArray(arg: any): arg is readonly any[];\n }\n}\n\ntype BaseProps = object;\n\ntype CreateChainOfResponsibilityOptions = {\n /**\n * Allows one component to pass different set of props to its downstream component. Default is false.\n *\n * It is recommended to keep this settings as default to prevent newly added component from unexpectedly changing behavior of downstream components.\n */\n readonly allowOverrideProps?: boolean | undefined;\n\n /**\n * Allows a middleware to pass another request object when calling its next middleware. Default is false.\n *\n * It is recommended to keep this settings as default ot prevent newly added middleware from unexpectedly changing behavior of downstream middleware.\n *\n * To prevent upstream middleware from modifying the request, the request object should be set to be immutable through `Object.freeze`.\n */\n readonly passModifiedRequest?: boolean | undefined;\n};\n\ntype ChainOfResponsibility<Request, Props extends BaseProps, Init> = {\n readonly Provider: ComponentType<ProviderProps<Request, Props, Init>> & InferenceHelper<Request, Props, Init>;\n readonly Proxy: ComponentType<ProxyProps<Request, Props>>;\n readonly reactComponent: ReactComponentHandlerResult<Props>;\n readonly useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props>;\n};\n\n// TODO: Maybe this one should be local.\n// Verify that reactComponent() from an instance of CoR should throw error when used in another instance of CoR.\nconst DO_NOT_CREATE_THIS_OBJECT_YOURSELF = Symbol();\n\ntype ComponentRenderer<Props> = (props: Props) => ReactElement | null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst componentHandlerResultSchema = custom<ComponentHandlerResult<any>>(\n value =>\n safeParse(object({ render: function_() }), value).success &&\n !!value &&\n typeof value === 'object' &&\n DO_NOT_CREATE_THIS_OBJECT_YOURSELF in value,\n 'react-chain-of-responsibility: middleware must return value constructed by reactComponent()'\n);\n\ninterface ComponentHandlerResult<Props extends BaseProps> {\n readonly [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined;\n readonly render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null;\n}\n\ntype ComponentHandler<Request, Props extends BaseProps> = (\n request: Request\n) => ComponentHandlerResult<Props> | undefined;\n\ntype ComponentEnhancer<Request, Props extends BaseProps> = (\n next: ComponentHandler<Request, Props>\n) => ComponentHandler<Request, Props>;\n\ntype ComponentMiddleware<Request, Props extends BaseProps, Init = undefined> = (\n init: Init\n) => ComponentEnhancer<Request, Props>;\n\ntype ReactComponentInit<\n Props extends BaseProps,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n> = W extends void\n ? {\n wrapperComponent?: undefined;\n wrapperProps?: undefined;\n }\n : {\n wrapperComponent: ComponentType<W>;\n wrapperProps: W | ((props: Props) => W);\n };\n\ntype ReactComponentHandlerResult<Props extends BaseProps> = <\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n>(\n component: ComponentType<P>,\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W>\n) => ComponentHandlerResult<Props>;\n\ntype UseBuildRenderCallbackOptions<Props> = {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n};\n\ninterface UseBuildRenderCallback<Request, Props extends BaseProps> {\n (request: Request, options?: undefined | UseBuildRenderCallbackOptions<Props>): ComponentRenderer<Props> | undefined;\n}\n\ntype BuildContextType<Request, Props extends BaseProps> = {\n readonly enhancer: ComponentEnhancer<Request, Props>;\n};\n\ntype RenderContextType<Props> = {\n readonly originalProps: Props;\n};\n\ntype ProviderProps<Request, Props extends BaseProps, Init> = PropsWithChildren<{\n readonly middleware: readonly ComponentMiddleware<Request, Props, Init>[];\n}> &\n (Init extends never | void\n ? { readonly init?: undefined }\n : Init extends undefined | void\n ? { readonly init?: Init }\n : { readonly init: Init });\n\ntype ProxyProps<Request, Props extends BaseProps> = Props & {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n readonly request: Request;\n};\n\ntype InferenceHelper<Request, Props extends BaseProps, Init> = {\n readonly '~types': {\n readonly init: Init;\n readonly middleware: ComponentMiddleware<Request, Props, Init>;\n readonly props: Props;\n readonly proxyProps: ProxyProps<Request, Props>;\n readonly providerProps: ProviderProps<Request, Props, Init>;\n readonly request: Request;\n };\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferInit<T extends InferenceHelper<any, any, any>> = T['~types']['init'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferMiddleware<T extends InferenceHelper<any, any, any>> = T['~types']['middleware'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProps<T extends InferenceHelper<any, any, any>> = T['~types']['props'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProxyProps<T extends InferenceHelper<any, any, any>> = T['~types']['proxyProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProviderProps<T extends InferenceHelper<any, any, any>> = T['~types']['providerProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferRequest<T extends InferenceHelper<any, any, any>> = T['~types']['request'];\n\nfunction createComponentHandlerResult<Props extends BaseProps>(\n render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null\n): ComponentHandlerResult<Props> {\n return Object.freeze({ [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined, render });\n}\n\nfunction createChainOfResponsibility<\n Request = void,\n Props extends BaseProps = { readonly children?: never },\n Init = void\n>(options: CreateChainOfResponsibilityOptions = {}): ChainOfResponsibility<Request, Props, Init> {\n // Freeze options to prevent accidental change.\n options = Object.freeze({ ...options });\n\n const BuildContext = createContext<BuildContextType<Request, Props>>(\n Object.freeze({ enhancer: next => request => next(request) })\n );\n\n const RenderContext = createContext<RenderContextType<Props>>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new Proxy({} as any, {\n get() {\n // The following is assertion, there is no way to hit this line.\n /* istanbul ignore next */\n throw new Error(\n 'react-chain-of-responsibility: this hook cannot be used outside of <Proxy> and useBuildRenderCallback()'\n );\n }\n })\n );\n\n function reactComponent<P extends Props, W extends (BaseProps & { children?: ReactNode | undefined }) | void = void>(\n component: ComponentType<P>,\n // For `bindProps` of type function, do not do side-effect in it, it may not be always called in all scenarios.\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W> | undefined\n ): ComponentHandlerResult<Props> {\n // memo() and generic type do not play well together.\n const TypedWrapperComponent = WrapperComponent as ComponentType<WrapperComponentProps<P, W>>;\n\n if (init?.wrapperComponent && init.wrapperProps) {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent\n bindProps={bindProps}\n component={component}\n overridingProps={overridingProps}\n wrapperComponent={init.wrapperComponent as ComponentType<W>}\n wrapperProps={init.wrapperProps as W}\n />\n ));\n } else {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent bindProps={bindProps} component={component} overridingProps={overridingProps} />\n ));\n }\n }\n\n type WrapperComponentProps<\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n > = {\n readonly bindProps: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined;\n readonly component: ComponentType<P>;\n readonly overridingProps: Partial<Props> | undefined;\n readonly wrapperComponent?: ComponentType<W> | undefined;\n readonly wrapperProps?: W | ((props: Props) => W) | undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const WrapperComponent = memo<WrapperComponentProps<any, any>>(function WrapperComponent<\n P extends Props,\n W extends BaseProps & { children?: ReactNode | undefined }\n >({\n bindProps,\n component: Component,\n overridingProps,\n wrapperComponent: WrapperComponent,\n wrapperProps\n }: WrapperComponentProps<P, W>) {\n const { allowOverrideProps } = options;\n const { originalProps: renderCallbackProps } = useContext(RenderContext);\n\n if (overridingProps && !arePropsEqual(overridingProps, renderCallbackProps) && !allowOverrideProps) {\n console.warn('react-chain-of-responsibility: \"allowOverrideProps\" must be set to true to override props');\n }\n\n const props = Object.freeze(\n allowOverrideProps ? { ...renderCallbackProps, ...overridingProps } : { ...renderCallbackProps }\n );\n\n const child = (\n <Component\n {...({\n ...props,\n ...(typeof bindProps === 'function' ? bindProps(props) : bindProps)\n } as P)}\n />\n );\n\n return WrapperComponent && wrapperProps ? (\n <WrapperComponent {...(typeof wrapperProps === 'function' ? wrapperProps(props) : wrapperProps)}>\n {child}\n </WrapperComponent>\n ) : (\n child\n );\n });\n\n const useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props> = () => {\n const { enhancer } = useContext(BuildContext);\n\n return useCallback(\n (request, buildOptions = {}) => {\n const result =\n // Put the \"fallbackComponent\" as the last one in the chain.\n enhancer(() => {\n const { fallbackComponent } = buildOptions;\n\n if (!fallbackComponent) {\n console.warn(\n 'react-chain-of-responsibility: the request has fall through all middleware, set \"fallbackComponent\" as a catchall',\n request\n );\n\n // For clarity, we are returning `undefined` instead of `() => undefined`.\n return;\n }\n\n // `fallbackComponent` do not need `overridingProps` because it is the last one in the chain, it would not have the next() function.\n return reactComponent(fallbackComponent);\n })(request);\n\n return (\n result &&\n ((originalProps: Props) => (\n // This is render function, we cannot call any hooks here.\n <BuildRenderCallback originalProps={originalProps} render={result.render} />\n ))\n );\n },\n [enhancer]\n );\n };\n\n type BuildRenderCallbackProps = {\n readonly originalProps: Props;\n readonly render: () => ReactNode;\n };\n\n // Do not memoize <BuildRenderCallback>.\n // `bindProps` may have side effect and we want to be re-rendered to capture the side-effect.\n // To prevent wasted render, web devs should memoize it themselves.\n function BuildRenderCallback({ originalProps, render }: BuildRenderCallbackProps) {\n const context = useMemo<RenderContextType<Props>>(() => Object.freeze({ originalProps }), [originalProps]);\n\n return <RenderContext.Provider value={context}>{render()}</RenderContext.Provider>;\n }\n\n function ChainOfResponsibilityProvider({ children, init, middleware }: ProviderProps<Request, Props, Init>) {\n if (!Array.isArray(middleware) || middleware.some(middleware => typeof middleware !== 'function')) {\n throw new Error('react-chain-of-responsibility: \"middleware\" prop must be an array of functions');\n }\n\n // Remap the middleware, so all inputs/outputs are validated.\n const fortifiedMiddleware = useMemo(\n () =>\n Object.freeze(\n middleware.map<ComponentMiddleware<Request, Props, Init>>(fn => (init: Init) => {\n const enhancer = fn(init);\n\n return next => originalRequest => {\n // False positive: although we did not re-assign the variable from true, it was initialized as undefined.\n // eslint-disable-next-line prefer-const\n let hasReturned: boolean;\n\n const returnValue = enhancer(nextRequest => {\n if (hasReturned) {\n throw new Error(\n 'react-chain-of-responsibility: next() cannot be called after the function had returned synchronously'\n );\n }\n\n // We do not allow passing void/undefined to next() because it would be confusing whether to keep the original request or pass an undefined.\n !options.passModifiedRequest &&\n !Object.is(nextRequest, originalRequest) &&\n console.warn(\n 'react-chain-of-responsibility: next() must be called with the original request, otherwise, set \"options.passModifiedRequest\" to true to pass a different request object downstream'\n );\n\n return next(options.passModifiedRequest ? nextRequest : originalRequest);\n })(originalRequest);\n\n hasReturned = true;\n\n // Make sure the return value is built using our helper function for forward-compatibility reason.\n return returnValue && parse(componentHandlerResultSchema, returnValue);\n };\n })\n ),\n [middleware]\n );\n\n const { enhancer: parentEnhancer } = useContext(BuildContext);\n\n const enhancer = useMemo<ComponentEnhancer<Request, Props>>(\n () =>\n // We are reversing because it is easier to read:\n // - With reverse, [a, b, c] will become a(b(c(fn)))\n // - Without reverse, [a, b, c] will become c(b(a(fn)))\n applyMiddleware<ComponentHandlerResult<Props> | undefined, Request, Init>(\n ...[...fortifiedMiddleware, ...[() => parentEnhancer]]\n )(init as Init),\n [init, fortifiedMiddleware, parentEnhancer]\n );\n\n const contextValue = useMemo<BuildContextType<Request, Props>>(() => Object.freeze({ enhancer }), [enhancer]);\n\n return <BuildContext.Provider value={contextValue}>{children}</BuildContext.Provider>;\n }\n\n function ChainOfResponsibilityProxy({ fallbackComponent, request, ...props }: ProxyProps<Request, Props>) {\n const result = useBuildRenderCallback()(request, { fallbackComponent })?.(props as Props);\n\n return result ? <Fragment>{result}</Fragment> : null;\n }\n\n const MemoizedChainOfResponsibilityProvider =\n memo<ProviderProps<Request, Props, Init>>(ChainOfResponsibilityProvider);\n\n return Object.freeze({\n Provider: MemoizedChainOfResponsibilityProvider as typeof MemoizedChainOfResponsibilityProvider &\n InferenceHelper<Request, Props, Init>,\n Proxy: ChainOfResponsibilityProxy,\n reactComponent,\n useBuildRenderCallback\n\n // TODO: Consider adding back `asMiddleware`.\n });\n}\n\nexport default createChainOfResponsibility;\nexport {\n type ChainOfResponsibility,\n type ComponentEnhancer,\n type ComponentHandler,\n type ComponentHandlerResult,\n type ComponentMiddleware,\n type ComponentRenderer,\n type CreateChainOfResponsibilityOptions,\n type InferenceHelper,\n type InferInit,\n type InferMiddleware,\n type InferProps,\n type InferProviderProps,\n type InferProxyProps,\n type InferRequest,\n type ProviderProps,\n type ProxyProps,\n type ReactComponentHandlerResult,\n type UseBuildRenderCallback,\n type UseBuildRenderCallbackOptions\n};\n","// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function arePropsEqual<T extends Record<string, any>>(x: T, y: T): boolean {\n if (Object.is(x, y)) {\n return true;\n }\n\n const mapOfX = new Map(Object.entries(x));\n const mapOfY = new Map(Object.entries(y));\n\n if (mapOfX.size !== mapOfY.size) {\n return false;\n }\n\n const keys = new Set([...mapOfX.keys(), ...mapOfY.keys()]);\n\n for (const key of keys) {\n if (!Object.is(mapOfX.get(key), mapOfY.get(key))) {\n return false;\n }\n }\n\n return true;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,2BAAgC;AAChC,mBAWO;AAEP,qBAA4D;;;ACb7C,SAAR,cAA8D,GAAM,GAAe;AACxF,MAAI,OAAO,GAAG,GAAG,CAAC,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC;AACxC,QAAM,SAAS,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC;AAExC,MAAI,OAAO,SAAS,OAAO,MAAM;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC;AAEzD,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,OAAO,GAAG,OAAO,IAAI,GAAG,GAAG,OAAO,IAAI,GAAG,CAAC,GAAG;AAChD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ADkCA,IAAM,qCAAqC,OAAO;AAKlD,IAAM,mCAA+B;AAAA,EACnC,eACE,8BAAU,uBAAO,EAAE,YAAQ,0BAAU,EAAE,CAAC,GAAG,KAAK,EAAE,WAClD,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,sCAAsC;AAAA,EACxC;AACF;AA+FA,SAAS,6BACP,QAC+B;AAC/B,SAAO,OAAO,OAAO,EAAE,CAAC,kCAAkC,GAAG,QAAW,OAAO,CAAC;AAClF;AAEA,SAAS,4BAIP,UAA8C,CAAC,GAAgD;AAE/F,YAAU,OAAO,OAAO,EAAE,GAAG,QAAQ,CAAC;AAEtC,QAAM,mBAAe;AAAA,IACnB,OAAO,OAAO,EAAE,UAAU,UAAQ,aAAW,KAAK,OAAO,EAAE,CAAC;AAAA,EAC9D;AAEA,QAAM,oBAAgB;AAAA;AAAA,IAEpB,IAAI,MAAM,CAAC,GAAU;AAAA,MACnB,MAAM;AAGJ,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,eACP,WAEA,WACA,MAC+B;AAE/B,UAAM,wBAAwB;AAE9B,SAAI,6BAAM,qBAAoB,KAAK,cAAc;AAC/C,aAAO,6BAA6B,CAAC,oBACnC,6BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB,KAAK;AAAA,UACvB,cAAc,KAAK;AAAA;AAAA,MACrB,CACD;AAAA,IACH,OAAO;AACL,aAAO,6BAA6B,CAAC,oBACnC,6BAAAA,QAAA,cAAC,yBAAsB,WAAsB,WAAsB,iBAAkC,CACtG;AAAA,IACH;AAAA,EACF;AAcA,QAAM,uBAAmB,mBAAsC,SAASC,kBAGtE;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,kBAAkBA;AAAA,IAClB;AAAA,EACF,GAAgC;AAC9B,UAAM,EAAE,mBAAmB,IAAI;AAC/B,UAAM,EAAE,eAAe,oBAAoB,QAAI,yBAAW,aAAa;AAEvE,QAAI,mBAAmB,CAAC,cAAc,iBAAiB,mBAAmB,KAAK,CAAC,oBAAoB;AAClG,cAAQ,KAAK,2FAA2F;AAAA,IAC1G;AAEA,UAAM,QAAQ,OAAO;AAAA,MACnB,qBAAqB,EAAE,GAAG,qBAAqB,GAAG,gBAAgB,IAAI,EAAE,GAAG,oBAAoB;AAAA,IACjG;AAEA,UAAM,QACJ,6BAAAD,QAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAI;AAAA,UACH,GAAG;AAAA,UACH,GAAI,OAAO,cAAc,aAAa,UAAU,KAAK,IAAI;AAAA,QAC3D;AAAA;AAAA,IACF;AAGF,WAAOC,qBAAoB,eACzB,6BAAAD,QAAA,cAACC,mBAAA,EAAkB,GAAI,OAAO,iBAAiB,aAAa,aAAa,KAAK,IAAI,gBAC/E,KACH,IAEA;AAAA,EAEJ,CAAC;AAED,QAAM,yBAAuE,MAAM;AACjF,UAAM,EAAE,SAAS,QAAI,yBAAW,YAAY;AAE5C,eAAO;AAAA,MACL,CAAC,SAAS,eAAe,CAAC,MAAM;AAC9B,cAAM;AAAA;AAAA,UAEJ,SAAS,MAAM;AACb,kBAAM,EAAE,kBAAkB,IAAI;AAE9B,gBAAI,CAAC,mBAAmB;AACtB,sBAAQ;AAAA,gBACN;AAAA,gBACA;AAAA,cACF;AAGA;AAAA,YACF;AAGA,mBAAO,eAAe,iBAAiB;AAAA,UACzC,CAAC,EAAE,OAAO;AAAA;AAEZ,eACE,WACC,CAAC;AAAA;AAAA,UAEA,6BAAAD,QAAA,cAAC,uBAAoB,eAA8B,QAAQ,OAAO,QAAQ;AAAA;AAAA,MAGhF;AAAA,MACA,CAAC,QAAQ;AAAA,IACX;AAAA,EACF;AAUA,WAAS,oBAAoB,EAAE,eAAe,OAAO,GAA6B;AAChF,UAAM,cAAU,sBAAkC,MAAM,OAAO,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC;AAEzG,WAAO,6BAAAA,QAAA,cAAC,cAAc,UAAd,EAAuB,OAAO,WAAU,OAAO,CAAE;AAAA,EAC3D;AAEA,WAAS,8BAA8B,EAAE,UAAU,MAAM,WAAW,GAAwC;AAC1G,QAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,WAAW,KAAK,CAAAE,gBAAc,OAAOA,gBAAe,UAAU,GAAG;AACjG,YAAM,IAAI,MAAM,gFAAgF;AAAA,IAClG;AAGA,UAAM,0BAAsB;AAAA,MAC1B,MACE,OAAO;AAAA,QACL,WAAW,IAA+C,QAAM,CAACC,UAAe;AAC9E,gBAAMC,YAAW,GAAGD,KAAI;AAExB,iBAAO,UAAQ,qBAAmB;AAGhC,gBAAI;AAEJ,kBAAM,cAAcC,UAAS,iBAAe;AAC1C,kBAAI,aAAa;AACf,sBAAM,IAAI;AAAA,kBACR;AAAA,gBACF;AAAA,cACF;AAGA,eAAC,QAAQ,uBACP,CAAC,OAAO,GAAG,aAAa,eAAe,KACvC,QAAQ;AAAA,gBACN;AAAA,cACF;AAEF,qBAAO,KAAK,QAAQ,sBAAsB,cAAc,eAAe;AAAA,YACzE,CAAC,EAAE,eAAe;AAElB,0BAAc;AAGd,mBAAO,mBAAe,sBAAM,8BAA8B,WAAW;AAAA,UACvE;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACF,CAAC,UAAU;AAAA,IACb;AAEA,UAAM,EAAE,UAAU,eAAe,QAAI,yBAAW,YAAY;AAE5D,UAAM,eAAW;AAAA,MACf;AAAA;AAAA;AAAA;AAAA,YAIE;AAAA,UACE,GAAG,CAAC,GAAG,qBAAqB,GAAG,CAAC,MAAM,cAAc,CAAC;AAAA,QACvD,EAAE,IAAY;AAAA;AAAA,MAChB,CAAC,MAAM,qBAAqB,cAAc;AAAA,IAC5C;AAEA,UAAM,mBAAe,sBAA0C,MAAM,OAAO,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;AAE5G,WAAO,6BAAAJ,QAAA,cAAC,aAAa,UAAb,EAAsB,OAAO,gBAAe,QAAS;AAAA,EAC/D;AAEA,WAAS,2BAA2B,EAAE,mBAAmB,SAAS,GAAG,MAAM,GAA+B;AA/X5G;AAgYI,UAAM,UAAS,4BAAuB,EAAE,SAAS,EAAE,kBAAkB,CAAC,MAAvD,mBAA2D;AAE1E,WAAO,SAAS,6BAAAA,QAAA,cAAC,6BAAU,MAAO,IAAc;AAAA,EAClD;AAEA,QAAM,4CACJ,mBAA0C,6BAA6B;AAEzE,SAAO,OAAO,OAAO;AAAA,IACnB,UAAU;AAAA,IAEV,OAAO;AAAA,IACP;AAAA,IACA;AAAA;AAAA,EAGF,CAAC;AACH;AAEA,IAAO,sDAAQ;","names":["React","WrapperComponent","middleware","init","enhancer"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.preview.ts","../src/preview/createChainOfResponsibilityAsRenderCallback.tsx","../src/preview/private/arePropsEqual.ts"],"sourcesContent":["export {\n default as createChainOfResponsibility,\n type ChainOfResponsibility,\n type ComponentEnhancer,\n type ComponentHandler,\n type ComponentHandlerResult,\n type ComponentMiddleware,\n type ComponentRenderer,\n type CreateChainOfResponsibilityOptions,\n type InferenceHelper,\n type InferInit,\n type InferMiddleware,\n type InferProps,\n type InferProviderProps,\n type InferProxyProps,\n type InferRequest,\n type ProviderProps,\n type ProxyProps,\n type ReactComponentHandlerResult,\n type UseBuildRenderCallback,\n type UseBuildRenderCallbackOptions\n} from './preview/createChainOfResponsibilityAsRenderCallback.tsx';\n","import { applyMiddleware } from 'handler-chain';\nimport React, { type ComponentType, type PropsWithChildren, type ReactElement, type ReactNode } from 'react';\nimport { type SetOptional } from 'type-fest';\nimport { custom, function_, object, parse, safeParse } from 'valibot';\n\nimport arePropsEqual from './private/arePropsEqual.ts';\n\nconst { createContext, Fragment, memo, useCallback, useContext, useMemo } = React;\n\n// TODO: Related to https://github.com/microsoft/TypeScript/issues/17002.\n// typescript@5.2.2 has a bug, Array.isArray() is a type predicate but only works with mutable array, not readonly array.\ndeclare global {\n interface ArrayConstructor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n isArray(arg: any): arg is readonly any[];\n }\n}\n\ntype BaseProps = object;\n\ntype CreateChainOfResponsibilityOptions = {\n /**\n * Allows one component to pass different set of props to its downstream component. Default is false.\n *\n * It is recommended to keep this settings as default to prevent newly added component from unexpectedly changing behavior of downstream components.\n */\n readonly allowOverrideProps?: boolean | undefined;\n\n /**\n * Allows a middleware to pass another request object when calling its next middleware. Default is false.\n *\n * It is recommended to keep this settings as default ot prevent newly added middleware from unexpectedly changing behavior of downstream middleware.\n *\n * To prevent upstream middleware from modifying the request, the request object should be set to be immutable through `Object.freeze`.\n */\n readonly passModifiedRequest?: boolean | undefined;\n};\n\ntype ChainOfResponsibility<Request, Props extends BaseProps, Init> = {\n readonly Provider: ComponentType<ProviderProps<Request, Props, Init>> & InferenceHelper<Request, Props, Init>;\n readonly Proxy: ComponentType<ProxyProps<Request, Props>>;\n readonly reactComponent: ReactComponentHandlerResult<Props>;\n readonly useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props>;\n};\n\n// TODO: Maybe this one should be local.\n// Verify that reactComponent() from an instance of CoR should throw error when used in another instance of CoR.\nconst DO_NOT_CREATE_THIS_OBJECT_YOURSELF = Symbol();\n\ntype ComponentRenderer<Props> = (props: Props) => ReactElement | null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst componentHandlerResultSchema = custom<ComponentHandlerResult<any>>(\n value =>\n safeParse(object({ render: function_() }), value).success &&\n !!value &&\n typeof value === 'object' &&\n DO_NOT_CREATE_THIS_OBJECT_YOURSELF in value,\n 'react-chain-of-responsibility: middleware must return value constructed by reactComponent()'\n);\n\ninterface ComponentHandlerResult<Props extends BaseProps> {\n readonly [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined;\n readonly render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null;\n}\n\ntype ComponentHandler<Request, Props extends BaseProps> = (\n request: Request\n) => ComponentHandlerResult<Props> | undefined;\n\ntype ComponentEnhancer<Request, Props extends BaseProps> = (\n next: ComponentHandler<Request, Props>\n) => ComponentHandler<Request, Props>;\n\ntype ComponentMiddleware<Request, Props extends BaseProps, Init = undefined> = (\n init: Init\n) => ComponentEnhancer<Request, Props>;\n\ntype ReactComponentInit<\n Props extends BaseProps,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n> = W extends void\n ? {\n wrapperComponent?: undefined;\n wrapperProps?: undefined;\n }\n : {\n wrapperComponent: ComponentType<W>;\n wrapperProps: W | ((props: Props) => W);\n };\n\ntype ReactComponentHandlerResult<Props extends BaseProps> = <\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n>(\n component: ComponentType<P>,\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W>\n) => ComponentHandlerResult<Props>;\n\ntype UseBuildRenderCallbackOptions<Props> = {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n};\n\ninterface UseBuildRenderCallback<Request, Props extends BaseProps> {\n (request: Request, options?: undefined | UseBuildRenderCallbackOptions<Props>): ComponentRenderer<Props> | undefined;\n}\n\ntype BuildContextType<Request, Props extends BaseProps> = {\n readonly enhancer: ComponentEnhancer<Request, Props>;\n};\n\ntype RenderContextType<Props> = {\n readonly originalProps: Props;\n};\n\ntype ProviderProps<Request, Props extends BaseProps, Init> = PropsWithChildren<{\n readonly middleware: readonly ComponentMiddleware<Request, Props, Init>[];\n}> &\n (Init extends never | void\n ? { readonly init?: undefined }\n : Init extends undefined | void\n ? { readonly init?: Init }\n : { readonly init: Init });\n\ntype ProxyProps<Request, Props extends BaseProps> = Props & {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n readonly request: Request;\n};\n\ntype InferenceHelper<Request, Props extends BaseProps, Init> = {\n readonly '~types': {\n readonly init: Init;\n readonly middleware: ComponentMiddleware<Request, Props, Init>;\n readonly props: Props;\n readonly proxyProps: ProxyProps<Request, Props>;\n readonly providerProps: ProviderProps<Request, Props, Init>;\n readonly request: Request;\n };\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferInit<T extends InferenceHelper<any, any, any>> = T['~types']['init'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferMiddleware<T extends InferenceHelper<any, any, any>> = T['~types']['middleware'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProps<T extends InferenceHelper<any, any, any>> = T['~types']['props'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProxyProps<T extends InferenceHelper<any, any, any>> = T['~types']['proxyProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProviderProps<T extends InferenceHelper<any, any, any>> = T['~types']['providerProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferRequest<T extends InferenceHelper<any, any, any>> = T['~types']['request'];\n\nfunction createComponentHandlerResult<Props extends BaseProps>(\n render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null\n): ComponentHandlerResult<Props> {\n return Object.freeze({ [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined, render });\n}\n\nfunction createChainOfResponsibility<\n Request = void,\n Props extends BaseProps = { readonly children?: never },\n Init = void\n>(options: CreateChainOfResponsibilityOptions = {}): ChainOfResponsibility<Request, Props, Init> {\n // Freeze options to prevent accidental change.\n options = Object.freeze({ ...options });\n\n const BuildContext = createContext<BuildContextType<Request, Props>>(\n Object.freeze({ enhancer: next => request => next(request) })\n );\n\n const RenderContext = createContext<RenderContextType<Props>>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new Proxy({} as any, {\n get() {\n // The following is assertion, there is no way to hit this line.\n /* istanbul ignore next */\n throw new Error(\n 'react-chain-of-responsibility: this hook cannot be used outside of <Proxy> and useBuildRenderCallback()'\n );\n }\n })\n );\n\n function reactComponent<P extends Props, W extends (BaseProps & { children?: ReactNode | undefined }) | void = void>(\n component: ComponentType<P>,\n // For `bindProps` of type function, do not do side-effect in it, it may not be always called in all scenarios.\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W> | undefined\n ): ComponentHandlerResult<Props> {\n // memo() and generic type do not play well together.\n const TypedWrapperComponent = WrapperComponent as ComponentType<WrapperComponentProps<P, W>>;\n\n if (init?.wrapperComponent && init.wrapperProps) {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent\n bindProps={bindProps}\n component={component}\n overridingProps={overridingProps}\n wrapperComponent={init.wrapperComponent as ComponentType<W>}\n wrapperProps={init.wrapperProps as W}\n />\n ));\n } else {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent bindProps={bindProps} component={component} overridingProps={overridingProps} />\n ));\n }\n }\n\n type WrapperComponentProps<\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n > = {\n readonly bindProps: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined;\n readonly component: ComponentType<P>;\n readonly overridingProps: Partial<Props> | undefined;\n readonly wrapperComponent?: ComponentType<W> | undefined;\n readonly wrapperProps?: W | ((props: Props) => W) | undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const WrapperComponent = memo<WrapperComponentProps<any, any>>(function WrapperComponent<\n P extends Props,\n W extends BaseProps & { children?: ReactNode | undefined }\n >({\n bindProps,\n component: Component,\n overridingProps,\n wrapperComponent: WrapperComponent,\n wrapperProps\n }: WrapperComponentProps<P, W>) {\n const { allowOverrideProps } = options;\n const { originalProps: renderCallbackProps } = useContext(RenderContext);\n\n if (overridingProps && !arePropsEqual(overridingProps, renderCallbackProps) && !allowOverrideProps) {\n console.warn('react-chain-of-responsibility: \"allowOverrideProps\" must be set to true to override props');\n }\n\n const props = Object.freeze(\n allowOverrideProps ? { ...renderCallbackProps, ...overridingProps } : { ...renderCallbackProps }\n );\n\n const child = (\n <Component\n {...({\n ...props,\n ...(typeof bindProps === 'function' ? bindProps(props) : bindProps)\n } as P)}\n />\n );\n\n return WrapperComponent && wrapperProps ? (\n <WrapperComponent {...(typeof wrapperProps === 'function' ? wrapperProps(props) : wrapperProps)}>\n {child}\n </WrapperComponent>\n ) : (\n child\n );\n });\n\n const useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props> = () => {\n const { enhancer } = useContext(BuildContext);\n\n return useCallback(\n (request, buildOptions = {}) => {\n const result =\n // Put the \"fallbackComponent\" as the last one in the chain.\n enhancer(() => {\n const { fallbackComponent } = buildOptions;\n\n if (!fallbackComponent) {\n console.warn(\n 'react-chain-of-responsibility: the request has fall through all middleware, set \"fallbackComponent\" as a catchall',\n request\n );\n\n // For clarity, we are returning `undefined` instead of `() => undefined`.\n return;\n }\n\n // `fallbackComponent` do not need `overridingProps` because it is the last one in the chain, it would not have the next() function.\n return reactComponent(fallbackComponent);\n })(request);\n\n return (\n result &&\n ((originalProps: Props) => (\n // This is render function, we cannot call any hooks here.\n <BuildRenderCallback originalProps={originalProps} render={result.render} />\n ))\n );\n },\n [enhancer]\n );\n };\n\n type BuildRenderCallbackProps = {\n readonly originalProps: Props;\n readonly render: () => ReactNode;\n };\n\n // Do not memoize <BuildRenderCallback>.\n // `bindProps` may have side effect and we want to be re-rendered to capture the side-effect.\n // To prevent wasted render, web devs should memoize it themselves.\n function BuildRenderCallback({ originalProps, render }: BuildRenderCallbackProps) {\n const context = useMemo<RenderContextType<Props>>(() => Object.freeze({ originalProps }), [originalProps]);\n\n return <RenderContext.Provider value={context}>{render()}</RenderContext.Provider>;\n }\n\n function ChainOfResponsibilityProvider({ children, init, middleware }: ProviderProps<Request, Props, Init>) {\n if (!Array.isArray(middleware) || middleware.some(middleware => typeof middleware !== 'function')) {\n throw new Error('react-chain-of-responsibility: \"middleware\" prop must be an array of functions');\n }\n\n // Remap the middleware, so all inputs/outputs are validated.\n const fortifiedMiddleware = useMemo(\n () =>\n Object.freeze(\n middleware.map<ComponentMiddleware<Request, Props, Init>>(fn => (init: Init) => {\n const enhancer = fn(init);\n\n return next => originalRequest => {\n // False positive: although we did not re-assign the variable from true, it was initialized as undefined.\n // eslint-disable-next-line prefer-const\n let hasReturned: boolean;\n\n const returnValue = enhancer(nextRequest => {\n if (hasReturned) {\n throw new Error(\n 'react-chain-of-responsibility: next() cannot be called after the function had returned synchronously'\n );\n }\n\n // We do not allow passing void/undefined to next() because it would be confusing whether to keep the original request or pass an undefined.\n !options.passModifiedRequest &&\n !Object.is(nextRequest, originalRequest) &&\n console.warn(\n 'react-chain-of-responsibility: next() must be called with the original request, otherwise, set \"options.passModifiedRequest\" to true to pass a different request object downstream'\n );\n\n return next(options.passModifiedRequest ? nextRequest : originalRequest);\n })(originalRequest);\n\n hasReturned = true;\n\n // Make sure the return value is built using our helper function for forward-compatibility reason.\n return returnValue && parse(componentHandlerResultSchema, returnValue);\n };\n })\n ),\n [middleware]\n );\n\n const { enhancer: parentEnhancer } = useContext(BuildContext);\n\n const enhancer = useMemo<ComponentEnhancer<Request, Props>>(\n () =>\n // We are reversing because it is easier to read:\n // - With reverse, [a, b, c] will become a(b(c(fn)))\n // - Without reverse, [a, b, c] will become c(b(a(fn)))\n applyMiddleware<ComponentHandlerResult<Props> | undefined, Request, Init>(\n ...[...fortifiedMiddleware, ...[() => parentEnhancer]]\n )(init as Init),\n [init, fortifiedMiddleware, parentEnhancer]\n );\n\n const contextValue = useMemo<BuildContextType<Request, Props>>(() => Object.freeze({ enhancer }), [enhancer]);\n\n return <BuildContext.Provider value={contextValue}>{children}</BuildContext.Provider>;\n }\n\n function ChainOfResponsibilityProxy({ fallbackComponent, request, ...props }: ProxyProps<Request, Props>) {\n const result = useBuildRenderCallback()(request, { fallbackComponent })?.(props as Props);\n\n return result ? <Fragment>{result}</Fragment> : null;\n }\n\n const MemoizedChainOfResponsibilityProvider =\n memo<ProviderProps<Request, Props, Init>>(ChainOfResponsibilityProvider);\n\n return Object.freeze({\n Provider: MemoizedChainOfResponsibilityProvider as typeof MemoizedChainOfResponsibilityProvider &\n InferenceHelper<Request, Props, Init>,\n Proxy: ChainOfResponsibilityProxy,\n reactComponent,\n useBuildRenderCallback\n\n // TODO: Consider adding back `asMiddleware`.\n });\n}\n\nexport default createChainOfResponsibility;\nexport {\n type ChainOfResponsibility,\n type ComponentEnhancer,\n type ComponentHandler,\n type ComponentHandlerResult,\n type ComponentMiddleware,\n type ComponentRenderer,\n type CreateChainOfResponsibilityOptions,\n type InferenceHelper,\n type InferInit,\n type InferMiddleware,\n type InferProps,\n type InferProviderProps,\n type InferProxyProps,\n type InferRequest,\n type ProviderProps,\n type ProxyProps,\n type ReactComponentHandlerResult,\n type UseBuildRenderCallback,\n type UseBuildRenderCallbackOptions\n};\n","// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function arePropsEqual<T extends Record<string, any>>(x: T, y: T): boolean {\n if (Object.is(x, y)) {\n return true;\n }\n\n const mapOfX = new Map(Object.entries(x));\n const mapOfY = new Map(Object.entries(y));\n\n if (mapOfX.size !== mapOfY.size) {\n return false;\n }\n\n const keys = new Set([...mapOfX.keys(), ...mapOfY.keys()]);\n\n for (const key of keys) {\n if (!Object.is(mapOfX.get(key), mapOfY.get(key))) {\n return false;\n }\n }\n\n return true;\n}\n"],"mappings":"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","names":["React","WrapperComponent","middleware","init","enhancer"]}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
// src/preview/createChainOfResponsibilityAsRenderCallback.tsx
|
|
2
2
|
import { applyMiddleware } from "handler-chain";
|
|
3
|
-
import React
|
|
4
|
-
createContext,
|
|
5
|
-
Fragment,
|
|
6
|
-
memo,
|
|
7
|
-
useCallback,
|
|
8
|
-
useContext,
|
|
9
|
-
useMemo
|
|
10
|
-
} from "react";
|
|
3
|
+
import React from "react";
|
|
11
4
|
import { custom, function_, object, parse, safeParse } from "valibot";
|
|
12
5
|
|
|
13
6
|
// src/preview/private/arePropsEqual.ts
|
|
@@ -30,6 +23,7 @@ function arePropsEqual(x, y) {
|
|
|
30
23
|
}
|
|
31
24
|
|
|
32
25
|
// src/preview/createChainOfResponsibilityAsRenderCallback.tsx
|
|
26
|
+
var { createContext, Fragment, memo, useCallback, useContext, useMemo } = React;
|
|
33
27
|
var DO_NOT_CREATE_THIS_OBJECT_YOURSELF = Symbol();
|
|
34
28
|
var componentHandlerResultSchema = custom(
|
|
35
29
|
(value) => safeParse(object({ render: function_() }), value).success && !!value && typeof value === "object" && DO_NOT_CREATE_THIS_OBJECT_YOURSELF in value,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/preview/createChainOfResponsibilityAsRenderCallback.tsx","../src/preview/private/arePropsEqual.ts"],"sourcesContent":["import { applyMiddleware } from 'handler-chain';\nimport React, {\n createContext,\n Fragment,\n memo,\n useCallback,\n useContext,\n useMemo,\n type ComponentType,\n type PropsWithChildren,\n type ReactElement,\n type ReactNode\n} from 'react';\nimport { type SetOptional } from 'type-fest';\nimport { custom, function_, object, parse, safeParse } from 'valibot';\n\nimport arePropsEqual from './private/arePropsEqual.ts';\n\n// TODO: Related to https://github.com/microsoft/TypeScript/issues/17002.\n// typescript@5.2.2 has a bug, Array.isArray() is a type predicate but only works with mutable array, not readonly array.\ndeclare global {\n interface ArrayConstructor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n isArray(arg: any): arg is readonly any[];\n }\n}\n\ntype BaseProps = object;\n\ntype CreateChainOfResponsibilityOptions = {\n /**\n * Allows one component to pass different set of props to its downstream component. Default is false.\n *\n * It is recommended to keep this settings as default to prevent newly added component from unexpectedly changing behavior of downstream components.\n */\n readonly allowOverrideProps?: boolean | undefined;\n\n /**\n * Allows a middleware to pass another request object when calling its next middleware. Default is false.\n *\n * It is recommended to keep this settings as default ot prevent newly added middleware from unexpectedly changing behavior of downstream middleware.\n *\n * To prevent upstream middleware from modifying the request, the request object should be set to be immutable through `Object.freeze`.\n */\n readonly passModifiedRequest?: boolean | undefined;\n};\n\ntype ChainOfResponsibility<Request, Props extends BaseProps, Init> = {\n readonly Provider: ComponentType<ProviderProps<Request, Props, Init>> & InferenceHelper<Request, Props, Init>;\n readonly Proxy: ComponentType<ProxyProps<Request, Props>>;\n readonly reactComponent: ReactComponentHandlerResult<Props>;\n readonly useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props>;\n};\n\n// TODO: Maybe this one should be local.\n// Verify that reactComponent() from an instance of CoR should throw error when used in another instance of CoR.\nconst DO_NOT_CREATE_THIS_OBJECT_YOURSELF = Symbol();\n\ntype ComponentRenderer<Props> = (props: Props) => ReactElement | null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst componentHandlerResultSchema = custom<ComponentHandlerResult<any>>(\n value =>\n safeParse(object({ render: function_() }), value).success &&\n !!value &&\n typeof value === 'object' &&\n DO_NOT_CREATE_THIS_OBJECT_YOURSELF in value,\n 'react-chain-of-responsibility: middleware must return value constructed by reactComponent()'\n);\n\ninterface ComponentHandlerResult<Props extends BaseProps> {\n readonly [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined;\n readonly render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null;\n}\n\ntype ComponentHandler<Request, Props extends BaseProps> = (\n request: Request\n) => ComponentHandlerResult<Props> | undefined;\n\ntype ComponentEnhancer<Request, Props extends BaseProps> = (\n next: ComponentHandler<Request, Props>\n) => ComponentHandler<Request, Props>;\n\ntype ComponentMiddleware<Request, Props extends BaseProps, Init = undefined> = (\n init: Init\n) => ComponentEnhancer<Request, Props>;\n\ntype ReactComponentInit<\n Props extends BaseProps,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n> = W extends void\n ? {\n wrapperComponent?: undefined;\n wrapperProps?: undefined;\n }\n : {\n wrapperComponent: ComponentType<W>;\n wrapperProps: W | ((props: Props) => W);\n };\n\ntype ReactComponentHandlerResult<Props extends BaseProps> = <\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n>(\n component: ComponentType<P>,\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W>\n) => ComponentHandlerResult<Props>;\n\ntype UseBuildRenderCallbackOptions<Props> = {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n};\n\ninterface UseBuildRenderCallback<Request, Props extends BaseProps> {\n (request: Request, options?: undefined | UseBuildRenderCallbackOptions<Props>): ComponentRenderer<Props> | undefined;\n}\n\ntype BuildContextType<Request, Props extends BaseProps> = {\n readonly enhancer: ComponentEnhancer<Request, Props>;\n};\n\ntype RenderContextType<Props> = {\n readonly originalProps: Props;\n};\n\ntype ProviderProps<Request, Props extends BaseProps, Init> = PropsWithChildren<{\n readonly middleware: readonly ComponentMiddleware<Request, Props, Init>[];\n}> &\n (Init extends never | void\n ? { readonly init?: undefined }\n : Init extends undefined | void\n ? { readonly init?: Init }\n : { readonly init: Init });\n\ntype ProxyProps<Request, Props extends BaseProps> = Props & {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n readonly request: Request;\n};\n\ntype InferenceHelper<Request, Props extends BaseProps, Init> = {\n readonly '~types': {\n readonly init: Init;\n readonly middleware: ComponentMiddleware<Request, Props, Init>;\n readonly props: Props;\n readonly proxyProps: ProxyProps<Request, Props>;\n readonly providerProps: ProviderProps<Request, Props, Init>;\n readonly request: Request;\n };\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferInit<T extends InferenceHelper<any, any, any>> = T['~types']['init'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferMiddleware<T extends InferenceHelper<any, any, any>> = T['~types']['middleware'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProps<T extends InferenceHelper<any, any, any>> = T['~types']['props'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProxyProps<T extends InferenceHelper<any, any, any>> = T['~types']['proxyProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProviderProps<T extends InferenceHelper<any, any, any>> = T['~types']['providerProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferRequest<T extends InferenceHelper<any, any, any>> = T['~types']['request'];\n\nfunction createComponentHandlerResult<Props extends BaseProps>(\n render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null\n): ComponentHandlerResult<Props> {\n return Object.freeze({ [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined, render });\n}\n\nfunction createChainOfResponsibility<\n Request = void,\n Props extends BaseProps = { readonly children?: never },\n Init = void\n>(options: CreateChainOfResponsibilityOptions = {}): ChainOfResponsibility<Request, Props, Init> {\n // Freeze options to prevent accidental change.\n options = Object.freeze({ ...options });\n\n const BuildContext = createContext<BuildContextType<Request, Props>>(\n Object.freeze({ enhancer: next => request => next(request) })\n );\n\n const RenderContext = createContext<RenderContextType<Props>>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new Proxy({} as any, {\n get() {\n // The following is assertion, there is no way to hit this line.\n /* istanbul ignore next */\n throw new Error(\n 'react-chain-of-responsibility: this hook cannot be used outside of <Proxy> and useBuildRenderCallback()'\n );\n }\n })\n );\n\n function reactComponent<P extends Props, W extends (BaseProps & { children?: ReactNode | undefined }) | void = void>(\n component: ComponentType<P>,\n // For `bindProps` of type function, do not do side-effect in it, it may not be always called in all scenarios.\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W> | undefined\n ): ComponentHandlerResult<Props> {\n // memo() and generic type do not play well together.\n const TypedWrapperComponent = WrapperComponent as ComponentType<WrapperComponentProps<P, W>>;\n\n if (init?.wrapperComponent && init.wrapperProps) {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent\n bindProps={bindProps}\n component={component}\n overridingProps={overridingProps}\n wrapperComponent={init.wrapperComponent as ComponentType<W>}\n wrapperProps={init.wrapperProps as W}\n />\n ));\n } else {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent bindProps={bindProps} component={component} overridingProps={overridingProps} />\n ));\n }\n }\n\n type WrapperComponentProps<\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n > = {\n readonly bindProps: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined;\n readonly component: ComponentType<P>;\n readonly overridingProps: Partial<Props> | undefined;\n readonly wrapperComponent?: ComponentType<W> | undefined;\n readonly wrapperProps?: W | ((props: Props) => W) | undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const WrapperComponent = memo<WrapperComponentProps<any, any>>(function WrapperComponent<\n P extends Props,\n W extends BaseProps & { children?: ReactNode | undefined }\n >({\n bindProps,\n component: Component,\n overridingProps,\n wrapperComponent: WrapperComponent,\n wrapperProps\n }: WrapperComponentProps<P, W>) {\n const { allowOverrideProps } = options;\n const { originalProps: renderCallbackProps } = useContext(RenderContext);\n\n if (overridingProps && !arePropsEqual(overridingProps, renderCallbackProps) && !allowOverrideProps) {\n console.warn('react-chain-of-responsibility: \"allowOverrideProps\" must be set to true to override props');\n }\n\n const props = Object.freeze(\n allowOverrideProps ? { ...renderCallbackProps, ...overridingProps } : { ...renderCallbackProps }\n );\n\n const child = (\n <Component\n {...({\n ...props,\n ...(typeof bindProps === 'function' ? bindProps(props) : bindProps)\n } as P)}\n />\n );\n\n return WrapperComponent && wrapperProps ? (\n <WrapperComponent {...(typeof wrapperProps === 'function' ? wrapperProps(props) : wrapperProps)}>\n {child}\n </WrapperComponent>\n ) : (\n child\n );\n });\n\n const useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props> = () => {\n const { enhancer } = useContext(BuildContext);\n\n return useCallback(\n (request, buildOptions = {}) => {\n const result =\n // Put the \"fallbackComponent\" as the last one in the chain.\n enhancer(() => {\n const { fallbackComponent } = buildOptions;\n\n if (!fallbackComponent) {\n console.warn(\n 'react-chain-of-responsibility: the request has fall through all middleware, set \"fallbackComponent\" as a catchall',\n request\n );\n\n // For clarity, we are returning `undefined` instead of `() => undefined`.\n return;\n }\n\n // `fallbackComponent` do not need `overridingProps` because it is the last one in the chain, it would not have the next() function.\n return reactComponent(fallbackComponent);\n })(request);\n\n return (\n result &&\n ((originalProps: Props) => (\n // This is render function, we cannot call any hooks here.\n <BuildRenderCallback originalProps={originalProps} render={result.render} />\n ))\n );\n },\n [enhancer]\n );\n };\n\n type BuildRenderCallbackProps = {\n readonly originalProps: Props;\n readonly render: () => ReactNode;\n };\n\n // Do not memoize <BuildRenderCallback>.\n // `bindProps` may have side effect and we want to be re-rendered to capture the side-effect.\n // To prevent wasted render, web devs should memoize it themselves.\n function BuildRenderCallback({ originalProps, render }: BuildRenderCallbackProps) {\n const context = useMemo<RenderContextType<Props>>(() => Object.freeze({ originalProps }), [originalProps]);\n\n return <RenderContext.Provider value={context}>{render()}</RenderContext.Provider>;\n }\n\n function ChainOfResponsibilityProvider({ children, init, middleware }: ProviderProps<Request, Props, Init>) {\n if (!Array.isArray(middleware) || middleware.some(middleware => typeof middleware !== 'function')) {\n throw new Error('react-chain-of-responsibility: \"middleware\" prop must be an array of functions');\n }\n\n // Remap the middleware, so all inputs/outputs are validated.\n const fortifiedMiddleware = useMemo(\n () =>\n Object.freeze(\n middleware.map<ComponentMiddleware<Request, Props, Init>>(fn => (init: Init) => {\n const enhancer = fn(init);\n\n return next => originalRequest => {\n // False positive: although we did not re-assign the variable from true, it was initialized as undefined.\n // eslint-disable-next-line prefer-const\n let hasReturned: boolean;\n\n const returnValue = enhancer(nextRequest => {\n if (hasReturned) {\n throw new Error(\n 'react-chain-of-responsibility: next() cannot be called after the function had returned synchronously'\n );\n }\n\n // We do not allow passing void/undefined to next() because it would be confusing whether to keep the original request or pass an undefined.\n !options.passModifiedRequest &&\n !Object.is(nextRequest, originalRequest) &&\n console.warn(\n 'react-chain-of-responsibility: next() must be called with the original request, otherwise, set \"options.passModifiedRequest\" to true to pass a different request object downstream'\n );\n\n return next(options.passModifiedRequest ? nextRequest : originalRequest);\n })(originalRequest);\n\n hasReturned = true;\n\n // Make sure the return value is built using our helper function for forward-compatibility reason.\n return returnValue && parse(componentHandlerResultSchema, returnValue);\n };\n })\n ),\n [middleware]\n );\n\n const { enhancer: parentEnhancer } = useContext(BuildContext);\n\n const enhancer = useMemo<ComponentEnhancer<Request, Props>>(\n () =>\n // We are reversing because it is easier to read:\n // - With reverse, [a, b, c] will become a(b(c(fn)))\n // - Without reverse, [a, b, c] will become c(b(a(fn)))\n applyMiddleware<ComponentHandlerResult<Props> | undefined, Request, Init>(\n ...[...fortifiedMiddleware, ...[() => parentEnhancer]]\n )(init as Init),\n [init, fortifiedMiddleware, parentEnhancer]\n );\n\n const contextValue = useMemo<BuildContextType<Request, Props>>(() => Object.freeze({ enhancer }), [enhancer]);\n\n return <BuildContext.Provider value={contextValue}>{children}</BuildContext.Provider>;\n }\n\n function ChainOfResponsibilityProxy({ fallbackComponent, request, ...props }: ProxyProps<Request, Props>) {\n const result = useBuildRenderCallback()(request, { fallbackComponent })?.(props as Props);\n\n return result ? <Fragment>{result}</Fragment> : null;\n }\n\n const MemoizedChainOfResponsibilityProvider =\n memo<ProviderProps<Request, Props, Init>>(ChainOfResponsibilityProvider);\n\n return Object.freeze({\n Provider: MemoizedChainOfResponsibilityProvider as typeof MemoizedChainOfResponsibilityProvider &\n InferenceHelper<Request, Props, Init>,\n Proxy: ChainOfResponsibilityProxy,\n reactComponent,\n useBuildRenderCallback\n\n // TODO: Consider adding back `asMiddleware`.\n });\n}\n\nexport default createChainOfResponsibility;\nexport {\n type ChainOfResponsibility,\n type ComponentEnhancer,\n type ComponentHandler,\n type ComponentHandlerResult,\n type ComponentMiddleware,\n type ComponentRenderer,\n type CreateChainOfResponsibilityOptions,\n type InferenceHelper,\n type InferInit,\n type InferMiddleware,\n type InferProps,\n type InferProviderProps,\n type InferProxyProps,\n type InferRequest,\n type ProviderProps,\n type ProxyProps,\n type ReactComponentHandlerResult,\n type UseBuildRenderCallback,\n type UseBuildRenderCallbackOptions\n};\n","// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function arePropsEqual<T extends Record<string, any>>(x: T, y: T): boolean {\n if (Object.is(x, y)) {\n return true;\n }\n\n const mapOfX = new Map(Object.entries(x));\n const mapOfY = new Map(Object.entries(y));\n\n if (mapOfX.size !== mapOfY.size) {\n return false;\n }\n\n const keys = new Set([...mapOfX.keys(), ...mapOfY.keys()]);\n\n for (const key of keys) {\n if (!Object.is(mapOfX.get(key), mapOfY.get(key))) {\n return false;\n }\n }\n\n return true;\n}\n"],"mappings":"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","names":["WrapperComponent","middleware","init","enhancer"]}
|
|
1
|
+
{"version":3,"sources":["../src/preview/createChainOfResponsibilityAsRenderCallback.tsx","../src/preview/private/arePropsEqual.ts"],"sourcesContent":["import { applyMiddleware } from 'handler-chain';\nimport React, { type ComponentType, type PropsWithChildren, type ReactElement, type ReactNode } from 'react';\nimport { type SetOptional } from 'type-fest';\nimport { custom, function_, object, parse, safeParse } from 'valibot';\n\nimport arePropsEqual from './private/arePropsEqual.ts';\n\nconst { createContext, Fragment, memo, useCallback, useContext, useMemo } = React;\n\n// TODO: Related to https://github.com/microsoft/TypeScript/issues/17002.\n// typescript@5.2.2 has a bug, Array.isArray() is a type predicate but only works with mutable array, not readonly array.\ndeclare global {\n interface ArrayConstructor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n isArray(arg: any): arg is readonly any[];\n }\n}\n\ntype BaseProps = object;\n\ntype CreateChainOfResponsibilityOptions = {\n /**\n * Allows one component to pass different set of props to its downstream component. Default is false.\n *\n * It is recommended to keep this settings as default to prevent newly added component from unexpectedly changing behavior of downstream components.\n */\n readonly allowOverrideProps?: boolean | undefined;\n\n /**\n * Allows a middleware to pass another request object when calling its next middleware. Default is false.\n *\n * It is recommended to keep this settings as default ot prevent newly added middleware from unexpectedly changing behavior of downstream middleware.\n *\n * To prevent upstream middleware from modifying the request, the request object should be set to be immutable through `Object.freeze`.\n */\n readonly passModifiedRequest?: boolean | undefined;\n};\n\ntype ChainOfResponsibility<Request, Props extends BaseProps, Init> = {\n readonly Provider: ComponentType<ProviderProps<Request, Props, Init>> & InferenceHelper<Request, Props, Init>;\n readonly Proxy: ComponentType<ProxyProps<Request, Props>>;\n readonly reactComponent: ReactComponentHandlerResult<Props>;\n readonly useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props>;\n};\n\n// TODO: Maybe this one should be local.\n// Verify that reactComponent() from an instance of CoR should throw error when used in another instance of CoR.\nconst DO_NOT_CREATE_THIS_OBJECT_YOURSELF = Symbol();\n\ntype ComponentRenderer<Props> = (props: Props) => ReactElement | null;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst componentHandlerResultSchema = custom<ComponentHandlerResult<any>>(\n value =>\n safeParse(object({ render: function_() }), value).success &&\n !!value &&\n typeof value === 'object' &&\n DO_NOT_CREATE_THIS_OBJECT_YOURSELF in value,\n 'react-chain-of-responsibility: middleware must return value constructed by reactComponent()'\n);\n\ninterface ComponentHandlerResult<Props extends BaseProps> {\n readonly [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined;\n readonly render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null;\n}\n\ntype ComponentHandler<Request, Props extends BaseProps> = (\n request: Request\n) => ComponentHandlerResult<Props> | undefined;\n\ntype ComponentEnhancer<Request, Props extends BaseProps> = (\n next: ComponentHandler<Request, Props>\n) => ComponentHandler<Request, Props>;\n\ntype ComponentMiddleware<Request, Props extends BaseProps, Init = undefined> = (\n init: Init\n) => ComponentEnhancer<Request, Props>;\n\ntype ReactComponentInit<\n Props extends BaseProps,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n> = W extends void\n ? {\n wrapperComponent?: undefined;\n wrapperProps?: undefined;\n }\n : {\n wrapperComponent: ComponentType<W>;\n wrapperProps: W | ((props: Props) => W);\n };\n\ntype ReactComponentHandlerResult<Props extends BaseProps> = <\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n>(\n component: ComponentType<P>,\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W>\n) => ComponentHandlerResult<Props>;\n\ntype UseBuildRenderCallbackOptions<Props> = {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n};\n\ninterface UseBuildRenderCallback<Request, Props extends BaseProps> {\n (request: Request, options?: undefined | UseBuildRenderCallbackOptions<Props>): ComponentRenderer<Props> | undefined;\n}\n\ntype BuildContextType<Request, Props extends BaseProps> = {\n readonly enhancer: ComponentEnhancer<Request, Props>;\n};\n\ntype RenderContextType<Props> = {\n readonly originalProps: Props;\n};\n\ntype ProviderProps<Request, Props extends BaseProps, Init> = PropsWithChildren<{\n readonly middleware: readonly ComponentMiddleware<Request, Props, Init>[];\n}> &\n (Init extends never | void\n ? { readonly init?: undefined }\n : Init extends undefined | void\n ? { readonly init?: Init }\n : { readonly init: Init });\n\ntype ProxyProps<Request, Props extends BaseProps> = Props & {\n readonly fallbackComponent?: ComponentType<Props> | undefined;\n readonly request: Request;\n};\n\ntype InferenceHelper<Request, Props extends BaseProps, Init> = {\n readonly '~types': {\n readonly init: Init;\n readonly middleware: ComponentMiddleware<Request, Props, Init>;\n readonly props: Props;\n readonly proxyProps: ProxyProps<Request, Props>;\n readonly providerProps: ProviderProps<Request, Props, Init>;\n readonly request: Request;\n };\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferInit<T extends InferenceHelper<any, any, any>> = T['~types']['init'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferMiddleware<T extends InferenceHelper<any, any, any>> = T['~types']['middleware'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProps<T extends InferenceHelper<any, any, any>> = T['~types']['props'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProxyProps<T extends InferenceHelper<any, any, any>> = T['~types']['proxyProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferProviderProps<T extends InferenceHelper<any, any, any>> = T['~types']['providerProps'];\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferRequest<T extends InferenceHelper<any, any, any>> = T['~types']['request'];\n\nfunction createComponentHandlerResult<Props extends BaseProps>(\n render: (overridingProps?: Partial<Props> | undefined) => ReactElement | null\n): ComponentHandlerResult<Props> {\n return Object.freeze({ [DO_NOT_CREATE_THIS_OBJECT_YOURSELF]: undefined, render });\n}\n\nfunction createChainOfResponsibility<\n Request = void,\n Props extends BaseProps = { readonly children?: never },\n Init = void\n>(options: CreateChainOfResponsibilityOptions = {}): ChainOfResponsibility<Request, Props, Init> {\n // Freeze options to prevent accidental change.\n options = Object.freeze({ ...options });\n\n const BuildContext = createContext<BuildContextType<Request, Props>>(\n Object.freeze({ enhancer: next => request => next(request) })\n );\n\n const RenderContext = createContext<RenderContextType<Props>>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n new Proxy({} as any, {\n get() {\n // The following is assertion, there is no way to hit this line.\n /* istanbul ignore next */\n throw new Error(\n 'react-chain-of-responsibility: this hook cannot be used outside of <Proxy> and useBuildRenderCallback()'\n );\n }\n })\n );\n\n function reactComponent<P extends Props, W extends (BaseProps & { children?: ReactNode | undefined }) | void = void>(\n component: ComponentType<P>,\n // For `bindProps` of type function, do not do side-effect in it, it may not be always called in all scenarios.\n bindProps?: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined,\n init?: ReactComponentInit<Props, W> | undefined\n ): ComponentHandlerResult<Props> {\n // memo() and generic type do not play well together.\n const TypedWrapperComponent = WrapperComponent as ComponentType<WrapperComponentProps<P, W>>;\n\n if (init?.wrapperComponent && init.wrapperProps) {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent\n bindProps={bindProps}\n component={component}\n overridingProps={overridingProps}\n wrapperComponent={init.wrapperComponent as ComponentType<W>}\n wrapperProps={init.wrapperProps as W}\n />\n ));\n } else {\n return createComponentHandlerResult((overridingProps?: Partial<Props> | undefined) => (\n <TypedWrapperComponent bindProps={bindProps} component={component} overridingProps={overridingProps} />\n ));\n }\n }\n\n type WrapperComponentProps<\n P extends Props,\n W extends (BaseProps & { children?: ReactNode | undefined }) | void = void\n > = {\n readonly bindProps: SetOptional<P, keyof Props> | ((props: Props) => SetOptional<P, keyof Props>) | undefined;\n readonly component: ComponentType<P>;\n readonly overridingProps: Partial<Props> | undefined;\n readonly wrapperComponent?: ComponentType<W> | undefined;\n readonly wrapperProps?: W | ((props: Props) => W) | undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const WrapperComponent = memo<WrapperComponentProps<any, any>>(function WrapperComponent<\n P extends Props,\n W extends BaseProps & { children?: ReactNode | undefined }\n >({\n bindProps,\n component: Component,\n overridingProps,\n wrapperComponent: WrapperComponent,\n wrapperProps\n }: WrapperComponentProps<P, W>) {\n const { allowOverrideProps } = options;\n const { originalProps: renderCallbackProps } = useContext(RenderContext);\n\n if (overridingProps && !arePropsEqual(overridingProps, renderCallbackProps) && !allowOverrideProps) {\n console.warn('react-chain-of-responsibility: \"allowOverrideProps\" must be set to true to override props');\n }\n\n const props = Object.freeze(\n allowOverrideProps ? { ...renderCallbackProps, ...overridingProps } : { ...renderCallbackProps }\n );\n\n const child = (\n <Component\n {...({\n ...props,\n ...(typeof bindProps === 'function' ? bindProps(props) : bindProps)\n } as P)}\n />\n );\n\n return WrapperComponent && wrapperProps ? (\n <WrapperComponent {...(typeof wrapperProps === 'function' ? wrapperProps(props) : wrapperProps)}>\n {child}\n </WrapperComponent>\n ) : (\n child\n );\n });\n\n const useBuildRenderCallback: () => UseBuildRenderCallback<Request, Props> = () => {\n const { enhancer } = useContext(BuildContext);\n\n return useCallback(\n (request, buildOptions = {}) => {\n const result =\n // Put the \"fallbackComponent\" as the last one in the chain.\n enhancer(() => {\n const { fallbackComponent } = buildOptions;\n\n if (!fallbackComponent) {\n console.warn(\n 'react-chain-of-responsibility: the request has fall through all middleware, set \"fallbackComponent\" as a catchall',\n request\n );\n\n // For clarity, we are returning `undefined` instead of `() => undefined`.\n return;\n }\n\n // `fallbackComponent` do not need `overridingProps` because it is the last one in the chain, it would not have the next() function.\n return reactComponent(fallbackComponent);\n })(request);\n\n return (\n result &&\n ((originalProps: Props) => (\n // This is render function, we cannot call any hooks here.\n <BuildRenderCallback originalProps={originalProps} render={result.render} />\n ))\n );\n },\n [enhancer]\n );\n };\n\n type BuildRenderCallbackProps = {\n readonly originalProps: Props;\n readonly render: () => ReactNode;\n };\n\n // Do not memoize <BuildRenderCallback>.\n // `bindProps` may have side effect and we want to be re-rendered to capture the side-effect.\n // To prevent wasted render, web devs should memoize it themselves.\n function BuildRenderCallback({ originalProps, render }: BuildRenderCallbackProps) {\n const context = useMemo<RenderContextType<Props>>(() => Object.freeze({ originalProps }), [originalProps]);\n\n return <RenderContext.Provider value={context}>{render()}</RenderContext.Provider>;\n }\n\n function ChainOfResponsibilityProvider({ children, init, middleware }: ProviderProps<Request, Props, Init>) {\n if (!Array.isArray(middleware) || middleware.some(middleware => typeof middleware !== 'function')) {\n throw new Error('react-chain-of-responsibility: \"middleware\" prop must be an array of functions');\n }\n\n // Remap the middleware, so all inputs/outputs are validated.\n const fortifiedMiddleware = useMemo(\n () =>\n Object.freeze(\n middleware.map<ComponentMiddleware<Request, Props, Init>>(fn => (init: Init) => {\n const enhancer = fn(init);\n\n return next => originalRequest => {\n // False positive: although we did not re-assign the variable from true, it was initialized as undefined.\n // eslint-disable-next-line prefer-const\n let hasReturned: boolean;\n\n const returnValue = enhancer(nextRequest => {\n if (hasReturned) {\n throw new Error(\n 'react-chain-of-responsibility: next() cannot be called after the function had returned synchronously'\n );\n }\n\n // We do not allow passing void/undefined to next() because it would be confusing whether to keep the original request or pass an undefined.\n !options.passModifiedRequest &&\n !Object.is(nextRequest, originalRequest) &&\n console.warn(\n 'react-chain-of-responsibility: next() must be called with the original request, otherwise, set \"options.passModifiedRequest\" to true to pass a different request object downstream'\n );\n\n return next(options.passModifiedRequest ? nextRequest : originalRequest);\n })(originalRequest);\n\n hasReturned = true;\n\n // Make sure the return value is built using our helper function for forward-compatibility reason.\n return returnValue && parse(componentHandlerResultSchema, returnValue);\n };\n })\n ),\n [middleware]\n );\n\n const { enhancer: parentEnhancer } = useContext(BuildContext);\n\n const enhancer = useMemo<ComponentEnhancer<Request, Props>>(\n () =>\n // We are reversing because it is easier to read:\n // - With reverse, [a, b, c] will become a(b(c(fn)))\n // - Without reverse, [a, b, c] will become c(b(a(fn)))\n applyMiddleware<ComponentHandlerResult<Props> | undefined, Request, Init>(\n ...[...fortifiedMiddleware, ...[() => parentEnhancer]]\n )(init as Init),\n [init, fortifiedMiddleware, parentEnhancer]\n );\n\n const contextValue = useMemo<BuildContextType<Request, Props>>(() => Object.freeze({ enhancer }), [enhancer]);\n\n return <BuildContext.Provider value={contextValue}>{children}</BuildContext.Provider>;\n }\n\n function ChainOfResponsibilityProxy({ fallbackComponent, request, ...props }: ProxyProps<Request, Props>) {\n const result = useBuildRenderCallback()(request, { fallbackComponent })?.(props as Props);\n\n return result ? <Fragment>{result}</Fragment> : null;\n }\n\n const MemoizedChainOfResponsibilityProvider =\n memo<ProviderProps<Request, Props, Init>>(ChainOfResponsibilityProvider);\n\n return Object.freeze({\n Provider: MemoizedChainOfResponsibilityProvider as typeof MemoizedChainOfResponsibilityProvider &\n InferenceHelper<Request, Props, Init>,\n Proxy: ChainOfResponsibilityProxy,\n reactComponent,\n useBuildRenderCallback\n\n // TODO: Consider adding back `asMiddleware`.\n });\n}\n\nexport default createChainOfResponsibility;\nexport {\n type ChainOfResponsibility,\n type ComponentEnhancer,\n type ComponentHandler,\n type ComponentHandlerResult,\n type ComponentMiddleware,\n type ComponentRenderer,\n type CreateChainOfResponsibilityOptions,\n type InferenceHelper,\n type InferInit,\n type InferMiddleware,\n type InferProps,\n type InferProviderProps,\n type InferProxyProps,\n type InferRequest,\n type ProviderProps,\n type ProxyProps,\n type ReactComponentHandlerResult,\n type UseBuildRenderCallback,\n type UseBuildRenderCallbackOptions\n};\n","// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function arePropsEqual<T extends Record<string, any>>(x: T, y: T): boolean {\n if (Object.is(x, y)) {\n return true;\n }\n\n const mapOfX = new Map(Object.entries(x));\n const mapOfY = new Map(Object.entries(y));\n\n if (mapOfX.size !== mapOfY.size) {\n return false;\n }\n\n const keys = new Set([...mapOfX.keys(), ...mapOfY.keys()]);\n\n for (const key of keys) {\n if (!Object.is(mapOfX.get(key), mapOfY.get(key))) {\n return false;\n }\n }\n\n return true;\n}\n"],"mappings":"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","names":["WrapperComponent","middleware","init","enhancer"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-chain-of-responsibility",
|
|
3
|
-
"version": "0.4.3-main.
|
|
3
|
+
"version": "0.4.3-main.202601010031.78b7d38",
|
|
4
4
|
"description": "Using chain of responsibility design pattern for compositing and customizing React component.",
|
|
5
5
|
"files": [
|
|
6
6
|
"./*.js",
|
|
@@ -17,16 +17,6 @@
|
|
|
17
17
|
"default": "./dist/react-chain-of-responsibility.js"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
-
"./fluentUI": {
|
|
21
|
-
"import": {
|
|
22
|
-
"types": "./dist/react-chain-of-responsibility.fluentUI.d.mts",
|
|
23
|
-
"default": "./dist/react-chain-of-responsibility.fluentUI.mjs"
|
|
24
|
-
},
|
|
25
|
-
"require": {
|
|
26
|
-
"types": "./dist/react-chain-of-responsibility.fluentUI.d.ts",
|
|
27
|
-
"default": "./dist/react-chain-of-responsibility.fluentUI.js"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
20
|
"./preview": {
|
|
31
21
|
"import": {
|
|
32
22
|
"types": "./dist/react-chain-of-responsibility.preview.d.mts",
|
|
@@ -45,6 +35,8 @@
|
|
|
45
35
|
"bump": "npm run bump:prod && npm run bump:dev",
|
|
46
36
|
"bump:dev": "PACKAGES_TO_BUMP=$(cat package.json | jq -r '(.pinDependencies // {}) as $P | (.localPeerDependencies // {}) as $L | (.devDependencies // {}) | to_entries | map(select(.key as $K | $L | has($K) | not)) | map(.key + \"@\" + ($P[.key] // [\"latest\"])[0]) | join(\" \")') && [ ! -z \"$PACKAGES_TO_BUMP\" ] && npm install $PACKAGES_TO_BUMP || true",
|
|
47
37
|
"bump:prod": "PACKAGES_TO_BUMP=$(cat package.json | jq -r '(.pinDependencies // {}) as $P | (.localPeerDependencies // {}) as $L | (.dependencies // {}) | to_entries | map(select(.key as $K | $L | has($K) | not)) | map(.key + \"@\" + ($P[.key] // [\"latest\"])[0]) | join(\" \")') && [ ! -z \"$PACKAGES_TO_BUMP\" ] && npm install $PACKAGES_TO_BUMP || true",
|
|
38
|
+
"init": "npm run init:dev --if-present && npm run init:prod --if-present",
|
|
39
|
+
"init:dev": "npm install --save--dev @compulim/test-harness@0.0.0-0 @tsconfig/recommended @tsconfig/strictest @types/node @types/react@18 @types/react-dom@18 escape-string-regexp expect publint react@18 react-dom@18 react-test-renderer@18 tsup typescript",
|
|
48
40
|
"precommit": "npm run precommit:eslint && npm run precommit:publint && npm run precommit:typescript:production && npm run precommit:typescript:test",
|
|
49
41
|
"precommit:eslint": "ESLINT_USE_FLAT_CONFIG=false eslint ./src/",
|
|
50
42
|
"precommit:publint": "publint",
|
|
@@ -53,7 +45,9 @@
|
|
|
53
45
|
"prepack": "cp ../../CHANGELOG.md . && cp ../../LICENSE . && cp ../../README.md .",
|
|
54
46
|
"start": "npm run build -- --onSuccess \"touch ../pages/package.json\" --watch",
|
|
55
47
|
"switch": "cat package.json | jq --arg SWITCH_NAME $SWITCH_NAME -r '(.[\"switch:\" + $SWITCH_NAME] // {}) as $TEMPLATE | .devDependencies += ($TEMPLATE.devDependencies // {}) | .dependencies += ($TEMPLATE.dependencies // {})' | tee ./package.json.tmp && mv ./package.json.tmp ./package.json",
|
|
56
|
-
"test": "
|
|
48
|
+
"test": "npm run test:unit && npm run test:types",
|
|
49
|
+
"test:types": "node --experimental-strip-types --import @compulim/test-harness/test-types.import --test **/*.test-types.ts",
|
|
50
|
+
"test:unit": "node --experimental-strip-types --experimental-test-coverage --experimental-test-isolation=none --import @compulim/test-harness/happy-dom.import --import @compulim/test-harness/jsx.import --test --test-force-exit **/*.test.{cjs,cts,js,jsx,mjs,mts,ts,tsx}"
|
|
57
51
|
},
|
|
58
52
|
"repository": {
|
|
59
53
|
"type": "git",
|
|
@@ -76,9 +70,9 @@
|
|
|
76
70
|
"@types/react": "^16",
|
|
77
71
|
"@types/react-dom": "^16",
|
|
78
72
|
"@types/react-test-renderer": "^16",
|
|
79
|
-
"react": "16.8.
|
|
80
|
-
"react-dom": "16.8.
|
|
81
|
-
"react-test-renderer": "16.8.
|
|
73
|
+
"react": "16.8.0",
|
|
74
|
+
"react-dom": "16.8.0",
|
|
75
|
+
"react-test-renderer": "16.8.0"
|
|
82
76
|
}
|
|
83
77
|
},
|
|
84
78
|
"switch:react-17": {
|
|
@@ -104,12 +98,6 @@
|
|
|
104
98
|
}
|
|
105
99
|
},
|
|
106
100
|
"pinDependencies": {
|
|
107
|
-
"@testduet/given-when-then": [
|
|
108
|
-
"main"
|
|
109
|
-
],
|
|
110
|
-
"@testduet/wait-for": [
|
|
111
|
-
"main"
|
|
112
|
-
],
|
|
113
101
|
"@types/react": [
|
|
114
102
|
"18"
|
|
115
103
|
],
|
|
@@ -132,42 +120,39 @@
|
|
|
132
120
|
"18"
|
|
133
121
|
]
|
|
134
122
|
},
|
|
123
|
+
"localPeerDependencies": {
|
|
124
|
+
"@compulim/test-harness": "0.0.0-0"
|
|
125
|
+
},
|
|
126
|
+
"peerDependencies": {
|
|
127
|
+
"react": ">=16.8.0"
|
|
128
|
+
},
|
|
135
129
|
"devDependencies": {
|
|
136
|
-
"@
|
|
137
|
-
"@
|
|
138
|
-
"@babel/preset-typescript": "^7.27.1",
|
|
139
|
-
"@fluentui/react": "^8.123.1",
|
|
140
|
-
"@testduet/given-when-then": "^0.1.0-main.334801c",
|
|
141
|
-
"@testduet/wait-for": "^0.1.1-main.3a4f261",
|
|
130
|
+
"@compulim/test-harness": "0.0.0-0",
|
|
131
|
+
"@testduet/given-when-then": "^0.1.0",
|
|
142
132
|
"@testing-library/dom": "^10.4.0",
|
|
143
133
|
"@testing-library/react": "^16.3.0",
|
|
144
134
|
"@tsconfig/recommended": "^1.0.10",
|
|
145
135
|
"@tsconfig/strictest": "^2.0.5",
|
|
146
|
-
"@types/jest": "^30.0.0",
|
|
147
136
|
"@types/node": "^24.0.15",
|
|
148
137
|
"@types/react": "^18.3.23",
|
|
149
138
|
"@types/react-dom": "^18.3.7",
|
|
150
139
|
"@types/react-test-renderer": "^18.3.1",
|
|
151
|
-
"esbuild": "^0.25.8",
|
|
152
140
|
"escape-string-regexp": "^4.0.0",
|
|
153
|
-
"
|
|
154
|
-
"jest-
|
|
141
|
+
"expect": "^30.2.0",
|
|
142
|
+
"jest-mock": "^30.2.0",
|
|
155
143
|
"prettier": "^3.6.2",
|
|
156
144
|
"publint": "^0.3.12",
|
|
157
145
|
"react": "^18.3.1",
|
|
158
146
|
"react-dom": "^18.3.1",
|
|
159
147
|
"react-test-renderer": "^18.3.1",
|
|
160
|
-
"react-wrap-with": "^0.
|
|
148
|
+
"react-wrap-with": "^0.2.0",
|
|
161
149
|
"tsup": "^8.5.0",
|
|
162
150
|
"type-fest": "^4.41.0",
|
|
163
151
|
"typescript": "^5.8.3"
|
|
164
152
|
},
|
|
165
|
-
"peerDependencies": {
|
|
166
|
-
"react": ">=16.8.6"
|
|
167
|
-
},
|
|
168
153
|
"dependencies": {
|
|
169
154
|
"handler-chain": "^0.1.0",
|
|
170
|
-
"react-chain-of-responsibility": "^0.4.3-main.
|
|
155
|
+
"react-chain-of-responsibility": "^0.4.3-main.202601010031.78b7d38",
|
|
171
156
|
"valibot": "^1.1.0"
|
|
172
157
|
}
|
|
173
158
|
}
|
package/dist/chunk-U4UF7NZV.mjs
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
// src/createChainOfResponsibility.tsx
|
|
2
|
-
import { applyMiddleware } from "handler-chain";
|
|
3
|
-
import React, {
|
|
4
|
-
createContext,
|
|
5
|
-
isValidElement,
|
|
6
|
-
memo,
|
|
7
|
-
useCallback,
|
|
8
|
-
useContext,
|
|
9
|
-
useMemo
|
|
10
|
-
} from "react";
|
|
11
|
-
|
|
12
|
-
// src/isReactComponent.ts
|
|
13
|
-
import { custom } from "valibot";
|
|
14
|
-
function isConsumer(component) {
|
|
15
|
-
return component?.$$typeof?.toString() === "Symbol(react.context)";
|
|
16
|
-
}
|
|
17
|
-
function isProvider(component) {
|
|
18
|
-
return component?.$$typeof?.toString() === "Symbol(react.provider)";
|
|
19
|
-
}
|
|
20
|
-
function isFragment(component) {
|
|
21
|
-
return component?.toString() === "Symbol(react.fragment)";
|
|
22
|
-
}
|
|
23
|
-
function isFunctionComponent(component) {
|
|
24
|
-
if (typeof component === "function") {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
return isPureFunctionComponent(component);
|
|
28
|
-
}
|
|
29
|
-
function isPureFunctionComponent(component) {
|
|
30
|
-
return component?.$$typeof?.toString() === "Symbol(react.memo)" && isFunctionComponent(component.type);
|
|
31
|
-
}
|
|
32
|
-
function isComponentClass(component) {
|
|
33
|
-
return typeof component === "object" && typeof component?.["render"] === "function";
|
|
34
|
-
}
|
|
35
|
-
function isReactComponent(component) {
|
|
36
|
-
return isFunctionComponent(component) || isComponentClass(component) || isFragment(component) || isConsumer(component) || isProvider(component);
|
|
37
|
-
}
|
|
38
|
-
var isReactComponent_default = isReactComponent;
|
|
39
|
-
|
|
40
|
-
// src/createChainOfResponsibility.tsx
|
|
41
|
-
function createChainOfResponsibility(options = {}) {
|
|
42
|
-
const defaultUseBuildComponentCallback = {
|
|
43
|
-
get enhancer() {
|
|
44
|
-
return void 0;
|
|
45
|
-
},
|
|
46
|
-
useBuildComponentCallback(_request, options2) {
|
|
47
|
-
if (!options2?.fallbackComponent) {
|
|
48
|
-
throw new Error("This component/hook cannot be used outside of its corresponding <Provider>");
|
|
49
|
-
}
|
|
50
|
-
return options2.fallbackComponent;
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const context = createContext(defaultUseBuildComponentCallback);
|
|
54
|
-
function ChainOfResponsibilityProvider({ children, init, middleware }) {
|
|
55
|
-
if (!Array.isArray(middleware) || middleware.some((middleware2) => typeof middleware2 !== "function")) {
|
|
56
|
-
throw new Error("middleware prop must be an array of functions");
|
|
57
|
-
}
|
|
58
|
-
const patchedMiddleware = Object.freeze(
|
|
59
|
-
middleware ? middleware.map((fn) => (init2) => {
|
|
60
|
-
const enhancer2 = fn(init2);
|
|
61
|
-
return (next) => (originalRequest) => {
|
|
62
|
-
let hasReturned;
|
|
63
|
-
const returnValue = enhancer2((nextRequest) => {
|
|
64
|
-
if (hasReturned) {
|
|
65
|
-
throw new Error("next() cannot be called after the function had returned synchronously");
|
|
66
|
-
}
|
|
67
|
-
!options.passModifiedRequest && nextRequest !== originalRequest && console.warn(
|
|
68
|
-
'react-chain-of-responsibility: "options.passModifiedRequest" must be set to true to pass a different request object to next().'
|
|
69
|
-
);
|
|
70
|
-
return next(options.passModifiedRequest ? nextRequest : originalRequest);
|
|
71
|
-
})(originalRequest);
|
|
72
|
-
hasReturned = true;
|
|
73
|
-
if (isValidElement(returnValue)) {
|
|
74
|
-
throw new Error("middleware must not return React element directly");
|
|
75
|
-
} else if (returnValue !== false && returnValue !== null && typeof returnValue !== "undefined" && !isReactComponent_default(returnValue)) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
"middleware must return false, null, undefined, function component, or class component"
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
return returnValue;
|
|
81
|
-
};
|
|
82
|
-
}) : []
|
|
83
|
-
);
|
|
84
|
-
const { enhancer: parentEnhancer } = useContext(context);
|
|
85
|
-
const enhancer = useMemo(
|
|
86
|
-
() => (
|
|
87
|
-
// We are reversing because it is easier to read:
|
|
88
|
-
// - With reverse, [a, b, c] will become a(b(c(fn)))
|
|
89
|
-
// - Without reverse, [a, b, c] will become c(b(a(fn)))
|
|
90
|
-
applyMiddleware(
|
|
91
|
-
...[...patchedMiddleware, ...parentEnhancer ? [() => parentEnhancer] : []]
|
|
92
|
-
)(init)
|
|
93
|
-
),
|
|
94
|
-
[init, middleware, parentEnhancer]
|
|
95
|
-
);
|
|
96
|
-
const useBuildComponentCallback2 = useCallback(
|
|
97
|
-
(request, options2 = {}) => enhancer(() => options2.fallbackComponent)(request) || void 0,
|
|
98
|
-
[enhancer]
|
|
99
|
-
);
|
|
100
|
-
const contextValue = useMemo(
|
|
101
|
-
() => ({ enhancer, useBuildComponentCallback: useBuildComponentCallback2 }),
|
|
102
|
-
[enhancer, useBuildComponentCallback2]
|
|
103
|
-
);
|
|
104
|
-
return /* @__PURE__ */ React.createElement(context.Provider, { value: contextValue }, children);
|
|
105
|
-
}
|
|
106
|
-
const useBuildComponentCallback = () => useContext(context).useBuildComponentCallback;
|
|
107
|
-
function Proxy({ fallbackComponent, request, ...props }) {
|
|
108
|
-
const enhancer = useBuildComponentCallback();
|
|
109
|
-
const Component = enhancer(request, { fallbackComponent });
|
|
110
|
-
return Component ? /* @__PURE__ */ React.createElement(Component, { ...props }) : null;
|
|
111
|
-
}
|
|
112
|
-
const asMiddleware = (MiddlewareComponent) => (init) => (next) => (request) => {
|
|
113
|
-
const RawNextComponent = next(request);
|
|
114
|
-
const MiddlewareOf = (props) => {
|
|
115
|
-
const middleware = useMemo(
|
|
116
|
-
() => Object.freeze({
|
|
117
|
-
init,
|
|
118
|
-
Next: memo(
|
|
119
|
-
RawNextComponent ? (overridingProps) => /* @__PURE__ */ React.createElement(RawNextComponent, { ...props, ...overridingProps }) : () => null
|
|
120
|
-
),
|
|
121
|
-
request
|
|
122
|
-
}),
|
|
123
|
-
[]
|
|
124
|
-
);
|
|
125
|
-
return /* @__PURE__ */ React.createElement(MiddlewareComponent, { ...props, middleware });
|
|
126
|
-
};
|
|
127
|
-
MiddlewareOf.displayName = `MiddlewareOf<${MiddlewareComponent.displayName || ""}>`;
|
|
128
|
-
return memo(MiddlewareOf);
|
|
129
|
-
};
|
|
130
|
-
return Object.freeze({
|
|
131
|
-
asMiddleware,
|
|
132
|
-
Provider: memo(ChainOfResponsibilityProvider),
|
|
133
|
-
Proxy: memo(Proxy),
|
|
134
|
-
types: Object.freeze({
|
|
135
|
-
middlewareComponentProps: void 0,
|
|
136
|
-
init: void 0,
|
|
137
|
-
middleware: void 0,
|
|
138
|
-
props: void 0,
|
|
139
|
-
proxyProps: void 0,
|
|
140
|
-
request: void 0
|
|
141
|
-
}),
|
|
142
|
-
useBuildComponentCallback
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
var createChainOfResponsibility_default = createChainOfResponsibility;
|
|
146
|
-
|
|
147
|
-
export {
|
|
148
|
-
createChainOfResponsibility_default
|
|
149
|
-
};
|
|
150
|
-
//# sourceMappingURL=chunk-U4UF7NZV.mjs.map
|