@fluentui-react-native/framework-base 0.1.4 → 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.
Files changed (72) hide show
  1. package/CHANGELOG.json +16 -1
  2. package/CHANGELOG.md +10 -2
  3. package/README.md +10 -11
  4. package/lib/component-patterns/render.d.ts +8 -0
  5. package/lib/component-patterns/render.d.ts.map +1 -0
  6. package/lib/component-patterns/render.js +42 -0
  7. package/lib/component-patterns/render.js.map +1 -0
  8. package/lib/component-patterns/render.types.d.ts +98 -0
  9. package/lib/component-patterns/render.types.d.ts.map +1 -0
  10. package/lib/component-patterns/render.types.js +2 -0
  11. package/lib/component-patterns/render.types.js.map +1 -0
  12. package/lib/component-patterns/stagedComponent.d.ts +7 -31
  13. package/lib/component-patterns/stagedComponent.d.ts.map +1 -1
  14. package/lib/component-patterns/stagedComponent.js +18 -0
  15. package/lib/component-patterns/stagedComponent.js.map +1 -1
  16. package/lib/component-patterns/withSlots.d.ts +2 -2
  17. package/lib/component-patterns/withSlots.d.ts.map +1 -1
  18. package/lib/component-patterns/withSlots.js +2 -2
  19. package/lib/component-patterns/withSlots.js.map +1 -1
  20. package/lib/index.d.ts +4 -4
  21. package/lib/index.d.ts.map +1 -1
  22. package/lib/index.js +3 -2
  23. package/lib/index.js.map +1 -1
  24. package/lib/jsx-runtime.d.ts +4 -0
  25. package/lib/jsx-runtime.d.ts.map +1 -0
  26. package/lib/jsx-runtime.js +9 -0
  27. package/lib/jsx-runtime.js.map +1 -0
  28. package/lib-commonjs/component-patterns/render.d.ts +8 -0
  29. package/lib-commonjs/component-patterns/render.d.ts.map +1 -0
  30. package/lib-commonjs/component-patterns/render.js +48 -0
  31. package/lib-commonjs/component-patterns/render.js.map +1 -0
  32. package/lib-commonjs/component-patterns/render.types.d.ts +98 -0
  33. package/lib-commonjs/component-patterns/render.types.d.ts.map +1 -0
  34. package/lib-commonjs/component-patterns/render.types.js +3 -0
  35. package/lib-commonjs/component-patterns/render.types.js.map +1 -0
  36. package/lib-commonjs/component-patterns/stagedComponent.d.ts +7 -31
  37. package/lib-commonjs/component-patterns/stagedComponent.d.ts.map +1 -1
  38. package/lib-commonjs/component-patterns/stagedComponent.js +20 -1
  39. package/lib-commonjs/component-patterns/stagedComponent.js.map +1 -1
  40. package/lib-commonjs/component-patterns/withSlots.d.ts +2 -2
  41. package/lib-commonjs/component-patterns/withSlots.d.ts.map +1 -1
  42. package/lib-commonjs/component-patterns/withSlots.js +2 -2
  43. package/lib-commonjs/component-patterns/withSlots.js.map +1 -1
  44. package/lib-commonjs/index.d.ts +4 -4
  45. package/lib-commonjs/index.d.ts.map +1 -1
  46. package/lib-commonjs/index.js +9 -3
  47. package/lib-commonjs/index.js.map +1 -1
  48. package/lib-commonjs/jsx-runtime.d.ts +4 -0
  49. package/lib-commonjs/jsx-runtime.d.ts.map +1 -0
  50. package/lib-commonjs/jsx-runtime.js +15 -0
  51. package/lib-commonjs/jsx-runtime.js.map +1 -0
  52. package/package.json +6 -1
  53. package/src/component-patterns/README.md +39 -0
  54. package/src/component-patterns/render.ts +54 -0
  55. package/src/component-patterns/render.types.ts +114 -0
  56. package/src/component-patterns/stagedComponent.tsx +45 -0
  57. package/src/component-patterns/withSlots.tsx +4 -8
  58. package/src/immutable-merge/README.md +185 -0
  59. package/src/index.ts +17 -4
  60. package/src/jsx-runtime.ts +11 -0
  61. package/src/memo-cache/README.md +141 -0
  62. package/src/merge-props/README.md +43 -0
  63. package/lib/component-patterns/renderSlot.d.ts +0 -21
  64. package/lib/component-patterns/renderSlot.d.ts.map +0 -1
  65. package/lib/component-patterns/renderSlot.js +0 -14
  66. package/lib/component-patterns/renderSlot.js.map +0 -1
  67. package/lib-commonjs/component-patterns/renderSlot.d.ts +0 -21
  68. package/lib-commonjs/component-patterns/renderSlot.d.ts.map +0 -1
  69. package/lib-commonjs/component-patterns/renderSlot.js +0 -19
  70. package/lib-commonjs/component-patterns/renderSlot.js.map +0 -1
  71. package/src/component-patterns/renderSlot.ts +0 -27
  72. package/src/component-patterns/stagedComponent.ts +0 -53
