@fluentui-react-native/framework-base 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +31 -1
- package/CHANGELOG.md +18 -2
- package/README.md +10 -11
- package/lib/component-patterns/render.d.ts +8 -0
- package/lib/component-patterns/render.d.ts.map +1 -0
- package/lib/component-patterns/render.js +42 -0
- package/lib/component-patterns/render.js.map +1 -0
- package/lib/component-patterns/render.types.d.ts +98 -0
- package/lib/component-patterns/render.types.d.ts.map +1 -0
- package/lib/component-patterns/render.types.js +2 -0
- package/lib/component-patterns/render.types.js.map +1 -0
- package/lib/component-patterns/stagedComponent.d.ts +7 -31
- package/lib/component-patterns/stagedComponent.d.ts.map +1 -1
- package/lib/component-patterns/stagedComponent.js +18 -0
- package/lib/component-patterns/stagedComponent.js.map +1 -1
- package/lib/component-patterns/withSlots.d.ts +2 -2
- package/lib/component-patterns/withSlots.d.ts.map +1 -1
- package/lib/component-patterns/withSlots.js +2 -2
- package/lib/component-patterns/withSlots.js.map +1 -1
- package/lib/index.d.ts +4 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/jsx-runtime.d.ts +4 -0
- package/lib/jsx-runtime.d.ts.map +1 -0
- package/lib/jsx-runtime.js +9 -0
- package/lib/jsx-runtime.js.map +1 -0
- package/lib-commonjs/component-patterns/render.d.ts +8 -0
- package/lib-commonjs/component-patterns/render.d.ts.map +1 -0
- package/lib-commonjs/component-patterns/render.js +48 -0
- package/lib-commonjs/component-patterns/render.js.map +1 -0
- package/lib-commonjs/component-patterns/render.types.d.ts +98 -0
- package/lib-commonjs/component-patterns/render.types.d.ts.map +1 -0
- package/lib-commonjs/component-patterns/render.types.js +3 -0
- package/lib-commonjs/component-patterns/render.types.js.map +1 -0
- package/lib-commonjs/component-patterns/stagedComponent.d.ts +7 -31
- package/lib-commonjs/component-patterns/stagedComponent.d.ts.map +1 -1
- package/lib-commonjs/component-patterns/stagedComponent.js +20 -1
- package/lib-commonjs/component-patterns/stagedComponent.js.map +1 -1
- package/lib-commonjs/component-patterns/withSlots.d.ts +2 -2
- package/lib-commonjs/component-patterns/withSlots.d.ts.map +1 -1
- package/lib-commonjs/component-patterns/withSlots.js +2 -2
- package/lib-commonjs/component-patterns/withSlots.js.map +1 -1
- package/lib-commonjs/index.d.ts +4 -4
- package/lib-commonjs/index.d.ts.map +1 -1
- package/lib-commonjs/index.js +9 -3
- package/lib-commonjs/index.js.map +1 -1
- package/lib-commonjs/jsx-runtime.d.ts +4 -0
- package/lib-commonjs/jsx-runtime.d.ts.map +1 -0
- package/lib-commonjs/jsx-runtime.js +15 -0
- package/lib-commonjs/jsx-runtime.js.map +1 -0
- package/package.json +7 -2
- package/src/component-patterns/README.md +39 -0
- package/src/component-patterns/render.ts +54 -0
- package/src/component-patterns/render.types.ts +114 -0
- package/src/component-patterns/stagedComponent.tsx +45 -0
- package/src/component-patterns/withSlots.tsx +4 -8
- package/src/immutable-merge/README.md +185 -0
- package/src/index.ts +17 -4
- package/src/jsx-runtime.ts +11 -0
- package/src/memo-cache/README.md +141 -0
- package/src/merge-props/README.md +43 -0
- package/lib/component-patterns/renderSlot.d.ts +0 -21
- package/lib/component-patterns/renderSlot.d.ts.map +0 -1
- package/lib/component-patterns/renderSlot.js +0 -14
- package/lib/component-patterns/renderSlot.js.map +0 -1
- package/lib-commonjs/component-patterns/renderSlot.d.ts +0 -21
- package/lib-commonjs/component-patterns/renderSlot.d.ts.map +0 -1
- package/lib-commonjs/component-patterns/renderSlot.js +0 -19
- package/lib-commonjs/component-patterns/renderSlot.js.map +0 -1
- package/src/component-patterns/renderSlot.ts +0 -27
- package/src/component-patterns/stagedComponent.ts +0 -53
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type ReactJSX from 'react/jsx-runtime';
|
|
3
|
+
/**
|
|
4
|
+
* Base types for rendering components in a react application, extracted from react types
|
|
5
|
+
*/
|
|
6
|
+
export type RenderResult = ReturnType<typeof ReactJSX.jsx>;
|
|
7
|
+
export type RenderType = Parameters<typeof ReactJSX.jsx>[0] | string;
|
|
8
|
+
/**
|
|
9
|
+
* The standard element type inputs for react and react-native. This might be View or Button, or it might be 'div' in web. Effectively
|
|
10
|
+
* it is what react accepts for React.createElement
|
|
11
|
+
*/
|
|
12
|
+
export type NativeReactType = RenderType;
|
|
13
|
+
/**
|
|
14
|
+
* DIRECT RENDERING
|
|
15
|
+
*
|
|
16
|
+
* This is a pattern where a function can by called directly to render a component, bypassing creating additional layers of the
|
|
17
|
+
* rendering tree. This is useful for higher order components that mainly need to do simple prop manipulation but want to
|
|
18
|
+
* compartmentalize the logic.
|
|
19
|
+
*
|
|
20
|
+
* Note that for this to be safe, hooks cannot be used in the function. This is the reason why function component is redefined,
|
|
21
|
+
* to help linting tools catch bad usage.
|
|
22
|
+
*
|
|
23
|
+
* The newer DirectComponent type should be used, as it will handle children consistently.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* type of the render function, not a FunctionComponent to help prevent hook usage
|
|
27
|
+
*/
|
|
28
|
+
export type DirectComponentFunction<TProps> = (props: TProps) => RenderResult;
|
|
29
|
+
/**
|
|
30
|
+
* The full component definition that has the attached properties to allow the jsx handlers to render it directly.
|
|
31
|
+
*/
|
|
32
|
+
export type DirectComponent<TProps> = DirectComponentFunction<TProps> & {
|
|
33
|
+
displayName?: string;
|
|
34
|
+
_callDirect?: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Legacy slot function type, this allows the rendering handlers to bypass the normal JSX rendering and call the function
|
|
38
|
+
* directly. This expects the function to have children as the last argument of the call which isn't consistent with standard
|
|
39
|
+
* react usage, where children are passed as a prop. If writing new components use the DirectComponent type instead.
|
|
40
|
+
* @deprecated use DirectComponent instead
|
|
41
|
+
*/
|
|
42
|
+
export type LegacyDirectComponent<TProps> = React.FunctionComponent<TProps> & {
|
|
43
|
+
_canCompose?: boolean;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Legacy type name used for consistency with old rendering patterns.
|
|
47
|
+
*/
|
|
48
|
+
export type SlotFn<TProps> = LegacyDirectComponent<TProps>;
|
|
49
|
+
/**
|
|
50
|
+
* MULTI-STAGE RENDERING
|
|
51
|
+
*
|
|
52
|
+
* The above direct rendering pattern is useful for simple components, but it does not allow for hooks or complex logic. The staged render pattern allows
|
|
53
|
+
* for a component to be rendered in two stages, allowing for hooks to be used in the first stage and then the second stage to be a simple render function that can
|
|
54
|
+
* be called directly.
|
|
55
|
+
*
|
|
56
|
+
* In code that respects the pattern the first stage will be called with props (though children will not be present) and will return a function that will be called
|
|
57
|
+
* with additional props, this time with children present. This allows for the first stage to handle all the logic and hooks, while the second stage can be a simple render function
|
|
58
|
+
* that can leverage direct rendering if supported.
|
|
59
|
+
*
|
|
60
|
+
* The component itself will be a FunctionComponent, but it will have an attached property that is the staged render function. This allows the component to be used in two
|
|
61
|
+
* parts via the useSlot hook, or to be used directly in JSX/TSX as a normal component.
|
|
62
|
+
*/
|
|
63
|
+
/**
|
|
64
|
+
* This is an updated version of the staged render that handles children and types more consistently. Generally children
|
|
65
|
+
* will be passed as part of the props for component rendering, it is inconsistent to have them as a variable argument.
|
|
66
|
+
*
|
|
67
|
+
* The `children` prop will be automatically inferred and typed correctly by the prop type. Hooks are still expected
|
|
68
|
+
*/
|
|
69
|
+
export type TwoStageRender<TProps> = (props: TProps) => React.ComponentType<React.PropsWithChildren<TProps>>;
|
|
70
|
+
/**
|
|
71
|
+
* Component type for a component that can be rendered in two stages, with the attached render function.
|
|
72
|
+
*/
|
|
73
|
+
export type StagedComponent<TProps> = React.FunctionComponent<TProps> & {
|
|
74
|
+
_twoStageRender?: TwoStageRender<TProps>;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The final rendering of the props in a staged render. This is the function component signature that matches that of
|
|
78
|
+
* React.createElement, children (if present) will be part of the variable args at the end.
|
|
79
|
+
*/
|
|
80
|
+
export type FinalRender<TProps> = (props: TProps, ...children: React.ReactNode[]) => JSX.Element | null;
|
|
81
|
+
/**
|
|
82
|
+
* Signature for a staged render function.
|
|
83
|
+
* @deprecated Use TwoStageRender instead
|
|
84
|
+
*/
|
|
85
|
+
export type StagedRender<TProps> = (props: TProps, ...args: any[]) => FinalRender<TProps>;
|
|
86
|
+
/**
|
|
87
|
+
* Signature for a component that uses the staged render pattern.
|
|
88
|
+
* @deprecated Use TwoStageRender instead
|
|
89
|
+
*/
|
|
90
|
+
export type ComposableFunction<TProps> = React.FunctionComponent<TProps> & {
|
|
91
|
+
_staged?: StagedRender<TProps>;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* A type aggregating all the custom types that can be used in the render process.
|
|
95
|
+
* @internal only used in this package, should not be exported
|
|
96
|
+
*/
|
|
97
|
+
export type AnyCustomType<TProps> = React.FunctionComponent<TProps> | DirectComponent<TProps> | StagedComponent<TProps> | ComposableFunction<TProps> | LegacyDirectComponent<TProps>;
|
|
98
|
+
//# sourceMappingURL=render.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.types.d.ts","sourceRoot":"","sources":["../../src/component-patterns/render.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC3D,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AAErE;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC;AAEzC;;;;;;;;;;;GAWG;AAEH;;GAEG;AACH,MAAM,MAAM,uBAAuB,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,MAAM,IAAI,uBAAuB,CAAC,MAAM,CAAC,GAAG;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,CAAC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG;IAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,MAAM,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;AAE7G;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG;IACtE,eAAe,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CAC1C,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,WAAW,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;AAExG;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;AAE1F;;;GAGG;AACH,MAAM,MAAM,kBAAkB,CAAC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAE9G;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,MAAM,IAC5B,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAC/B,eAAe,CAAC,MAAM,CAAC,GACvB,eAAe,CAAC,MAAM,CAAC,GACvB,kBAAkB,CAAC,MAAM,CAAC,GAC1B,qBAAqB,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.types.js","sourceRoot":"","sources":["../../src/component-patterns/render.types.ts"],"names":[],"mappings":""}
|
|
@@ -1,34 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
/**
|
|
3
|
-
* The final rendering of the props in a staged render. This is the function component signature that matches that of
|
|
4
|
-
* React.createElement, children (if present) will be part of the variable args at the end.
|
|
5
|
-
*/
|
|
6
|
-
export type FinalRender<TProps> = (props: TProps, ...children: React.ReactNode[]) => JSX.Element | null;
|
|
7
|
-
/**
|
|
8
|
-
* This is a pattern of rendering where a functional component can be executed in two stages rather than in a single pass.
|
|
9
|
-
*
|
|
10
|
-
* The pattern looks like:
|
|
11
|
-
* (props) => {
|
|
12
|
-
* // handle props
|
|
13
|
-
* // call hooks, remember these can't be conditional
|
|
14
|
-
* // build styles and props to pass to child components
|
|
15
|
-
*
|
|
16
|
-
* return (additionalProps, ...children) => {
|
|
17
|
-
* // return the actual element tree, this includes conditional branching or rendering
|
|
18
|
-
* // mixin additional props, props which require logic should be required in phase 1.
|
|
19
|
-
*
|
|
20
|
-
* // NOTE: This is where children will show up
|
|
21
|
-
* };
|
|
22
|
-
* }
|
|
23
|
-
*/
|
|
24
|
-
export type StagedRender<TProps> = (props: TProps, ...args: any[]) => FinalRender<TProps>;
|
|
25
|
-
/**
|
|
26
|
-
* A composable function may have a two stage render function as an attached property. This allows the function to work
|
|
27
|
-
* in all the standard react flows, but allows for pulling out the staged render when components understand it.
|
|
28
|
-
*/
|
|
29
|
-
export type ComposableFunction<TProps> = React.FunctionComponent<TProps> & {
|
|
30
|
-
_staged?: StagedRender<TProps>;
|
|
31
|
-
};
|
|
1
|
+
import type { StagedComponent, TwoStageRender, StagedRender, ComposableFunction } from './render.types';
|
|
32
2
|
/**
|
|
33
3
|
* Take a staged render function and make a real component out of it
|
|
34
4
|
*
|
|
@@ -36,4 +6,10 @@ export type ComposableFunction<TProps> = React.FunctionComponent<TProps> & {
|
|
|
36
6
|
* @param memo - optional flag to enable wrapping the created component in a React.memo HOC
|
|
37
7
|
*/
|
|
38
8
|
export declare function stagedComponent<TProps>(staged: StagedRender<TProps>, memo?: boolean): ComposableFunction<TProps>;
|
|
9
|
+
/**
|
|
10
|
+
* Take a two stage render function and make a real component out of it, attaching the staged render function
|
|
11
|
+
* so it can be split if used in that manner.
|
|
12
|
+
* @param staged - two stage render function to wrap into a staged component
|
|
13
|
+
*/
|
|
14
|
+
export declare function twoStageComponent<TProps>(staged: TwoStageRender<TProps>): StagedComponent<TProps>;
|
|
39
15
|
//# sourceMappingURL=stagedComponent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stagedComponent.d.ts","sourceRoot":"","sources":["../../src/component-patterns/stagedComponent.
|
|
1
|
+
{"version":3,"file":"stagedComponent.d.ts","sourceRoot":"","sources":["../../src/component-patterns/stagedComponent.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAMxG;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAQhH;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,MAAM,CAAC,CAUjG"}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stagedComponent = void 0;
|
|
3
|
+
exports.twoStageComponent = exports.stagedComponent = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
/**
|
|
6
|
+
* @jsxRuntime classic
|
|
7
|
+
* @jsx withSlots
|
|
8
|
+
*/
|
|
5
9
|
const React = tslib_1.__importStar(require("react"));
|
|
10
|
+
const withSlots_1 = require("./withSlots");
|
|
6
11
|
function asArray(val) {
|
|
7
12
|
return Array.isArray(val) ? val : [val];
|
|
8
13
|
}
|
|
@@ -22,4 +27,18 @@ function stagedComponent(staged, memo) {
|
|
|
22
27
|
return stagedComponent;
|
|
23
28
|
}
|
|
24
29
|
exports.stagedComponent = stagedComponent;
|
|
30
|
+
/**
|
|
31
|
+
* Take a two stage render function and make a real component out of it, attaching the staged render function
|
|
32
|
+
* so it can be split if used in that manner.
|
|
33
|
+
* @param staged - two stage render function to wrap into a staged component
|
|
34
|
+
*/
|
|
35
|
+
function twoStageComponent(staged) {
|
|
36
|
+
return Object.assign((props) => {
|
|
37
|
+
const { children, ...outerProps } = props;
|
|
38
|
+
const innerProps = { children };
|
|
39
|
+
const Inner = staged(outerProps);
|
|
40
|
+
return (0, withSlots_1.withSlots)(Inner, { ...innerProps });
|
|
41
|
+
}, { _twoStageRender: staged });
|
|
42
|
+
}
|
|
43
|
+
exports.twoStageComponent = twoStageComponent;
|
|
25
44
|
//# sourceMappingURL=stagedComponent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stagedComponent.js","sourceRoot":"","sources":["../../src/component-patterns/stagedComponent.
|
|
1
|
+
{"version":3,"file":"stagedComponent.js","sourceRoot":"","sources":["../../src/component-patterns/stagedComponent.tsx"],"names":[],"mappings":";;;;AAAA;;;GAGG;AACH,qDAA+B;AAC/B,2CAAwC;AAIxC,SAAS,OAAO,CAAI,GAAY;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAAS,MAA4B,EAAE,IAAc;IAClF,MAAM,SAAS,GAAG,CAAC,KAAsC,EAAE,EAAE;QAC3D,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;QACpC,OAAO,MAAM,CAAC,IAAc,CAAC,CAAC,EAAqC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1F,CAAC,CAAC;IACF,MAAM,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACpD,OAAO,eAA6C,CAAC;AACvD,CAAC;AARD,0CAQC;AAED;;;;GAIG;AACH,SAAgB,iBAAiB,CAAS,MAA8B;IACtE,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,KAAsC,EAAE,EAAE;QACzC,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,GAAG,KAAK,CAAC;QAC1C,MAAM,UAAU,GAAG,EAAE,QAAQ,EAAqC,CAAC;QACnE,MAAM,KAAK,GAAG,MAAM,CAAC,UAAoB,CAAC,CAAC;QAC3C,OAAO,2BAAC,KAAK,OAAK,UAAU,GAAI,CAAC;IACnC,CAAC,EACD,EAAE,eAAe,EAAE,MAAM,EAAE,CAC5B,CAAC;AACJ,CAAC;AAVD,8CAUC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type React from 'react';
|
|
2
2
|
/**
|
|
3
3
|
* This function is required for any module that uses slots.
|
|
4
4
|
*
|
|
@@ -11,5 +11,5 @@ import type { NativeReactType } from './renderSlot';
|
|
|
11
11
|
*
|
|
12
12
|
* See React.createElement
|
|
13
13
|
*/
|
|
14
|
-
export declare function withSlots
|
|
14
|
+
export declare function withSlots(reactType: Parameters<typeof React.createElement>[0], props?: unknown, ...children: React.ReactNode[]): React.ReactElement<any, string | React.JSXElementConstructor<any>>;
|
|
15
15
|
//# sourceMappingURL=withSlots.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withSlots.d.ts","sourceRoot":"","sources":["../../src/component-patterns/withSlots.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"withSlots.d.ts","sourceRoot":"","sources":["../../src/component-patterns/withSlots.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B;;;;;;;;;;;GAWG;AAGH,wBAAgB,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,sEAG9H"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.withSlots = void 0;
|
|
4
|
-
const
|
|
4
|
+
const render_1 = require("./render");
|
|
5
5
|
/**
|
|
6
6
|
* This function is required for any module that uses slots.
|
|
7
7
|
*
|
|
@@ -17,7 +17,7 @@ const renderSlot_1 = require("./renderSlot");
|
|
|
17
17
|
// Can't use typeof on React.createElement since it's overloaded. Approximate createElement's signature for now and widen as needed.
|
|
18
18
|
function withSlots(reactType, props, ...children) {
|
|
19
19
|
// if it is a non-string type with _canCompose set just call the function directly, otherwise call createElement as normal
|
|
20
|
-
return (0,
|
|
20
|
+
return (0, render_1.renderForClassicRuntime)(reactType, props, ...children);
|
|
21
21
|
}
|
|
22
22
|
exports.withSlots = withSlots;
|
|
23
23
|
//# sourceMappingURL=withSlots.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withSlots.js","sourceRoot":"","sources":["../../src/component-patterns/withSlots.tsx"],"names":[],"mappings":";;;AACA,
|
|
1
|
+
{"version":3,"file":"withSlots.js","sourceRoot":"","sources":["../../src/component-patterns/withSlots.tsx"],"names":[],"mappings":";;;AACA,qCAAmD;AAEnD;;;;;;;;;;;GAWG;AAEH,oIAAoI;AACpI,SAAgB,SAAS,CAAC,SAAoD,EAAE,KAAe,EAAE,GAAG,QAA2B;IAC7H,0HAA0H;IAC1H,OAAO,IAAA,gCAAuB,EAAC,SAAS,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC;AAChE,CAAC;AAHD,8BAGC"}
|
package/lib-commonjs/index.d.ts
CHANGED
|
@@ -6,9 +6,9 @@ export { memoize } from './memo-cache/memoize';
|
|
|
6
6
|
export type { StyleProp } from './merge-props/mergeStyles.types';
|
|
7
7
|
export { mergeStyles } from './merge-props/mergeStyles';
|
|
8
8
|
export { mergeProps } from './merge-props/mergeProps';
|
|
9
|
-
export { renderSlot } from './component-patterns/
|
|
10
|
-
export type { SlotFn, NativeReactType } from './component-patterns/
|
|
9
|
+
export { renderForClassicRuntime, renderForJsxRuntime, renderSlot } from './component-patterns/render';
|
|
10
|
+
export type { DirectComponent, DirectComponentFunction, LegacyDirectComponent, StagedComponent, StagedRender, TwoStageRender, RenderType, RenderResult, ComposableFunction, FinalRender, SlotFn, NativeReactType, } from './component-patterns/render.types';
|
|
11
11
|
export { withSlots } from './component-patterns/withSlots';
|
|
12
|
-
export { stagedComponent } from './component-patterns/stagedComponent';
|
|
13
|
-
export
|
|
12
|
+
export { stagedComponent, twoStageComponent } from './component-patterns/stagedComponent';
|
|
13
|
+
export { jsx, jsxs } from './jsx-runtime';
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAChH,YAAY,EACV,wBAAwB,EACxB,sBAAsB,EACtB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAG/C,YAAY,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAChH,YAAY,EACV,wBAAwB,EACxB,sBAAsB,EACtB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAG/C,YAAY,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACvG,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,MAAM,EACN,eAAe,GAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC"}
|
package/lib-commonjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stagedComponent = exports.withSlots = exports.renderSlot = exports.mergeProps = exports.mergeStyles = exports.memoize = exports.getTypedMemoCache = exports.getMemoCache = exports.filterToObjects = exports.processImmutable = exports.immutableMergeCore = exports.immutableMerge = void 0;
|
|
3
|
+
exports.jsxs = exports.jsx = exports.twoStageComponent = exports.stagedComponent = exports.withSlots = exports.renderSlot = exports.renderForJsxRuntime = exports.renderForClassicRuntime = exports.mergeProps = exports.mergeStyles = exports.memoize = exports.getTypedMemoCache = exports.getMemoCache = exports.filterToObjects = exports.processImmutable = exports.immutableMergeCore = exports.immutableMerge = void 0;
|
|
4
4
|
// immutable-merge exports
|
|
5
5
|
var Merge_1 = require("./immutable-merge/Merge");
|
|
6
6
|
Object.defineProperty(exports, "immutableMerge", { enumerable: true, get: function () { return Merge_1.immutableMerge; } });
|
|
@@ -17,10 +17,16 @@ Object.defineProperty(exports, "mergeStyles", { enumerable: true, get: function
|
|
|
17
17
|
var mergeProps_1 = require("./merge-props/mergeProps");
|
|
18
18
|
Object.defineProperty(exports, "mergeProps", { enumerable: true, get: function () { return mergeProps_1.mergeProps; } });
|
|
19
19
|
// component pattern exports
|
|
20
|
-
var
|
|
21
|
-
Object.defineProperty(exports, "
|
|
20
|
+
var render_1 = require("./component-patterns/render");
|
|
21
|
+
Object.defineProperty(exports, "renderForClassicRuntime", { enumerable: true, get: function () { return render_1.renderForClassicRuntime; } });
|
|
22
|
+
Object.defineProperty(exports, "renderForJsxRuntime", { enumerable: true, get: function () { return render_1.renderForJsxRuntime; } });
|
|
23
|
+
Object.defineProperty(exports, "renderSlot", { enumerable: true, get: function () { return render_1.renderSlot; } });
|
|
22
24
|
var withSlots_1 = require("./component-patterns/withSlots");
|
|
23
25
|
Object.defineProperty(exports, "withSlots", { enumerable: true, get: function () { return withSlots_1.withSlots; } });
|
|
24
26
|
var stagedComponent_1 = require("./component-patterns/stagedComponent");
|
|
25
27
|
Object.defineProperty(exports, "stagedComponent", { enumerable: true, get: function () { return stagedComponent_1.stagedComponent; } });
|
|
28
|
+
Object.defineProperty(exports, "twoStageComponent", { enumerable: true, get: function () { return stagedComponent_1.twoStageComponent; } });
|
|
29
|
+
var jsx_runtime_1 = require("./jsx-runtime");
|
|
30
|
+
Object.defineProperty(exports, "jsx", { enumerable: true, get: function () { return jsx_runtime_1.jsx; } });
|
|
31
|
+
Object.defineProperty(exports, "jsxs", { enumerable: true, get: function () { return jsx_runtime_1.jsxs; } });
|
|
26
32
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0BAA0B;AAC1B,iDAAgH;AAAvG,uGAAA,cAAc,OAAA;AAAE,2GAAA,kBAAkB,OAAA;AAAE,yGAAA,gBAAgB,OAAA;AAAE,wGAAA,eAAe,OAAA;AAY9E,0DAA4E;AAAnE,4GAAA,YAAY,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AACxC,gDAA+C;AAAtC,kGAAA,OAAO,OAAA;AAIhB,yDAAwD;AAA/C,0GAAA,WAAW,OAAA;AACpB,uDAAsD;AAA7C,wGAAA,UAAU,OAAA;AAEnB,4BAA4B;AAC5B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0BAA0B;AAC1B,iDAAgH;AAAvG,uGAAA,cAAc,OAAA;AAAE,2GAAA,kBAAkB,OAAA;AAAE,yGAAA,gBAAgB,OAAA;AAAE,wGAAA,eAAe,OAAA;AAY9E,0DAA4E;AAAnE,4GAAA,YAAY,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AACxC,gDAA+C;AAAtC,kGAAA,OAAO,OAAA;AAIhB,yDAAwD;AAA/C,0GAAA,WAAW,OAAA;AACpB,uDAAsD;AAA7C,wGAAA,UAAU,OAAA;AAEnB,4BAA4B;AAC5B,sDAAuG;AAA9F,iHAAA,uBAAuB,OAAA;AAAE,6GAAA,mBAAmB,OAAA;AAAE,oGAAA,UAAU,OAAA;AAejE,4DAA2D;AAAlD,sGAAA,SAAS,OAAA;AAClB,wEAA0F;AAAjF,kHAAA,eAAe,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC3C,6CAA0C;AAAjC,kGAAA,GAAG,OAAA;AAAE,mGAAA,IAAI,OAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
export declare function jsx(type: React.ElementType, props: React.PropsWithChildren<unknown>, key?: React.Key): React.ReactElement;
|
|
3
|
+
export declare function jsxs(type: React.ElementType, props: React.PropsWithChildren<unknown>, key?: React.Key): React.ReactElement;
|
|
4
|
+
//# sourceMappingURL=jsx-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.d.ts","sourceRoot":"","sources":["../src/jsx-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,wBAAgB,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,YAAY,CAEzH;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,YAAY,CAE1H"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsxs = exports.jsx = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const ReactJSX = tslib_1.__importStar(require("react/jsx-runtime"));
|
|
6
|
+
const render_1 = require("./component-patterns/render");
|
|
7
|
+
function jsx(type, props, key) {
|
|
8
|
+
return (0, render_1.renderForJsxRuntime)(type, props, key, ReactJSX.jsx);
|
|
9
|
+
}
|
|
10
|
+
exports.jsx = jsx;
|
|
11
|
+
function jsxs(type, props, key) {
|
|
12
|
+
return (0, render_1.renderForJsxRuntime)(type, props, key, ReactJSX.jsxs);
|
|
13
|
+
}
|
|
14
|
+
exports.jsxs = jsxs;
|
|
15
|
+
//# sourceMappingURL=jsx-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.js","sourceRoot":"","sources":["../src/jsx-runtime.ts"],"names":[],"mappings":";;;;AACA,oEAA8C;AAC9C,wDAAkE;AAElE,SAAgB,GAAG,CAAC,IAAuB,EAAE,KAAuC,EAAE,GAAe;IACnG,OAAO,IAAA,4BAAmB,EAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC7D,CAAC;AAFD,kBAEC;AAED,SAAgB,IAAI,CAAC,IAAuB,EAAE,KAAuC,EAAE,GAAe;IACpG,OAAO,IAAA,4BAAmB,EAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC9D,CAAC;AAFD,oBAEC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluentui-react-native/framework-base",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Base types and utilities fluentui-react-native frameworks",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"import": "./lib/index.js",
|
|
17
17
|
"require": "./lib-commonjs/index.js",
|
|
18
18
|
"types": "./lib/index.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./jsx-runtime": {
|
|
21
|
+
"import": "./lib/jsx-runtime.js",
|
|
22
|
+
"require": "./lib-commonjs/jsx-runtime.js",
|
|
23
|
+
"types": "./lib/jsx-runtime.d.ts"
|
|
19
24
|
}
|
|
20
25
|
},
|
|
21
26
|
"scripts": {
|
|
@@ -38,6 +43,6 @@
|
|
|
38
43
|
"@fluentui-react-native/eslint-config-rules": "0.1.1",
|
|
39
44
|
"@fluentui-react-native/scripts": "0.1.1",
|
|
40
45
|
"@types/jest": "^29.0.0",
|
|
41
|
-
"@types/node": "^
|
|
46
|
+
"@types/node": "^22.0.0"
|
|
42
47
|
}
|
|
43
48
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# `fluentui-react-native` - Common component patterns
|
|
2
|
+
|
|
3
|
+
These are the base component patterns shared across the deprecated or v0 framework (found under packages/deprecated), and the newer framework (found under packages/framework). This also includes the custom JSX handlers required to render them properly.
|
|
4
|
+
|
|
5
|
+
There are two main patterns exposed here: direct rendering and staged rendering.
|
|
6
|
+
|
|
7
|
+
## Direct Rendering
|
|
8
|
+
|
|
9
|
+
The direct rendering pattern allows a component to be called directly, rather than creating a new entry in the DOM.
|
|
10
|
+
|
|
11
|
+
As an example, if you want to create a wrapper around a component called `MyText` that has `italicize` as one of its props, that always wants to set that value to true. You could define:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
const MyNewText: React.FunctionComponent<MyTextProps> = (props) => {
|
|
15
|
+
return <MyText {...props, italicize: true} />;
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
When this is rendered, there is an entry for `MyNewText` which contains a `MyText` (another entry), which might contains `Text` (for react-native usage). The direct rendering pattern is one where a component can denote that it is safe to be called directly as a function, instead operating as a prop transform that gets applied to the underlying component.
|
|
20
|
+
|
|
21
|
+
- For the above to be safe, `MyNewText` should NOT use hooks. In the case of any conditional rendering logic this will break the rule of hooks.
|
|
22
|
+
|
|
23
|
+
There are two types of implementations in this folder:
|
|
24
|
+
|
|
25
|
+
- `DirectComponent` - a functional component that marks itself as direct with a `_callDirect: true` attached property. This will then be called as a normal function component, with children included as part of props.
|
|
26
|
+
- `LegacyDirectComponent` - the pattern currently used in this library that should be moved away from. In this case `_canCompose: true` is set as an attached property, and the function component will be called with children split from props.
|
|
27
|
+
|
|
28
|
+
The internal logic of the JSX rendering helpers will handle both patterns. In the case of the newer `DirectComponent` pattern, the component will still work, even without any jsx hooks, whereas the `LegacyDirectComponent` pattern will have a somewhat undefined behavior with regards to children.
|
|
29
|
+
|
|
30
|
+
## Staged Rendering
|
|
31
|
+
|
|
32
|
+
The issue with the direct component pattern above, is that hooks are integral to writing functional components. The staged rendering pattern is designed to help with this. In this case a component is implemented in two stages, the prep stage where hooks are called, and the rendering stage where the tree is emitted.
|
|
33
|
+
|
|
34
|
+
As above there is a newer and older version of the pattern.
|
|
35
|
+
|
|
36
|
+
- `StagedComponent` - the newer version of the pattern, where the returned component function expects children as part of props.
|
|
37
|
+
- `StagedRender` - the older version, where children are split out and JSX hooks are required to render correctly.
|
|
38
|
+
|
|
39
|
+
Note that while the newer patterns work without any JSX hooks, the hooks will enable the element flattening.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as ReactJSX from 'react/jsx-runtime';
|
|
3
|
+
import type { RenderType, RenderResult, DirectComponent, LegacyDirectComponent } from './render.types';
|
|
4
|
+
|
|
5
|
+
export type CustomRender = () => RenderResult;
|
|
6
|
+
|
|
7
|
+
function asDirectComponent<TProps>(type: RenderType): DirectComponent<TProps> | undefined {
|
|
8
|
+
if (typeof type === 'function' && (type as DirectComponent<TProps>)._callDirect) {
|
|
9
|
+
return type as DirectComponent<TProps>;
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function asLegacyDirectComponent<TProps>(type: RenderType): LegacyDirectComponent<TProps> | undefined {
|
|
15
|
+
if (typeof type === 'function' && (type as LegacyDirectComponent<TProps>)._canCompose) {
|
|
16
|
+
return type as LegacyDirectComponent<TProps>;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function renderForJsxRuntime<TProps>(
|
|
22
|
+
type: React.ElementType,
|
|
23
|
+
props: React.PropsWithChildren<TProps>,
|
|
24
|
+
key?: React.Key,
|
|
25
|
+
jsxFn: typeof ReactJSX.jsx = ReactJSX.jsx,
|
|
26
|
+
): RenderResult {
|
|
27
|
+
const legacyDirect = asLegacyDirectComponent(type);
|
|
28
|
+
if (legacyDirect) {
|
|
29
|
+
const { children, ...rest } = props;
|
|
30
|
+
const newProps = { ...rest, key };
|
|
31
|
+
return legacyDirect(newProps, ...React.Children.toArray(children)) as RenderResult;
|
|
32
|
+
}
|
|
33
|
+
const directComponent = asDirectComponent<TProps>(type);
|
|
34
|
+
if (directComponent) {
|
|
35
|
+
const newProps = { ...props, key };
|
|
36
|
+
return directComponent(newProps);
|
|
37
|
+
}
|
|
38
|
+
return jsxFn(type, props, key);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function renderForClassicRuntime<TProps>(type: RenderType, props: TProps, ...children: React.ReactNode[]): RenderResult {
|
|
42
|
+
const legacyDirect = asLegacyDirectComponent(type);
|
|
43
|
+
if (legacyDirect) {
|
|
44
|
+
return legacyDirect(props, ...children) as RenderResult;
|
|
45
|
+
}
|
|
46
|
+
const directComponent = asDirectComponent(type);
|
|
47
|
+
if (directComponent) {
|
|
48
|
+
const newProps = { ...props, children };
|
|
49
|
+
return directComponent(newProps);
|
|
50
|
+
}
|
|
51
|
+
return React.createElement(type, props, ...children);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const renderSlot = renderForClassicRuntime;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type ReactJSX from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base types for rendering components in a react application, extracted from react types
|
|
6
|
+
*/
|
|
7
|
+
export type RenderResult = ReturnType<typeof ReactJSX.jsx>;
|
|
8
|
+
export type RenderType = Parameters<typeof ReactJSX.jsx>[0] | string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The standard element type inputs for react and react-native. This might be View or Button, or it might be 'div' in web. Effectively
|
|
12
|
+
* it is what react accepts for React.createElement
|
|
13
|
+
*/
|
|
14
|
+
export type NativeReactType = RenderType;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* DIRECT RENDERING
|
|
18
|
+
*
|
|
19
|
+
* This is a pattern where a function can by called directly to render a component, bypassing creating additional layers of the
|
|
20
|
+
* rendering tree. This is useful for higher order components that mainly need to do simple prop manipulation but want to
|
|
21
|
+
* compartmentalize the logic.
|
|
22
|
+
*
|
|
23
|
+
* Note that for this to be safe, hooks cannot be used in the function. This is the reason why function component is redefined,
|
|
24
|
+
* to help linting tools catch bad usage.
|
|
25
|
+
*
|
|
26
|
+
* The newer DirectComponent type should be used, as it will handle children consistently.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* type of the render function, not a FunctionComponent to help prevent hook usage
|
|
31
|
+
*/
|
|
32
|
+
export type DirectComponentFunction<TProps> = (props: TProps) => RenderResult;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The full component definition that has the attached properties to allow the jsx handlers to render it directly.
|
|
36
|
+
*/
|
|
37
|
+
export type DirectComponent<TProps> = DirectComponentFunction<TProps> & {
|
|
38
|
+
displayName?: string;
|
|
39
|
+
_callDirect?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Legacy slot function type, this allows the rendering handlers to bypass the normal JSX rendering and call the function
|
|
44
|
+
* directly. This expects the function to have children as the last argument of the call which isn't consistent with standard
|
|
45
|
+
* react usage, where children are passed as a prop. If writing new components use the DirectComponent type instead.
|
|
46
|
+
* @deprecated use DirectComponent instead
|
|
47
|
+
*/
|
|
48
|
+
export type LegacyDirectComponent<TProps> = React.FunctionComponent<TProps> & {
|
|
49
|
+
_canCompose?: boolean;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Legacy type name used for consistency with old rendering patterns.
|
|
54
|
+
*/
|
|
55
|
+
export type SlotFn<TProps> = LegacyDirectComponent<TProps>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* MULTI-STAGE RENDERING
|
|
59
|
+
*
|
|
60
|
+
* The above direct rendering pattern is useful for simple components, but it does not allow for hooks or complex logic. The staged render pattern allows
|
|
61
|
+
* for a component to be rendered in two stages, allowing for hooks to be used in the first stage and then the second stage to be a simple render function that can
|
|
62
|
+
* be called directly.
|
|
63
|
+
*
|
|
64
|
+
* In code that respects the pattern the first stage will be called with props (though children will not be present) and will return a function that will be called
|
|
65
|
+
* with additional props, this time with children present. This allows for the first stage to handle all the logic and hooks, while the second stage can be a simple render function
|
|
66
|
+
* that can leverage direct rendering if supported.
|
|
67
|
+
*
|
|
68
|
+
* The component itself will be a FunctionComponent, but it will have an attached property that is the staged render function. This allows the component to be used in two
|
|
69
|
+
* parts via the useSlot hook, or to be used directly in JSX/TSX as a normal component.
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* This is an updated version of the staged render that handles children and types more consistently. Generally children
|
|
74
|
+
* will be passed as part of the props for component rendering, it is inconsistent to have them as a variable argument.
|
|
75
|
+
*
|
|
76
|
+
* The `children` prop will be automatically inferred and typed correctly by the prop type. Hooks are still expected
|
|
77
|
+
*/
|
|
78
|
+
export type TwoStageRender<TProps> = (props: TProps) => React.ComponentType<React.PropsWithChildren<TProps>>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Component type for a component that can be rendered in two stages, with the attached render function.
|
|
82
|
+
*/
|
|
83
|
+
export type StagedComponent<TProps> = React.FunctionComponent<TProps> & {
|
|
84
|
+
_twoStageRender?: TwoStageRender<TProps>;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The final rendering of the props in a staged render. This is the function component signature that matches that of
|
|
89
|
+
* React.createElement, children (if present) will be part of the variable args at the end.
|
|
90
|
+
*/
|
|
91
|
+
export type FinalRender<TProps> = (props: TProps, ...children: React.ReactNode[]) => JSX.Element | null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Signature for a staged render function.
|
|
95
|
+
* @deprecated Use TwoStageRender instead
|
|
96
|
+
*/
|
|
97
|
+
export type StagedRender<TProps> = (props: TProps, ...args: any[]) => FinalRender<TProps>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Signature for a component that uses the staged render pattern.
|
|
101
|
+
* @deprecated Use TwoStageRender instead
|
|
102
|
+
*/
|
|
103
|
+
export type ComposableFunction<TProps> = React.FunctionComponent<TProps> & { _staged?: StagedRender<TProps> };
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* A type aggregating all the custom types that can be used in the render process.
|
|
107
|
+
* @internal only used in this package, should not be exported
|
|
108
|
+
*/
|
|
109
|
+
export type AnyCustomType<TProps> =
|
|
110
|
+
| React.FunctionComponent<TProps>
|
|
111
|
+
| DirectComponent<TProps>
|
|
112
|
+
| StagedComponent<TProps>
|
|
113
|
+
| ComposableFunction<TProps>
|
|
114
|
+
| LegacyDirectComponent<TProps>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jsxRuntime classic
|
|
3
|
+
* @jsx withSlots
|
|
4
|
+
*/
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { withSlots } from './withSlots';
|
|
7
|
+
|
|
8
|
+
import type { StagedComponent, TwoStageRender, StagedRender, ComposableFunction } from './render.types';
|
|
9
|
+
|
|
10
|
+
function asArray<T>(val: T | T[]): T[] {
|
|
11
|
+
return Array.isArray(val) ? val : [val];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Take a staged render function and make a real component out of it
|
|
16
|
+
*
|
|
17
|
+
* @param staged - staged render function to wrap into a staged component
|
|
18
|
+
* @param memo - optional flag to enable wrapping the created component in a React.memo HOC
|
|
19
|
+
*/
|
|
20
|
+
export function stagedComponent<TProps>(staged: StagedRender<TProps>, memo?: boolean): ComposableFunction<TProps> {
|
|
21
|
+
const component = (props: React.PropsWithChildren<TProps>) => {
|
|
22
|
+
const { children, ...rest } = props;
|
|
23
|
+
return staged(rest as TProps)({} as React.PropsWithChildren<TProps>, asArray(children));
|
|
24
|
+
};
|
|
25
|
+
const stagedComponent = memo ? React.memo(component) : component;
|
|
26
|
+
Object.assign(stagedComponent, { _staged: staged });
|
|
27
|
+
return stagedComponent as ComposableFunction<TProps>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Take a two stage render function and make a real component out of it, attaching the staged render function
|
|
32
|
+
* so it can be split if used in that manner.
|
|
33
|
+
* @param staged - two stage render function to wrap into a staged component
|
|
34
|
+
*/
|
|
35
|
+
export function twoStageComponent<TProps>(staged: TwoStageRender<TProps>): StagedComponent<TProps> {
|
|
36
|
+
return Object.assign(
|
|
37
|
+
(props: React.PropsWithChildren<TProps>) => {
|
|
38
|
+
const { children, ...outerProps } = props;
|
|
39
|
+
const innerProps = { children } as React.PropsWithChildren<TProps>;
|
|
40
|
+
const Inner = staged(outerProps as TProps);
|
|
41
|
+
return <Inner {...innerProps} />;
|
|
42
|
+
},
|
|
43
|
+
{ _twoStageRender: staged },
|
|
44
|
+
);
|
|
45
|
+
}
|