@fluentui-react-native/framework-base 0.2.1 → 0.3.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 +1 -1
- package/CHANGELOG.md +35 -2
- package/README.md +18 -1
- package/babel.config.js +1 -1
- package/jsx-runtime.js +1 -0
- package/lib/component-patterns/directComponent.d.ts +7 -0
- package/lib/component-patterns/directComponent.d.ts.map +1 -0
- package/lib/component-patterns/directComponent.js +8 -0
- package/lib/component-patterns/directComponent.js.map +1 -0
- package/lib/component-patterns/extract.d.ts +22 -0
- package/lib/component-patterns/extract.d.ts.map +1 -0
- package/lib/component-patterns/extract.js +25 -0
- package/lib/component-patterns/extract.js.map +1 -0
- package/lib/component-patterns/phasedComponent.d.ts +18 -0
- package/lib/component-patterns/phasedComponent.d.ts.map +1 -0
- package/lib/component-patterns/phasedComponent.js +51 -0
- package/lib/component-patterns/phasedComponent.js.map +1 -0
- package/lib/component-patterns/render.d.ts +9 -3
- package/lib/component-patterns/render.d.ts.map +1 -1
- package/lib/component-patterns/render.js +39 -32
- package/lib/component-patterns/render.js.map +1 -1
- package/lib/component-patterns/render.types.d.ts +60 -34
- package/lib/component-patterns/render.types.d.ts.map +1 -1
- package/lib/component-patterns/render.types.js +1 -1
- package/lib/component-patterns/stagedComponent.d.ts +3 -8
- package/lib/component-patterns/stagedComponent.d.ts.map +1 -1
- package/lib/component-patterns/stagedComponent.js +10 -27
- package/lib/component-patterns/stagedComponent.js.map +1 -1
- package/lib/component-patterns/withSlots.d.ts +6 -2
- package/lib/component-patterns/withSlots.d.ts.map +1 -1
- package/lib/component-patterns/withSlots.js +3 -3
- package/lib/component-patterns/withSlots.js.map +1 -1
- package/lib/immutable-merge/Merge.d.ts +6 -3
- package/lib/immutable-merge/Merge.js +79 -83
- package/lib/immutable-merge/Merge.js.map +1 -1
- package/lib/immutable-merge/Merge.test.d.ts +1 -1
- package/lib/immutable-merge/Merge.test.js +231 -219
- package/lib/immutable-merge/Merge.test.js.map +1 -1
- package/lib/index.d.ts +33 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +13 -4
- package/lib/index.js.map +1 -1
- package/lib/jsx-namespace.d.ts +65 -0
- package/lib/jsx-namespace.d.ts.map +1 -0
- package/lib/jsx-namespace.js +2 -0
- package/lib/jsx-namespace.js.map +1 -0
- package/lib/jsx-runtime.d.ts +6 -4
- package/lib/jsx-runtime.d.ts.map +1 -1
- package/lib/jsx-runtime.js +9 -7
- package/lib/jsx-runtime.js.map +1 -1
- package/lib/memo-cache/getCacheEntry.d.ts +13 -13
- package/lib/memo-cache/getCacheEntry.js +20 -22
- package/lib/memo-cache/getCacheEntry.js.map +1 -1
- package/lib/memo-cache/getCacheEntry.test.d.ts +1 -1
- package/lib/memo-cache/getCacheEntry.test.js +90 -90
- package/lib/memo-cache/getCacheEntry.test.js.map +1 -1
- package/lib/memo-cache/getMemoCache.d.ts +1 -1
- package/lib/memo-cache/getMemoCache.js +11 -11
- package/lib/memo-cache/getMemoCache.js.map +1 -1
- package/lib/memo-cache/getMemoCache.test.d.ts +1 -1
- package/lib/memo-cache/getMemoCache.test.js +73 -73
- package/lib/memo-cache/getMemoCache.test.js.map +1 -1
- package/lib/memo-cache/memoize.d.ts +1 -1
- package/lib/memo-cache/memoize.js +9 -9
- package/lib/memo-cache/memoize.js.map +1 -1
- package/lib/memo-cache/memoize.test.d.ts +1 -1
- package/lib/memo-cache/memoize.test.js +36 -38
- package/lib/memo-cache/memoize.test.js.map +1 -1
- package/lib/merge-props/index.d.ts +1 -1
- package/lib/merge-props/index.js +1 -1
- package/lib/merge-props/mergeProps.d.ts +1 -1
- package/lib/merge-props/mergeProps.js +4 -4
- package/lib/merge-props/mergeProps.js.map +1 -1
- package/lib/merge-props/mergeStyles.d.ts +33 -4
- package/lib/merge-props/mergeStyles.d.ts.map +1 -1
- package/lib/merge-props/mergeStyles.js +16 -17
- package/lib/merge-props/mergeStyles.js.map +1 -1
- package/lib/merge-props/mergeStyles.test.d.ts +1 -1
- package/lib/merge-props/mergeStyles.test.js +75 -75
- package/lib/merge-props/mergeStyles.test.js.map +1 -1
- package/lib/merge-props/mergeStyles.types.d.ts +4 -4
- package/lib/merge-props/mergeStyles.types.d.ts.map +1 -1
- package/lib/merge-props/mergeStyles.types.js +1 -1
- package/lib/utilities/filterProps.d.ts +3 -0
- package/lib/utilities/filterProps.d.ts.map +1 -0
- package/lib/utilities/filterProps.js +12 -0
- package/lib/utilities/filterProps.js.map +1 -0
- package/lib-commonjs/component-patterns/directComponent.d.ts +7 -0
- package/lib-commonjs/component-patterns/directComponent.d.ts.map +1 -0
- package/lib-commonjs/component-patterns/directComponent.js +11 -0
- package/lib-commonjs/component-patterns/directComponent.js.map +1 -0
- package/lib-commonjs/component-patterns/extract.d.ts +22 -0
- package/lib-commonjs/component-patterns/extract.d.ts.map +1 -0
- package/lib-commonjs/component-patterns/extract.js +30 -0
- package/lib-commonjs/component-patterns/extract.js.map +1 -0
- package/lib-commonjs/component-patterns/phasedComponent.d.ts +18 -0
- package/lib-commonjs/component-patterns/phasedComponent.d.ts.map +1 -0
- package/lib-commonjs/component-patterns/phasedComponent.js +60 -0
- package/lib-commonjs/component-patterns/phasedComponent.js.map +1 -0
- package/lib-commonjs/component-patterns/render.d.ts +9 -3
- package/lib-commonjs/component-patterns/render.d.ts.map +1 -1
- package/lib-commonjs/component-patterns/render.js +101 -64
- package/lib-commonjs/component-patterns/render.js.map +1 -1
- package/lib-commonjs/component-patterns/render.types.d.ts +60 -34
- package/lib-commonjs/component-patterns/render.types.d.ts.map +1 -1
- package/lib-commonjs/component-patterns/render.types.js +3 -3
- package/lib-commonjs/component-patterns/stagedComponent.d.ts +3 -8
- package/lib-commonjs/component-patterns/stagedComponent.d.ts.map +1 -1
- package/lib-commonjs/component-patterns/stagedComponent.js +64 -56
- package/lib-commonjs/component-patterns/stagedComponent.js.map +1 -1
- package/lib-commonjs/component-patterns/withSlots.d.ts +6 -2
- package/lib-commonjs/component-patterns/withSlots.d.ts.map +1 -1
- package/lib-commonjs/component-patterns/withSlots.js +7 -8
- package/lib-commonjs/component-patterns/withSlots.js.map +1 -1
- package/lib-commonjs/immutable-merge/Merge.d.ts +6 -3
- package/lib-commonjs/immutable-merge/Merge.js +85 -90
- package/lib-commonjs/immutable-merge/Merge.js.map +1 -1
- package/lib-commonjs/immutable-merge/Merge.test.d.ts +1 -1
- package/lib-commonjs/immutable-merge/Merge.test.js +234 -222
- package/lib-commonjs/immutable-merge/Merge.test.js.map +1 -1
- package/lib-commonjs/index.d.ts +33 -5
- package/lib-commonjs/index.d.ts.map +1 -1
- package/lib-commonjs/index.js +184 -31
- package/lib-commonjs/index.js.map +1 -1
- package/lib-commonjs/jsx-namespace.d.ts +65 -0
- package/lib-commonjs/jsx-namespace.d.ts.map +1 -0
- package/lib-commonjs/jsx-namespace.js +3 -0
- package/lib-commonjs/jsx-namespace.js.map +1 -0
- package/lib-commonjs/jsx-runtime.d.ts +6 -4
- package/lib-commonjs/jsx-runtime.d.ts.map +1 -1
- package/lib-commonjs/jsx-runtime.js +69 -34
- package/lib-commonjs/jsx-runtime.js.map +1 -1
- package/lib-commonjs/memo-cache/getCacheEntry.d.ts +13 -13
- package/lib-commonjs/memo-cache/getCacheEntry.js +23 -26
- package/lib-commonjs/memo-cache/getCacheEntry.js.map +1 -1
- package/lib-commonjs/memo-cache/getCacheEntry.test.d.ts +1 -1
- package/lib-commonjs/memo-cache/getCacheEntry.test.js +93 -93
- package/lib-commonjs/memo-cache/getCacheEntry.test.js.map +1 -1
- package/lib-commonjs/memo-cache/getMemoCache.d.ts +1 -1
- package/lib-commonjs/memo-cache/getMemoCache.js +16 -17
- package/lib-commonjs/memo-cache/getMemoCache.js.map +1 -1
- package/lib-commonjs/memo-cache/getMemoCache.test.d.ts +1 -1
- package/lib-commonjs/memo-cache/getMemoCache.test.js +76 -76
- package/lib-commonjs/memo-cache/getMemoCache.test.js.map +1 -1
- package/lib-commonjs/memo-cache/memoize.d.ts +1 -1
- package/lib-commonjs/memo-cache/memoize.js +13 -14
- package/lib-commonjs/memo-cache/memoize.js.map +1 -1
- package/lib-commonjs/memo-cache/memoize.test.d.ts +1 -1
- package/lib-commonjs/memo-cache/memoize.test.js +39 -41
- package/lib-commonjs/memo-cache/memoize.test.js.map +1 -1
- package/lib-commonjs/merge-props/index.d.ts +1 -1
- package/lib-commonjs/merge-props/index.js +17 -7
- package/lib-commonjs/merge-props/index.js.map +1 -1
- package/lib-commonjs/merge-props/mergeProps.d.ts +1 -1
- package/lib-commonjs/merge-props/mergeProps.js +9 -10
- package/lib-commonjs/merge-props/mergeProps.js.map +1 -1
- package/lib-commonjs/merge-props/mergeStyles.d.ts +33 -4
- package/lib-commonjs/merge-props/mergeStyles.d.ts.map +1 -1
- package/lib-commonjs/merge-props/mergeStyles.js +23 -25
- package/lib-commonjs/merge-props/mergeStyles.js.map +1 -1
- package/lib-commonjs/merge-props/mergeStyles.test.d.ts +1 -1
- package/lib-commonjs/merge-props/mergeStyles.test.js +78 -78
- package/lib-commonjs/merge-props/mergeStyles.test.js.map +1 -1
- package/lib-commonjs/merge-props/mergeStyles.types.d.ts +4 -4
- package/lib-commonjs/merge-props/mergeStyles.types.d.ts.map +1 -1
- package/lib-commonjs/merge-props/mergeStyles.types.js +3 -3
- package/lib-commonjs/utilities/filterProps.d.ts +3 -0
- package/lib-commonjs/utilities/filterProps.d.ts.map +1 -0
- package/lib-commonjs/utilities/filterProps.js +15 -0
- package/lib-commonjs/utilities/filterProps.js.map +1 -0
- package/package.json +48 -26
- package/src/component-patterns/README.md +53 -16
- package/src/component-patterns/directComponent.ts +9 -0
- package/src/component-patterns/extract.ts +32 -0
- package/src/component-patterns/phasedComponent.ts +54 -0
- package/src/component-patterns/render.ts +21 -13
- package/src/component-patterns/render.types.ts +55 -30
- package/src/component-patterns/stagedComponent.ts +24 -0
- package/src/immutable-merge/Merge.test.ts +5 -1
- package/src/index.ts +27 -7
- package/src/jsx-namespace.ts +83 -0
- package/src/jsx-runtime.ts +8 -4
- package/src/memo-cache/README.md +1 -1
- package/src/merge-props/mergeStyles.ts +52 -4
- package/src/merge-props/mergeStyles.types.ts +2 -2
- package/src/utilities/filterProps.ts +14 -0
- package/src/component-patterns/stagedComponent.tsx +0 -45
|
@@ -2,38 +2,75 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
-
There are two main patterns exposed here: direct rendering and
|
|
5
|
+
There are two main patterns exposed here: direct rendering and phased rendering.
|
|
6
6
|
|
|
7
7
|
## Direct Rendering
|
|
8
8
|
|
|
9
|
-
The direct rendering pattern allows a component to be called directly, rather than creating a new entry in the
|
|
9
|
+
The direct rendering pattern allows a component to be called directly, rather than creating a new entry in the render tree.
|
|
10
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
|
|
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
12
|
|
|
13
13
|
```ts
|
|
14
14
|
const MyNewText: React.FunctionComponent<MyTextProps> = (props) => {
|
|
15
|
-
return <MyText {...props
|
|
16
|
-
}
|
|
15
|
+
return <MyText {...props} italicize={true} />;
|
|
16
|
+
};
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
When this is rendered, there is an entry for `MyNewText` which contains a `MyText` (another entry), which might
|
|
19
|
+
When this is rendered, there is an entry for `MyNewText` which contains a `MyText` (another entry), which might contain `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
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
|
|
21
|
+
- For the above to be safe, `MyNewText` should NOT use hooks. In the case of any conditional rendering logic this will break the rules of hooks.
|
|
22
22
|
|
|
23
23
|
There are two types of implementations in this folder:
|
|
24
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
|
|
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. Use the `directComponent()` helper to create these.
|
|
26
|
+
- `LegacyDirectComponent` - the pattern currently used in legacy code 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
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
|
|
28
|
+
The internal logic of the JSX rendering helpers (`renderForJsxRuntime` and `renderForClassicRuntime`) 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 somewhat undefined behavior with regards to children.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
### Example: Using directComponent
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
```ts
|
|
33
|
+
import { directComponent } from '@fluentui-react-native/framework-base';
|
|
34
|
+
|
|
35
|
+
const MyNewText = directComponent<MyTextProps>((props) => {
|
|
36
|
+
return <MyText {...props} italicize={true} />;
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Phased Rendering
|
|
41
|
+
|
|
42
|
+
The issue with the direct component pattern above is that hooks are integral to writing functional components. The phased rendering pattern is designed to help with this. In this case a component is implemented in two phases: the prep phase where hooks are called, and the rendering phase where the tree is emitted.
|
|
43
|
+
|
|
44
|
+
As above there is a newer and older version of the pattern:
|
|
45
|
+
|
|
46
|
+
- `PhasedComponent` - the newer version of the pattern, where the returned component function expects children as part of props. Create these using `phasedComponent()`. The attached property is `_phasedRender`.
|
|
47
|
+
- `ComposableFunction` (deprecated) - the older "staged" version, where children are split out and JSX hooks are required to render correctly. Create these using the deprecated `stagedComponent()`. The attached property is `_staged`.
|
|
48
|
+
|
|
49
|
+
Note that while the newer patterns work without any JSX hooks, the hooks will enable element flattening.
|
|
50
|
+
|
|
51
|
+
### Example: Using phasedComponent
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { phasedComponent } from '@fluentui-react-native/framework-base';
|
|
55
|
+
|
|
56
|
+
const MyComponent = phasedComponent<MyComponentProps>((props) => {
|
|
57
|
+
// Phase 1: Hooks and logic
|
|
58
|
+
const theme = useTheme();
|
|
59
|
+
const styles = useStyles(theme, props);
|
|
60
|
+
|
|
61
|
+
// Phase 2: Return a component that renders
|
|
62
|
+
return (innerProps) => {
|
|
63
|
+
return <View style={styles}>{innerProps.children}</View>;
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## JSX Runtime
|
|
33
69
|
|
|
34
|
-
|
|
70
|
+
This package provides a custom JSX runtime (`@fluentui-react-native/framework-base/jsx-runtime`) that automatically handles both direct and phased rendering patterns. When you use the `@jsxImportSource @fluentui-react-native/framework-base` pragma, the custom runtime will:
|
|
35
71
|
|
|
36
|
-
|
|
37
|
-
|
|
72
|
+
1. Detect components marked with `_callDirect` or `_canCompose` and call them directly
|
|
73
|
+
2. Handle the different children patterns (props vs. rest args)
|
|
74
|
+
3. Fall back to standard React rendering for normal components
|
|
38
75
|
|
|
39
|
-
|
|
76
|
+
This enables element flattening without requiring explicit calls to helper functions.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FunctionComponent } from './render.types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param component functional component, usually a closure, to make into a direct component
|
|
5
|
+
* @return the same component with the direct component flag set, return type is a pure function component
|
|
6
|
+
*/
|
|
7
|
+
export function directComponent<TProps>(component: FunctionComponent<TProps>): FunctionComponent<TProps> {
|
|
8
|
+
return Object.assign(component, { _callDirect: true });
|
|
9
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ViewStyle, TextStyle, ImageStyle } from 'react-native';
|
|
2
|
+
|
|
3
|
+
type StyleTypes = ViewStyle | TextStyle | ImageStyle;
|
|
4
|
+
type PropsWithStyle = { style?: ViewStyle | TextStyle | ImageStyle };
|
|
5
|
+
type PropsWithChildren = { children?: React.ReactNode };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extract the props from a React element. If the element is undefined, undefined will be returned.
|
|
9
|
+
* @param element The React element from which to extract the props.
|
|
10
|
+
* @returns The extracted props or undefined if the element is undefined.
|
|
11
|
+
*/
|
|
12
|
+
export function extractProps<T extends object>(element?: React.ReactElement): T | undefined {
|
|
13
|
+
return element ? (element.props as T) : undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Extract the children from a React element. If the element is undefined, undefined will be returned.
|
|
18
|
+
* @param element The React element from which to extract the children.
|
|
19
|
+
* @returns The extracted children or undefined if the element is undefined.
|
|
20
|
+
*/
|
|
21
|
+
export function extractChildren(element?: React.ReactElement): React.ReactNode | undefined {
|
|
22
|
+
return extractProps<PropsWithChildren>(element)?.children;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extract a style object from a React element. If the element is undefined or does not have a style prop, an empty object will be returned.
|
|
27
|
+
* @param element The React element from which to extract the style.
|
|
28
|
+
* @returns The extracted style object or an empty object if not available.
|
|
29
|
+
*/
|
|
30
|
+
export function extractStyle<T extends StyleTypes = ViewStyle>(element?: React.ReactElement): T {
|
|
31
|
+
return (extractProps<PropsWithStyle>(element)?.style as T) ?? ({} as T);
|
|
32
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ComposableFunction, PhasedComponent, PhasedRender, FunctionComponent } from './render.types';
|
|
3
|
+
import { renderForJsxRuntime } from './render';
|
|
4
|
+
import type { LegacyDirectComponent } from './render.types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extract the phased render function from a component, if it has one.
|
|
8
|
+
* Handles both the newer PhasedComponent pattern (_phasedRender) and the legacy
|
|
9
|
+
* ComposableFunction pattern (_staged) for backward compatibility.
|
|
10
|
+
*
|
|
11
|
+
* @param component - The component to extract the phased render from
|
|
12
|
+
* @returns The phased render function if present, undefined otherwise
|
|
13
|
+
*/
|
|
14
|
+
export function getPhasedRender<TProps>(component: React.ComponentType<TProps>): PhasedRender<TProps> | undefined {
|
|
15
|
+
// only a function component can have a phased render
|
|
16
|
+
if (typeof component === 'function') {
|
|
17
|
+
// if this has a phased render function, return it
|
|
18
|
+
if ((component as PhasedComponent<TProps>)._phasedRender) {
|
|
19
|
+
return (component as PhasedComponent<TProps>)._phasedRender;
|
|
20
|
+
} else if ((component as ComposableFunction<TProps>)._staged) {
|
|
21
|
+
// for backward compatibility check for staged render and return a wrapper that maps the signature
|
|
22
|
+
const staged = (component as ComposableFunction<TProps>)._staged;
|
|
23
|
+
return (props: TProps) => {
|
|
24
|
+
const { children, ...rest } = props as React.PropsWithChildren<TProps>;
|
|
25
|
+
const inner = staged(rest as TProps, ...React.Children.toArray(children));
|
|
26
|
+
// staged render functions were not consistently marking contents as composable, though they were treated
|
|
27
|
+
// as such in useHook. To maintain compatibility we mark the returned function as composable here. This was
|
|
28
|
+
// dangerous, but this shim is necessary for backward compatibility. The newer pattern is explicit about this.
|
|
29
|
+
if (typeof inner === 'function' && !(inner as LegacyDirectComponent<TProps>)._canCompose) {
|
|
30
|
+
return Object.assign(inner, { _canCompose: true });
|
|
31
|
+
}
|
|
32
|
+
return inner;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Take a phased render function and make a real component out of it, attaching the phased render function
|
|
41
|
+
* so it can be split if used in that manner.
|
|
42
|
+
* @param getInnerPhase - phased render function to wrap into a staged component
|
|
43
|
+
*/
|
|
44
|
+
export function phasedComponent<TProps>(getInnerPhase: PhasedRender<TProps>): FunctionComponent<TProps> {
|
|
45
|
+
return Object.assign(
|
|
46
|
+
(props: React.PropsWithChildren<TProps>) => {
|
|
47
|
+
// pull out children from props
|
|
48
|
+
const { children, ...outerProps } = props;
|
|
49
|
+
const Inner = getInnerPhase(outerProps as TProps);
|
|
50
|
+
return renderForJsxRuntime(Inner, { children });
|
|
51
|
+
},
|
|
52
|
+
{ _phasedRender: getInnerPhase },
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -4,7 +4,7 @@ import type { RenderType, RenderResult, DirectComponent, LegacyDirectComponent }
|
|
|
4
4
|
|
|
5
5
|
export type CustomRender = () => RenderResult;
|
|
6
6
|
|
|
7
|
-
function asDirectComponent<TProps>(type: RenderType): DirectComponent<TProps> | undefined {
|
|
7
|
+
export function asDirectComponent<TProps>(type: RenderType): DirectComponent<TProps> | undefined {
|
|
8
8
|
if (typeof type === 'function' && (type as DirectComponent<TProps>)._callDirect) {
|
|
9
9
|
return type as DirectComponent<TProps>;
|
|
10
10
|
}
|
|
@@ -22,7 +22,7 @@ export function renderForJsxRuntime<TProps>(
|
|
|
22
22
|
type: React.ElementType,
|
|
23
23
|
props: React.PropsWithChildren<TProps>,
|
|
24
24
|
key?: React.Key,
|
|
25
|
-
jsxFn: typeof ReactJSX.jsx =
|
|
25
|
+
jsxFn: typeof ReactJSX.jsx = undefined,
|
|
26
26
|
): RenderResult {
|
|
27
27
|
const legacyDirect = asLegacyDirectComponent(type);
|
|
28
28
|
if (legacyDirect) {
|
|
@@ -35,20 +35,28 @@ export function renderForJsxRuntime<TProps>(
|
|
|
35
35
|
const newProps = { ...props, key };
|
|
36
36
|
return directComponent(newProps);
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
// auto-detect whether to use jsx or jsxs based on number of children, 0 or 1 = jsx, more than 1 = jsxs
|
|
40
|
+
if (!jsxFn) {
|
|
41
|
+
if (React.Children.count(props.children) > 1) {
|
|
42
|
+
jsxFn = ReactJSX.jsxs;
|
|
43
|
+
} else {
|
|
44
|
+
jsxFn = ReactJSX.jsx;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Extract key from props to avoid React 19 warning about spreading key prop
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
const { key: propsKey, ...propsWithoutKey } = props as any;
|
|
50
|
+
// Use explicitly passed key, or fall back to key from props
|
|
51
|
+
const finalKey = key ?? propsKey;
|
|
52
|
+
// now call the appropriate jsx function to render the component
|
|
53
|
+
return jsxFn(type, propsWithoutKey, finalKey);
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
export function renderForClassicRuntime<TProps>(type: RenderType, props: TProps, ...children: React.ReactNode[]): RenderResult {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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);
|
|
57
|
+
// if it is a non-string type with _canCompose set just call the function directly, otherwise call createElement as normal
|
|
58
|
+
const propsWithChildren = { children, ...props };
|
|
59
|
+
return renderForJsxRuntime(type as React.ElementType, propsWithChildren);
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
export const renderSlot = renderForClassicRuntime;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import type ReactJSX from 'react/jsx-runtime';
|
|
2
|
+
//import type ReactJSX from 'react/jsx-runtime';
|
|
3
|
+
import type { FurnJSX } from '../jsx-namespace';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Base types for rendering components in a react application, extracted from react types
|
|
6
7
|
*/
|
|
7
|
-
export type RenderResult =
|
|
8
|
-
export type
|
|
8
|
+
export type RenderResult = FurnJSX.Element;
|
|
9
|
+
//export type RenderResult = ReturnType<typeof ReactJSX.jsx>;
|
|
10
|
+
export type RenderType = FurnJSX.ElementType;
|
|
11
|
+
//export type RenderType = Parameters<typeof ReactJSX.jsx>[0] | string;
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* The standard element type inputs for react and react-native. This might be View or Button, or it might be 'div' in web. Effectively
|
|
@@ -13,6 +16,11 @@ export type RenderType = Parameters<typeof ReactJSX.jsx>[0] | string;
|
|
|
13
16
|
*/
|
|
14
17
|
export type NativeReactType = RenderType;
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Get the props from a react component type
|
|
21
|
+
*/
|
|
22
|
+
export type PropsOf<TComponent> = TComponent extends React.JSXElementConstructor<infer P> ? P : never;
|
|
23
|
+
|
|
16
24
|
/**
|
|
17
25
|
* DIRECT RENDERING
|
|
18
26
|
*
|
|
@@ -29,78 +37,95 @@ export type NativeReactType = RenderType;
|
|
|
29
37
|
/**
|
|
30
38
|
* type of the render function, not a FunctionComponent to help prevent hook usage
|
|
31
39
|
*/
|
|
32
|
-
export type
|
|
40
|
+
export type FunctionComponentCore<TProps> = (props: TProps) => RenderResult;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A function component that returns an element type. This allows for the empty call props usage for native
|
|
44
|
+
* components, as well as handles the returns of React components.
|
|
45
|
+
*/
|
|
46
|
+
export type FunctionComponent<TProps> = FunctionComponentCore<TProps> & {
|
|
47
|
+
displayName?: string;
|
|
48
|
+
};
|
|
33
49
|
|
|
34
50
|
/**
|
|
35
51
|
* The full component definition that has the attached properties to allow the jsx handlers to render it directly.
|
|
36
52
|
*/
|
|
37
|
-
export type DirectComponent<TProps> =
|
|
53
|
+
export type DirectComponent<TProps> = FunctionComponentCore<TProps> & {
|
|
38
54
|
displayName?: string;
|
|
39
55
|
_callDirect?: boolean;
|
|
40
56
|
};
|
|
41
57
|
|
|
58
|
+
type LegacyComponentFunction<TProps> = (props: TProps, ...children: React.ReactNode[]) => RenderResult;
|
|
59
|
+
|
|
42
60
|
/**
|
|
43
61
|
* Legacy slot function type, this allows the rendering handlers to bypass the normal JSX rendering and call the function
|
|
44
62
|
* directly. This expects the function to have children as the last argument of the call which isn't consistent with standard
|
|
45
63
|
* react usage, where children are passed as a prop. If writing new components use the DirectComponent type instead.
|
|
46
64
|
* @deprecated use DirectComponent instead
|
|
47
65
|
*/
|
|
48
|
-
export type LegacyDirectComponent<TProps> =
|
|
66
|
+
export type LegacyDirectComponent<TProps> = LegacyComponentFunction<TProps> & {
|
|
49
67
|
_canCompose?: boolean;
|
|
50
68
|
};
|
|
51
69
|
|
|
52
70
|
/**
|
|
53
|
-
*
|
|
71
|
+
* Slot function type used in the composition framework. Slot functions return React elements (not arbitrary ReactNode values)
|
|
72
|
+
* since they always either call staged render functions or React.createElement.
|
|
54
73
|
*/
|
|
55
|
-
export type SlotFn<TProps> =
|
|
74
|
+
export type SlotFn<TProps> = {
|
|
75
|
+
(props: TProps, ...children: React.ReactNode[]): React.ReactElement | null;
|
|
76
|
+
_canCompose?: boolean;
|
|
77
|
+
};
|
|
56
78
|
|
|
57
79
|
/**
|
|
58
|
-
*
|
|
80
|
+
* PHASED RENDERING (formerly called "staged" or "two-stage" rendering)
|
|
59
81
|
*
|
|
60
|
-
* The above direct rendering pattern is useful for simple components, but it does not allow for hooks or complex logic. The
|
|
61
|
-
* for a component to be rendered in two
|
|
82
|
+
* The above direct rendering pattern is useful for simple components, but it does not allow for hooks or complex logic. The phased render pattern allows
|
|
83
|
+
* for a component to be rendered in two phases, allowing for hooks to be used in the first phase and then the second phase to be a simple render function that can
|
|
62
84
|
* be called directly.
|
|
63
85
|
*
|
|
64
|
-
* In code that respects the pattern the first
|
|
65
|
-
* with additional props, this time with children present. This allows for the first
|
|
86
|
+
* In code that respects the pattern, the first phase will be called with props (though children will not be present) and will return a function that will be called
|
|
87
|
+
* with additional props, this time with children present. This allows for the first phase to handle all the logic and hooks, while the second phase can be a simple render function
|
|
66
88
|
* that can leverage direct rendering if supported.
|
|
67
89
|
*
|
|
68
|
-
* The component itself will be a FunctionComponent, but it will have an attached property that is the
|
|
90
|
+
* The component itself will be a FunctionComponent, but it will have an attached property that is the phased render function. This allows the component to be used in two
|
|
69
91
|
* parts via the useSlot hook, or to be used directly in JSX/TSX as a normal component.
|
|
70
92
|
*/
|
|
71
93
|
|
|
72
94
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
95
|
+
* Phased render function signature. This is the recommended pattern for components that need hooks.
|
|
96
|
+
*
|
|
97
|
+
* Phase 1 receives props (without children) and can use hooks to compute derived state.
|
|
98
|
+
* Phase 2 returns a component that will be called with props including children.
|
|
75
99
|
*
|
|
76
|
-
*
|
|
100
|
+
* Children will be passed as part of the props for component rendering. The `children` prop will be
|
|
101
|
+
* automatically inferred and typed correctly by the prop type.
|
|
77
102
|
*/
|
|
78
|
-
export type
|
|
103
|
+
export type PhasedRender<TProps> = (props: TProps) => React.ComponentType<React.PropsWithChildren<TProps>>;
|
|
79
104
|
|
|
80
105
|
/**
|
|
81
|
-
* Component type for a component that can be rendered in two
|
|
106
|
+
* Component type for a component that can be rendered in two phases, with the attached phased render function.
|
|
107
|
+
* Use phasedComponent() to create these.
|
|
82
108
|
*/
|
|
83
|
-
export type
|
|
84
|
-
|
|
109
|
+
export type PhasedComponent<TProps> = FunctionComponent<TProps> & {
|
|
110
|
+
_phasedRender?: PhasedRender<TProps>;
|
|
85
111
|
};
|
|
86
|
-
|
|
87
112
|
/**
|
|
88
|
-
* The final rendering of the props in a
|
|
113
|
+
* The final rendering of the props in a phased render. This is the function component signature that matches that of
|
|
89
114
|
* React.createElement, children (if present) will be part of the variable args at the end.
|
|
90
115
|
*/
|
|
91
|
-
export type FinalRender<TProps> = (props: TProps, ...children: React.ReactNode[]) =>
|
|
116
|
+
export type FinalRender<TProps> = (props: TProps, ...children: React.ReactNode[]) => FurnJSX.Element | null;
|
|
92
117
|
|
|
93
118
|
/**
|
|
94
|
-
*
|
|
95
|
-
* @deprecated Use
|
|
119
|
+
* Legacy staged render function signature.
|
|
120
|
+
* @deprecated Use PhasedRender instead. This older pattern splits children from props which is inconsistent with React conventions.
|
|
96
121
|
*/
|
|
97
122
|
export type StagedRender<TProps> = (props: TProps, ...args: any[]) => FinalRender<TProps>;
|
|
98
123
|
|
|
99
124
|
/**
|
|
100
|
-
*
|
|
101
|
-
* @deprecated Use
|
|
125
|
+
* Legacy component type that uses the staged render pattern.
|
|
126
|
+
* @deprecated Use PhasedComponent instead. Create with phasedComponent() rather than stagedComponent().
|
|
102
127
|
*/
|
|
103
|
-
export type ComposableFunction<TProps> =
|
|
128
|
+
export type ComposableFunction<TProps> = FunctionComponent<TProps> & { _staged?: StagedRender<TProps> };
|
|
104
129
|
|
|
105
130
|
/**
|
|
106
131
|
* A type aggregating all the custom types that can be used in the render process.
|
|
@@ -109,6 +134,6 @@ export type ComposableFunction<TProps> = React.FunctionComponent<TProps> & { _st
|
|
|
109
134
|
export type AnyCustomType<TProps> =
|
|
110
135
|
| React.FunctionComponent<TProps>
|
|
111
136
|
| DirectComponent<TProps>
|
|
112
|
-
|
|
|
137
|
+
| PhasedComponent<TProps>
|
|
113
138
|
| ComposableFunction<TProps>
|
|
114
139
|
| LegacyDirectComponent<TProps>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { StagedRender, ComposableFunction } from './render.types';
|
|
4
|
+
|
|
5
|
+
function asArray<T>(val: T | T[]): T[] {
|
|
6
|
+
return Array.isArray(val) ? val : [val];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Take a staged render function and make a real component out of it
|
|
11
|
+
*
|
|
12
|
+
* @param staged - staged render function to wrap into a staged component
|
|
13
|
+
* @param memo - optional flag to enable wrapping the created component in a React.memo HOC
|
|
14
|
+
* @deprecated Use phasedComponent from phasedComponent.ts instead
|
|
15
|
+
*/
|
|
16
|
+
export function stagedComponent<TProps>(staged: StagedRender<TProps>, memo?: boolean): ComposableFunction<TProps> {
|
|
17
|
+
const component = (props: React.PropsWithChildren<TProps>) => {
|
|
18
|
+
const { children, ...rest } = props;
|
|
19
|
+
return staged(rest as TProps)({} as React.PropsWithChildren<TProps>, asArray(children));
|
|
20
|
+
};
|
|
21
|
+
const stagedComponent = memo ? React.memo(component) : component;
|
|
22
|
+
Object.assign(stagedComponent, { _staged: staged });
|
|
23
|
+
return stagedComponent as ComposableFunction<TProps>;
|
|
24
|
+
}
|
|
@@ -305,7 +305,11 @@ describe('Immutable merge unit tests', () => {
|
|
|
305
305
|
const arrayMerger = (...targets: any[]) => {
|
|
306
306
|
const arrays = targets.filter((t) => Array.isArray(t));
|
|
307
307
|
let result = [];
|
|
308
|
-
|
|
308
|
+
for (const v of arrays) {
|
|
309
|
+
if (v.length > 0) {
|
|
310
|
+
result = result.concat(...v);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
309
313
|
return result;
|
|
310
314
|
};
|
|
311
315
|
|
package/src/index.ts
CHANGED
|
@@ -19,22 +19,42 @@ export type { StyleProp } from './merge-props/mergeStyles.types';
|
|
|
19
19
|
export { mergeStyles } from './merge-props/mergeStyles';
|
|
20
20
|
export { mergeProps } from './merge-props/mergeProps';
|
|
21
21
|
|
|
22
|
-
// component pattern exports
|
|
23
|
-
export {
|
|
22
|
+
// component pattern exports - extracting from elements
|
|
23
|
+
export { extractChildren, extractProps, extractStyle } from './component-patterns/extract';
|
|
24
|
+
|
|
25
|
+
// component pattern exports - rendering utilities
|
|
26
|
+
export { renderForJsxRuntime, renderSlot, asDirectComponent } from './component-patterns/render';
|
|
27
|
+
|
|
28
|
+
// component pattern exports - core types
|
|
24
29
|
export type {
|
|
25
30
|
DirectComponent,
|
|
26
|
-
|
|
31
|
+
FunctionComponent,
|
|
32
|
+
FunctionComponentCore,
|
|
27
33
|
LegacyDirectComponent,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
PhasedComponent,
|
|
35
|
+
PhasedRender,
|
|
36
|
+
PropsOf,
|
|
31
37
|
RenderType,
|
|
32
38
|
RenderResult,
|
|
39
|
+
StagedRender,
|
|
33
40
|
ComposableFunction,
|
|
34
41
|
FinalRender,
|
|
35
42
|
SlotFn,
|
|
36
43
|
NativeReactType,
|
|
37
44
|
} from './component-patterns/render.types';
|
|
45
|
+
|
|
46
|
+
// component pattern exports - component builders
|
|
47
|
+
export { directComponent } from './component-patterns/directComponent';
|
|
48
|
+
export { getPhasedRender, phasedComponent } from './component-patterns/phasedComponent';
|
|
49
|
+
export { stagedComponent } from './component-patterns/stagedComponent';
|
|
50
|
+
|
|
51
|
+
// component pattern exports - legacy JSX handlers
|
|
38
52
|
export { withSlots } from './component-patterns/withSlots';
|
|
39
|
-
|
|
53
|
+
|
|
54
|
+
// jsx runtime exports
|
|
40
55
|
export { jsx, jsxs } from './jsx-runtime';
|
|
56
|
+
export type { FurnJSX } from './jsx-namespace';
|
|
57
|
+
|
|
58
|
+
// general utilities
|
|
59
|
+
export { filterProps } from './utilities/filterProps';
|
|
60
|
+
export type { PropsFilter } from './utilities/filterProps';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This file defines a custom JSX namespace that re-exports React's JSX types, but also allows us to add our own custom behavior to the JSX runtime.
|
|
5
|
+
* The main reason we need this is to support our "direct component" pattern, which allows certain components to bypass React's createElement and
|
|
6
|
+
* return their own React elements directly from the JSX runtime.
|
|
7
|
+
*
|
|
8
|
+
* Exporting this custom namespace is required to make intrinsic attributes like key and ref work correctly with our custom JSX functions. The normal
|
|
9
|
+
* fallback behavior if not defined is to not allow any attributes on intrinsic elements, which breaks a lot of React functionality.
|
|
10
|
+
*
|
|
11
|
+
* The custom behavior is implemented in the jsx and jsxs functions, which first check if the type being rendered is a direct component and if so, call it directly.
|
|
12
|
+
*
|
|
13
|
+
* Thanks to the emotion library's jsx-namespace for providing a reference implementation of how to do this while handling both React 18 and React 19's
|
|
14
|
+
* changes to the JSX types.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
type IsPreReact19 = 2 extends Parameters<React.FunctionComponent<any>>['length'] ? true : false;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The following types are intrinsic types for React, but handled in a way that allows them to be correctly resolved in both
|
|
21
|
+
* React 18 and React 19.
|
|
22
|
+
*
|
|
23
|
+
* React 18:
|
|
24
|
+
* - JSX.Element, JSX.ElementClass, etc.
|
|
25
|
+
* - no React.JSX namespace
|
|
26
|
+
*
|
|
27
|
+
* React 19:
|
|
28
|
+
* - React.JSX.Element, React.JSX.ElementClass, etc.
|
|
29
|
+
* - no global JSX namespace
|
|
30
|
+
*
|
|
31
|
+
* In both cases, we want to be able to reference these types in our custom JSX namespace, so we conditionally define them based on whether we're in
|
|
32
|
+
* a pre-React 19 environment or not. The @ts-expect-error comments are used because both can't be valid at the same time so there will always be
|
|
33
|
+
* an error.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
37
|
+
type ReactJSXElement = true extends IsPreReact19 ? JSX.Element : React.JSX.Element;
|
|
38
|
+
|
|
39
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
40
|
+
type ReactJSXElementClass = true extends IsPreReact19 ? JSX.ElementClass : React.JSX.ElementClass;
|
|
41
|
+
|
|
42
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
43
|
+
type ReactJSXElementAttributesProperty = true extends IsPreReact19 ? JSX.ElementAttributesProperty : React.JSX.ElementAttributesProperty;
|
|
44
|
+
|
|
45
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
46
|
+
type ReactJSXElementChildrenAttribute = true extends IsPreReact19 ? JSX.ElementChildrenAttribute : React.JSX.ElementChildrenAttribute;
|
|
47
|
+
|
|
48
|
+
// prettier-ignore
|
|
49
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
50
|
+
type ReactJSXLibraryManagedAttributes<C, P> = true extends IsPreReact19 ? JSX.LibraryManagedAttributes<C, P> : React.JSX.LibraryManagedAttributes<C, P>;
|
|
51
|
+
|
|
52
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
53
|
+
type ReactJSXIntrinsicAttributes = true extends IsPreReact19 ? JSX.IntrinsicAttributes : React.JSX.IntrinsicAttributes;
|
|
54
|
+
|
|
55
|
+
// prettier-ignore
|
|
56
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
57
|
+
type ReactJSXIntrinsicClassAttributes<T> = true extends IsPreReact19 ? JSX.IntrinsicClassAttributes<T> : React.JSX.IntrinsicClassAttributes<T>;
|
|
58
|
+
|
|
59
|
+
/** @ts-expect-error references types for both react 18 and react 19, only one can be valid at a time */
|
|
60
|
+
type ReactJSXIntrinsicElements = true extends IsPreReact19 ? JSX.IntrinsicElements : React.JSX.IntrinsicElements;
|
|
61
|
+
|
|
62
|
+
// based on the code from @types/react@18.2.8
|
|
63
|
+
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/3197efc097d522c4bf02b94e1a0766d007d6cdeb/types/react/index.d.ts#LL3204C13-L3204C13
|
|
64
|
+
type ReactJSXElementType = true extends IsPreReact19 ? string | React.JSXElementConstructor<any> : React.JSX.ElementType;
|
|
65
|
+
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
67
|
+
export declare namespace FurnJSX {
|
|
68
|
+
export type ElementType = ReactJSXElementType;
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
70
|
+
export interface Element extends ReactJSXElement {}
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
72
|
+
export interface ElementClass extends ReactJSXElementClass {}
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
74
|
+
export interface ElementAttributesProperty extends ReactJSXElementAttributesProperty {}
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
76
|
+
export interface ElementChildrenAttribute extends ReactJSXElementChildrenAttribute {}
|
|
77
|
+
export type LibraryManagedAttributes<C, P> = ReactJSXLibraryManagedAttributes<C, P>;
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
79
|
+
export interface IntrinsicAttributes extends ReactJSXIntrinsicAttributes {}
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
81
|
+
export interface IntrinsicClassAttributes<T> extends ReactJSXIntrinsicClassAttributes<T> {}
|
|
82
|
+
export type IntrinsicElements = ReactJSXIntrinsicElements;
|
|
83
|
+
}
|
package/src/jsx-runtime.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import * as ReactJSX from 'react/jsx-runtime';
|
|
3
3
|
import { renderForJsxRuntime } from './component-patterns/render';
|
|
4
|
+
export type { FurnJSX as JSX } from './jsx-namespace';
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
+
export const jsx: typeof ReactJSX.jsx = (type, props, key?: React.Key) => {
|
|
6
7
|
return renderForJsxRuntime(type, props, key, ReactJSX.jsx);
|
|
7
|
-
}
|
|
8
|
+
};
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
+
export const jsxs: typeof ReactJSX.jsxs = (type, props, key?: React.Key) => {
|
|
10
11
|
return renderForJsxRuntime(type, props, key, ReactJSX.jsxs);
|
|
11
|
-
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Re-export Fragment for <></> syntax
|
|
15
|
+
export { Fragment } from 'react/jsx-runtime';
|
package/src/memo-cache/README.md
CHANGED
|
@@ -134,7 +134,7 @@ export const MyComponent = (props: IMyComponentProps) => {
|
|
|
134
134
|
}, [theme]);
|
|
135
135
|
|
|
136
136
|
// merge the styles if a style is passed in via props, caching the union to ensure consistent object identity
|
|
137
|
-
newProps.style = newProps.style ? themeLocalCache(() => mergeStyles(style, newProps.style), [newProps.style])[0] : style;
|
|
137
|
+
newProps.style = newProps.style ? themeLocalCache(() => mergeStyles<MyStyleType>(style, newProps.style), [newProps.style])[0] : style;
|
|
138
138
|
|
|
139
139
|
return <InnerControl {...newProps} />;
|
|
140
140
|
};
|