@@ -0,0 +1,185 @@
1
+ # Immutable Merge package
2
+
3
+ This package provides a relatively concise routine to handle merging multiple objects together with the following characteristics:
4
+
5
+ - No modifications will be made to any object
6
+ - Minimal updates. If only one value is updated three levels deep, only that value and the chain of containing objects will be recreated.
7
+ - Empty objects or undefined objects will be ignored and not cause a new branch to be created.
8
+ - Recursion is controllable in a variety of ways
9
+
10
+ Note that this does not provide a **strict** immutable package on its own. It also doesn't operate or return only readonly objects. This is to provide flexibility. It could easily be wrapped in various ways to provide that type of functionality, but it is provided in a more flexible form to be useful in other scenarios as well.
11
+
12
+ ## Deep Merge via `immutableMerge`
13
+
14
+ For standard deep merging, this package provides the `immutableMerge` function. The signature is as follows:
15
+
16
+ ```ts
17
+ export function immutableMerge<T extends object>(...objs: (T | undefined)[]): T | undefined;
18
+ ```
19
+
20
+ This takes one or more objects of type `T` and deep merges them. If objects are undefined or null in some manner they will be ignored. Merging via this routine (and all routines in the package) typically follow the semantics of `Object.assign`, with a few extra behaviors.
21
+
22
+ - all values at a given level will overwrite, with the last writer winning
23
+ - if a key does not exist for an object it is ignored
24
+ - if a key does exist, even if it is `undefined` it will replace the previous value
25
+ - only non-array objects will recurse, arrays will be replaced rather than appended
26
+ - keys which exist and have a value of `undefined` will be deleted
27
+
28
+ The peculiar pattern of deleting keys which end up as undefined is the only way to delete a key without violating the core principles. An example of key deletion might look like:
29
+
30
+ ```ts
31
+ const newObj = immutableMerge(myObj, { keyToDelete1: undefined, keyToDelete2: undefined });
32
+ ```
33
+
34
+ ## Custom Merging via `immutableMergeCore`
35
+
36
+ In many cases, merges have to follow additional rules to match the structure or behavior of objects passed in. This results in authoring custom merge routines to handle this constraint. This package allows for deep customization of merge behaviors via `immutableMergeCore`.
37
+
38
+ ```ts
39
+ export function immutableMergeCore<T extends object>(options: RecursionOptions | MergeOptions, ...objs: (T | undefined)[]): T | undefined;
40
+ ```
41
+
42
+ ### RecursionOptions
43
+
44
+ Recursion options can be a boolean or a number with behavior interpreted as follows:
45
+
46
+ - `boolean` - Should this recurse. If the value is `true` it will recurse infinitely, if `false` it will not recurse.
47
+ - `number` - Recursion depth. A value of `0` will not recurse any farther, a positive value will recurse that many additional levels before stopping, a negative value will recurse indefinitely.
48
+
49
+ ### MergeOptions
50
+
51
+ This object allows very precise control of the recursion. At a given level it matches values by name of the key, or by the resulting type of the property.
52
+
53
+ ```ts
54
+ export interface MergeOptions {
55
+ [typeOrName: string]: RecursionOptions | RecursionHandlers | MergeOptions;
56
+ }
57
+ ```
58
+
59
+ Matching will happen in the following order:
60
+
61
+ 1. Merged object property key matches a key in MergeOptions.
62
+ 2. The type of the key is referenced in MergeOptions. Note that arrays (which are objects) are treated as being of type 'array' for this purpose.
63
+
64
+ The values within the options can have the following types:
65
+
66
+ | Type | Usage |
67
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
68
+ | `RecursionOption` | Behaves as if this value was passed into the recursive call. So 0/false mean merge but don't recurse for the matching child object, less than zero / true means recurse deeply, greater than zero means recurse that many times. |
69
+ | `RecursionHandler` | Run a function to handle the merge or invoke one of the built-in handlers for the library. See below for more information. |
70
+ | `MergeOptions` | Forward the child `MergeOptions` to the child level when making the recursive call. |
71
+
72
+ ### RecursionHandler
73
+
74
+ When merging values for a given key, providing a recursion handler allows custom processing. A handler function has the following signature:
75
+
76
+ ```ts
77
+ export type CustomRecursionHandler = (...vals: any[]) => any;
78
+ ```
79
+
80
+ The vals parameter will have collected all the non-undefined values from the input objects. Note that type checking is the responsibility of the handler function.
81
+
82
+ #### Built in handlers
83
+
84
+ Built-in handlers can be referenced by name. The currently supported built-in handlers are as follows:
85
+
86
+ | Handler | Description |
87
+ | ------------- | ------------------------------------------- |
88
+ | `appendArray` | Append arrays rather than overwriting them. |
89
+
90
+ ### Example Usage
91
+
92
+ As an example, imagine props for react components, with a concept called SlotProps that has multiple props in the same object.
93
+
94
+ ```ts
95
+ export interface IStandardProps {
96
+ classNames?: string;
97
+ tokens?: ISomeObjectTypeWithoutStyle;
98
+ style?: CSSVariables | CSSVariables[];
99
+ // likely more
100
+ }
101
+
102
+ export interface IMyComponentProps extends IStandardProps {
103
+ // other stuff here
104
+ }
105
+
106
+ export interface IComponentSlotProps {
107
+ root: IMyComponentProps;
108
+ slot1: ISomeOtherComponentProps;
109
+ slot2: IYetAnotherComponentProps;
110
+ }
111
+ ```
112
+
113
+ In this case style needs to be merged in a special manner and classNames need to be appended. Deep recursion is not desireable in the case where a prop might be an object as with partial values you might get unexpected behavior. Here are some examples of ways to make merge routines:
114
+
115
+ ```ts
116
+ // all in one function
117
+ export function mergeSlotProps1(...slotProps: ISlotPropsBase[]): ISlotPropsBase {
118
+ return immutableMergeCore({
119
+ // match any object
120
+ object: {
121
+ // match tokens and merge but don't recurse
122
+ tokens: 0,
123
+ // run the string merge routine on classNames
124
+ classNames: (...names: string[]) => { names.map(name => name.trim()).join(' ') },
125
+ // run an existing style merge routine on styles
126
+ style: mergeStyles;
127
+ }
128
+ }, ...slotProps);
129
+ }
130
+
131
+ // this could be broken into two parts, options for props
132
+ const propsOptions: MergeOptions = {
133
+ tokens: 0,
134
+ classNames: (...names: string[]) => { names.map(name => name.trim()).join(' ') },
135
+ style: mergeStyles;
136
+ }
137
+
138
+ // then options for slotProps that refer to the props object
139
+ const slotPropsOptions: MergeOptions = {
140
+ object: propsOptions;
141
+ }
142
+
143
+ // then a wrapper for each
144
+ export function mergeProps<T extends IPropsBase>(...props: T[]): T {
145
+ return immutableMergeCore(propsOptions, ...props);
146
+ }
147
+
148
+ export function mergeSlotProps<T extends ISlotPropsBase>(...slotProps: T[]): T {
149
+ return immutableMergeCore(slotPropsOptions, ...slotProps);
150
+ }
151
+
152
+ ```
153
+
154
+ ## processImmutable
155
+
156
+ The ability to run a handler on something like a style as a part of merge is useful but in normal usage it has some limitations. If there is only one object in a branch or only one value of that type the handler won't run. If the processors are essential functions, or if it is desireable to run processors on a single object you can use `processImmutable`.
157
+
158
+ ```ts
159
+ export function processImmutable<T extends object>(options: MergeOptions, ...objs: (T | undefined)[]): T | undefined;
160
+ ```
161
+
162
+ This convenience function runs the merge routine as a processor for one or more objects. An example use case might be to turn all style entries into a css class name if it is not already a css class name. This should have the following behavior:
163
+
164
+ - Style values two levels down should be processed
165
+ - The object should remain unchanged if nothing changed
166
+ - branches which are unchanged should be untouched
167
+ - If a style gets updated the object should be mimally mutated
168
+
169
+ The usage would be as follows. Given a processor called `myStyleProcessor`:
170
+
171
+ ```ts
172
+ let complexObject: IMyObjtype = getObjectFromSomewhere();
173
+ complexObject = processImmutable(
174
+ {
175
+ object: {
176
+ object: {
177
+ style: myStyleProcessor,
178
+ },
179
+ },
180
+ },
181
+ complexObject,
182
+ );
183
+ ```
184
+
185
+ While the primary use case is for a single object this allows merging to happen at the same time if so desired. Merging happens as normal with the exception that processors will still be called in the case where there is only one object.
package/src/index.ts CHANGED
@@ -20,8 +20,21 @@ export { mergeStyles } from './merge-props/mergeStyles';
20
20
  export { mergeProps } from './merge-props/mergeProps';
21
21
 
22
22
  // component pattern exports
23
- export { renderSlot } from './component-patterns/renderSlot';
24
- export type { SlotFn, NativeReactType } from './component-patterns/renderSlot';
23
+ export { renderForClassicRuntime, renderForJsxRuntime, renderSlot } from './component-patterns/render';
24
+ export type {
25
+ DirectComponent,
26
+ DirectComponentFunction,
27
+ LegacyDirectComponent,
28
+ StagedComponent,
29
+ StagedRender,
30
+ TwoStageRender,
31
+ RenderType,
32
+ RenderResult,
33
+ ComposableFunction,
34
+ FinalRender,
35
+ SlotFn,
36
+ NativeReactType,
37
+ } from './component-patterns/render.types';
25
38
  export { withSlots } from './component-patterns/withSlots';
26
- export { stagedComponent } from './component-patterns/stagedComponent';
27
- export type { FinalRender, StagedRender, ComposableFunction } from './component-patterns/stagedComponent';
39
+ export { stagedComponent, twoStageComponent } from './component-patterns/stagedComponent';
40
+ export { jsx, jsxs } from './jsx-runtime';
@@ -0,0 +1,11 @@
1
+ import type React from 'react';
2
+ import * as ReactJSX from 'react/jsx-runtime';
3
+ import { renderForJsxRuntime } from './component-patterns/render';
4
+
5
+ export function jsx(type: React.ElementType, props: React.PropsWithChildren<unknown>, key?: React.Key): React.ReactElement {
6
+ return renderForJsxRuntime(type, props, key, ReactJSX.jsx);
7
+ }
8
+
9
+ export function jsxs(type: React.ElementType, props: React.PropsWithChildren<unknown>, key?: React.Key): React.ReactElement {
10
+ return renderForJsxRuntime(type, props, key, ReactJSX.jsxs);
11
+ }
@@ -0,0 +1,141 @@
1
+ # @fluentui-react-native/memo-cache
2
+
3
+ This package implements a hierarchical memoization cache using an API pattern that mimics the react.js useMemo hook. It also provides an implementation of traditional JavaScript memoization built using react style utility.
4
+
5
+ Memoization is an optimization pattern used when a discrete set of inputs, typically parameters to an expensive function, yield a deterministic output. In this case, if the inputs match a previous call, a cached result can be retrieved. This is typically implemented as a factory function, which wraps a function in a closure, adding implicit caching.
6
+
7
+ React.js provides a hook called `useMemo` which is shifts to a more explicit model, where the keys are listed explicitly. This allows more control over the inputs than the older pattern. It's worth mentioning that the react `useMemo` hook is not a global cache, it is attached to a given component instance and compares the current execution with the previous one.
8
+
9
+ ### When to Use This
10
+
11
+ This package can be beneficial in two scenarios:
12
+
13
+ #### Performance
14
+
15
+ If the routine to be memoized is expensive, then caching the results can boost performance. Note that cache lookups have cost themselves so memoizing a trivial function will likely be slower.
16
+
17
+ Also note that every additional key adds a level of depth to the hierarchical cache. This has expense and reduces the likelihood of data being already in the cache. Collapsing the inputs to a manageable set helps optimize this. For instance, if building a style from a theme definition pulls 8 values from a theme, it is more efficient to key the resulting object on the theme, than to key each property individually.
18
+
19
+ #### Object Identity
20
+
21
+ The other benefit to this pattern is maintaining object identity between subsequent calls. In react-native the object identity of the style property will sometimes be compared, even if the values within are identical, the shallow props compare will not see the objects as the same.
22
+
23
+ Similarly if a style is being turned into a CSS class (which is expensive), a `WeakMap` to map style objects to CSS classes will only work if the object identities are maintained.
24
+
25
+ ## Usage guide
26
+
27
+ The baseline cache pattern is defined by the following type:
28
+
29
+ ```ts
30
+ export type GetMemoValue<T, TGet = any> = (
31
+ factory: T | () => T,
32
+ keys: any[]
33
+ ) => [T, GetMemoValue<TGet>];
34
+ ```
35
+
36
+ The parameters are used as follows:
37
+
38
+ | Param | Description |
39
+ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
40
+ | `factory` | This is typically a function, often a simple closure, which returns a value. This value will be cached for a given set of keys. Subsequent calls will just return the value without executing the function. This can also be a value type in which case that will be returned directly. |
41
+ | `keys` | Variable parameter list, used as the keys for caching. Note that the order of keys matter. [A, B] resolves differently than [B, A]. |
42
+
43
+ The return result is a tuple with two elements containing:
44
+
45
+ - The result of the factory function, or the value of factory if it is not a function
46
+ - A function for caching which is local to the previous keys queried
47
+
48
+ This recursive calling pattern allows for a natural pipelining of caching and memoization. Because the cache is effectively implemented as a tree, this pattern falls out fairly easily. See the examples below for more detail.
49
+
50
+ ### getMemoCache
51
+
52
+ To get an instance of the memo cache to work with, a caller starts by calling `getMemoCache`.
53
+
54
+ ```ts
55
+ export function getMemoCache<T = any>(globalKey?: object): GetMemoValue<T>;
56
+ ```
57
+
58
+ This function takes an optional parameter `globalKey` which can be an object to use as a base cache reference.
59
+
60
+ - If `globalKey` is specified, the same cache will be retrieved from the global call with the same object reference.
61
+ - If `globalKey` is not specified the cache instance will be unique and contained entirely within the returned function.
62
+
63
+ ### memoize
64
+
65
+ This library also provides a standard memoization wrapper:
66
+
67
+ ```ts
68
+ export function memoize<T extends Function>(fn: T): T;
69
+ ```
70
+
71
+ This should be able to handle any function as an input. It will create its own instance of the cache, use any parameters to the function as key values, and return a closure with the same signature as the input.
72
+
73
+ This should support the following:
74
+
75
+ - Function with any number of parameters
76
+ - Functions with no parameters
77
+ - Any return result
78
+ - Void functions
79
+
80
+ ## Examples
81
+
82
+ The following are some examples for how to use the functions above for various optimizations.
83
+
84
+ ### Merge styles to ensure object identity does not change
85
+
86
+ Given a function to merge styles together, wrap it in a memoization helper to ensure object identities don't change. Then add a helper for ensuring a CSS rule exists for a set of styles.
87
+
88
+ ```ts
89
+ // standard function which will be memoized
90
+ function mergeStylesWorker(...cssStyles: CSSStyle[]): CSSStyle {
91
+ // do the work of merging multiple styles together to form a new CSS style
92
+ }
93
+
94
+ // exported function internally has a caching layer with memoize
95
+ export const mergeStyles = memoize(mergeStylesWorker);
96
+
97
+ // all-in-one authoring of memoized function, this one to turn a style into a CSS class, traditionally
98
+ // an expensive operation in browsers
99
+ export const createRuleForStyle = memoize((style: CSSStyle) => {
100
+ const className = // do the work of creating the rule
101
+ return className;
102
+ });
103
+ ```
104
+
105
+ ### Hierarchical Theme Caching
106
+
107
+ This demonstrates a component called `MyComponent` that:
108
+
109
+ 1. has a unique cache based on the component identity
110
+ 2. cached a style computed against a theme
111
+ 3. optionally merges a style from props and caches that result
112
+
113
+ These three levels of caching are effectively instance -> theme -> props.style.
114
+
115
+ ```ts
116
+ import { getMemoCache } from '@fluentui-react-native/memo-cache';
117
+
118
+ // get a unique cache for this component
119
+ const myComponentCache = getMemoCache();
120
+
121
+ // component is a function that takes props
122
+ export const MyComponent = (props: IMyComponentProps) => {
123
+ const theme = useContext(ThemeContext);
124
+ const newProps = { ...props };
125
+
126
+ // get the style, cached against the theme so it will only be called once, note that because
127
+ const [style, themeLocalCache] = myComponentCache(() => {
128
+ const colors = theme.colors;
129
+ return {
130
+ backgroundColor: colors.neutralBackground,
131
+ color: colors.neutralForeground,
132
+ // more stuff from theme
133
+ };
134
+ }, [theme]);
135
+
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;
138
+
139
+ return <InnerControl {...newProps} />;
140
+ };
141
+ ```
@@ -0,0 +1,43 @@
1
+ # @fluentui-react-native/merge-props
2
+
3
+ Utilities for merging styles and props (which contain styles)
4
+
5
+ ## Merging Props
6
+
7
+ The `mergeProps` routine handles merging props together. Generally this is a standard per property merge identical to the behavior of `Object.assign` with the following two exceptions:
8
+
9
+ - Objects under `props.style` will be merged using `mergeStyle` above, including caching the resolved styles
10
+ - Strings contained in `props.className` will be joined together using spaces as a delimiter.
11
+
12
+ ## Merging Styles
13
+
14
+ Styles are defined using the standard react-native pattern and will be merged in a way that maintains object identity where possible.
15
+
16
+ ### StyleProp
17
+
18
+ This is a copy of the StyleProp definition from `react-native`. This is copied primarily in the case where it is used in web code where adding a dependency on the `react-native` package itself is not desireable.
19
+
20
+ The StyleProp pattern itself is allows a style to be provided as a style or a recursive array of styles. So the following pattern is allowed:
21
+
22
+ ```ts
23
+ props = {
24
+ style: [{ ...style1 }, [{ ...style2 }, { ...style3 }, [{ ...style4 }]], { ...style5 }],
25
+ };
26
+ ```
27
+
28
+ In this model merging styles can be effectively deferred by the following:
29
+
30
+ ```ts
31
+ const styleToMerge = { ...values };
32
+ props.style = [props.style, styleToMerge];
33
+ ```
34
+
35
+ ### mergeStyles
36
+
37
+ This routine merges one or more react-native styles together. The inputs are styles in the `StyleProp` format referenced above. The various input styles will be flattened and merged together to produce a single non-flattened output style.
38
+
39
+ ```ts
40
+ function mergeStyles<T>(...styles: StyleProp<T>[]): T;
41
+ ```
42
+
43
+ This routine has a built-in caching layer that will attempt to ensure that object identity remains consistent. This means that style A + style B, where the references to A and B are the same, will always produce object C, where the reference will also be the same.
@@ -1,21 +0,0 @@
1
- import * as React from 'react';
2
- /**
3
- * Component slots have a marker which allows the slot render handler to know which ones are safe to call as a function.
4
- */
5
- export type SlotFn<TProps> = React.FunctionComponent<TProps> & {
6
- _canCompose?: boolean;
7
- };
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 = React.ElementType<any> | string;
13
- /**
14
- * Renders a slot
15
- *
16
- * @param slot - native react type or slot function to render
17
- * @param extraProps - additional props to mixin
18
- * @param children - the children to pass down to the slot
19
- */
20
- export declare function renderSlot<TProps>(slot: NativeReactType | SlotFn<TProps>, extraProps: TProps, ...children: React.ReactNode[]): React.ReactElement<any, any>;
21
- //# sourceMappingURL=renderSlot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderSlot.d.ts","sourceRoot":"","sources":["../../src/component-patterns/renderSlot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG;IAC7D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,gCAI5H"}
@@ -1,14 +0,0 @@
1
- import * as React from 'react';
2
- /**
3
- * Renders a slot
4
- *
5
- * @param slot - native react type or slot function to render
6
- * @param extraProps - additional props to mixin
7
- * @param children - the children to pass down to the slot
8
- */
9
- export function renderSlot(slot, extraProps, ...children) {
10
- return typeof slot === 'function' && slot._canCompose
11
- ? slot(extraProps, ...children)
12
- : React.createElement(slot, extraProps, ...children);
13
- }
14
- //# sourceMappingURL=renderSlot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderSlot.js","sourceRoot":"","sources":["../../src/component-patterns/renderSlot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAe/B;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAS,IAAsC,EAAE,UAAkB,EAAE,GAAG,QAA2B;IAC3H,OAAO,OAAO,IAAI,KAAK,UAAU,IAAK,IAAuB,CAAC,WAAW;QACvE,CAAC,CAAE,IAAuB,CAAC,UAAU,EAAE,GAAG,QAAQ,CAAC;QACnD,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC,CAAC;AACzD,CAAC"}
@@ -1,21 +0,0 @@
1
- import * as React from 'react';
2
- /**
3
- * Component slots have a marker which allows the slot render handler to know which ones are safe to call as a function.
4
- */
5
- export type SlotFn<TProps> = React.FunctionComponent<TProps> & {
6
- _canCompose?: boolean;
7
- };
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 = React.ElementType<any> | string;
13
- /**
14
- * Renders a slot
15
- *
16
- * @param slot - native react type or slot function to render
17
- * @param extraProps - additional props to mixin
18
- * @param children - the children to pass down to the slot
19
- */
20
- export declare function renderSlot<TProps>(slot: NativeReactType | SlotFn<TProps>, extraProps: TProps, ...children: React.ReactNode[]): React.ReactElement<any, any>;
21
- //# sourceMappingURL=renderSlot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderSlot.d.ts","sourceRoot":"","sources":["../../src/component-patterns/renderSlot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG;IAC7D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,gCAI5H"}
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.renderSlot = void 0;
4
- const tslib_1 = require("tslib");
5
- const React = tslib_1.__importStar(require("react"));
6
- /**
7
- * Renders a slot
8
- *
9
- * @param slot - native react type or slot function to render
10
- * @param extraProps - additional props to mixin
11
- * @param children - the children to pass down to the slot
12
- */
13
- function renderSlot(slot, extraProps, ...children) {
14
- return typeof slot === 'function' && slot._canCompose
15
- ? slot(extraProps, ...children)
16
- : React.createElement(slot, extraProps, ...children);
17
- }
18
- exports.renderSlot = renderSlot;
19
- //# sourceMappingURL=renderSlot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderSlot.js","sourceRoot":"","sources":["../../src/component-patterns/renderSlot.ts"],"names":[],"mappings":";;;;AAAA,qDAA+B;AAe/B;;;;;;GAMG;AACH,SAAgB,UAAU,CAAS,IAAsC,EAAE,UAAkB,EAAE,GAAG,QAA2B;IAC3H,OAAO,OAAO,IAAI,KAAK,UAAU,IAAK,IAAuB,CAAC,WAAW;QACvE,CAAC,CAAE,IAAuB,CAAC,UAAU,EAAE,GAAG,QAAQ,CAAC;QACnD,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC,CAAC;AACzD,CAAC;AAJD,gCAIC"}
@@ -1,27 +0,0 @@
1
- import * as React from 'react';
2
-
3
- /**
4
- * Component slots have a marker which allows the slot render handler to know which ones are safe to call as a function.
5
- */
6
- export type SlotFn<TProps> = React.FunctionComponent<TProps> & {
7
- _canCompose?: boolean;
8
- };
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 = React.ElementType<any> | string;
15
-
16
- /**
17
- * Renders a slot
18
- *
19
- * @param slot - native react type or slot function to render
20
- * @param extraProps - additional props to mixin
21
- * @param children - the children to pass down to the slot
22
- */
23
- export function renderSlot<TProps>(slot: NativeReactType | SlotFn<TProps>, extraProps: TProps, ...children: React.ReactNode[]) {
24
- return typeof slot === 'function' && (slot as SlotFn<TProps>)._canCompose
25
- ? (slot as SlotFn<TProps>)(extraProps, ...children)
26
- : React.createElement(slot, extraProps, ...children);
27
- }
@@ -1,53 +0,0 @@
1
- import * as React from 'react';
2
-
3
- /**
4
- * The final rendering of the props in a staged render. This is the function component signature that matches that of
5
- * React.createElement, children (if present) will be part of the variable args at the end.
6
- */
7
- export type FinalRender<TProps> = (props: TProps, ...children: React.ReactNode[]) => JSX.Element | null;
8
-
9
- /**
10
- * This is a pattern of rendering where a functional component can be executed in two stages rather than in a single pass.
11
- *
12
- * The pattern looks like:
13
- * (props) => {
14
- * // handle props
15
- * // call hooks, remember these can't be conditional
16
- * // build styles and props to pass to child components
17
- *
18
- * return (additionalProps, ...children) => {
19
- * // return the actual element tree, this includes conditional branching or rendering
20
- * // mixin additional props, props which require logic should be required in phase 1.
21
- *
22
- * // NOTE: This is where children will show up
23
- * };
24
- * }
25
- */
26
-
27
- export type StagedRender<TProps> = (props: TProps, ...args: any[]) => FinalRender<TProps>;
28
-
29
- /**
30
- * A composable function may have a two stage render function as an attached property. This allows the function to work
31
- * in all the standard react flows, but allows for pulling out the staged render when components understand it.
32
- */
33
- export type ComposableFunction<TProps> = React.FunctionComponent<TProps> & { _staged?: StagedRender<TProps> };
34
-
35
- function asArray<T>(val: T | T[]): T[] {
36
- return Array.isArray(val) ? val : [val];
37
- }
38
-
39
- /**
40
- * Take a staged render function and make a real component out of it
41
- *
42
- * @param staged - staged render function to wrap into a staged component
43
- * @param memo - optional flag to enable wrapping the created component in a React.memo HOC
44
- */
45
- export function stagedComponent<TProps>(staged: StagedRender<TProps>, memo?: boolean): ComposableFunction<TProps> {
46
- const component = (props: React.PropsWithChildren<TProps>) => {
47
- const { children, ...rest } = props;
48
- return staged(rest as TProps)({} as React.PropsWithChildren<TProps>, asArray(children));
49
- };
50
- const stagedComponent = memo ? React.memo(component) : component;
51
- Object.assign(stagedComponent, { _staged: staged });
52
- return stagedComponent as ComposableFunction<TProps>;
53
- }