@fluentui-react-native/composition 0.6.9

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.
@@ -0,0 +1,49 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`composeFactory test suite Base component render 1`] = `
4
+ <View
5
+ style={
6
+ Object {
7
+ "backgroundColor": "black",
8
+ "borderColor": "green",
9
+ "borderWidth": 1,
10
+ "height": 20,
11
+ "width": 30,
12
+ }
13
+ }
14
+ >
15
+ <Text
16
+ style={
17
+ Object {
18
+ "color": "white",
19
+ }
20
+ }
21
+ >
22
+ Hello
23
+ </Text>
24
+ </View>
25
+ `;
26
+
27
+ exports[`composeFactory test suite Base component render 2`] = `
28
+ <View
29
+ style={
30
+ Object {
31
+ "backgroundColor": "pink",
32
+ "borderColor": "green",
33
+ "borderWidth": 1,
34
+ "height": 20,
35
+ "width": 30,
36
+ }
37
+ }
38
+ >
39
+ <Text
40
+ style={
41
+ Object {
42
+ "color": "white",
43
+ }
44
+ }
45
+ >
46
+ Hello
47
+ </Text>
48
+ </View>
49
+ `;
@@ -0,0 +1,94 @@
1
+ /** @jsx withSlots */
2
+ import { withSlots } from '@fluentui-react-native/use-slot';
3
+ import * as renderer from 'react-test-renderer';
4
+ import { composeFactory, UseStyledSlots } from './composeFactory';
5
+ import { ViewProps, View, Text, TextProps, ColorValue } from 'react-native';
6
+ import { ThemeHelper } from '@fluentui-react-native/use-styling';
7
+
8
+ type Theme = {
9
+ values: {
10
+ backgroundColor?: ColorValue;
11
+ color?: ColorValue;
12
+ };
13
+ components: {
14
+ [key: string]: object;
15
+ };
16
+ };
17
+
18
+ const theme: Theme = {
19
+ values: {
20
+ backgroundColor: 'black',
21
+ color: 'white',
22
+ },
23
+ components: {},
24
+ };
25
+
26
+ type SlotProps = {
27
+ outer: ViewProps;
28
+ content: TextProps;
29
+ };
30
+
31
+ type Tokens = {
32
+ backgroundColor?: ColorValue;
33
+ color?: ColorValue;
34
+ };
35
+
36
+ const themeHelper: ThemeHelper<Theme> = {
37
+ useTheme: () => theme,
38
+ getComponentInfo: (theme: Theme, name: string) => {
39
+ return theme?.components ?? theme.components[name];
40
+ },
41
+ };
42
+
43
+ function mergeProps<T>(p1: T, p2: T): T {
44
+ return { ...p1, ...p2 };
45
+ }
46
+
47
+ const Base = composeFactory<ViewProps, SlotProps, Tokens, Theme>(
48
+ {
49
+ tokens: [
50
+ (t) => ({
51
+ backgroundColor: t.values.backgroundColor,
52
+ color: t.values.color,
53
+ }),
54
+ ],
55
+ slotProps: {
56
+ outer: (tokens) => ({ style: { backgroundColor: tokens.backgroundColor } }),
57
+ content: (tokens) => ({ style: { color: tokens.color } }),
58
+ },
59
+ slots: {
60
+ outer: View,
61
+ content: Text,
62
+ },
63
+ render: (props: ViewProps, useSlots: UseStyledSlots<ViewProps, SlotProps>) => {
64
+ const Slots = useSlots(props);
65
+ return (extra: ViewProps) => (
66
+ <Slots.outer {...mergeProps(props, extra)}>
67
+ <Slots.content>Hello</Slots.content>
68
+ </Slots.outer>
69
+ );
70
+ },
71
+ },
72
+ themeHelper,
73
+ );
74
+
75
+ const Customized = Base.customize({ backgroundColor: 'pink' });
76
+
77
+ const mixinStyle = {
78
+ width: 30,
79
+ height: 20,
80
+ borderColor: 'green',
81
+ borderWidth: 1,
82
+ };
83
+
84
+ describe('composeFactory test suite', () => {
85
+ it('Base component render', () => {
86
+ const tree = renderer.create(<Base style={mixinStyle} />).toJSON();
87
+ expect(tree).toMatchSnapshot();
88
+ });
89
+
90
+ it('Base component render', () => {
91
+ const tree = renderer.create(<Customized style={mixinStyle} />).toJSON();
92
+ expect(tree).toMatchSnapshot();
93
+ });
94
+ });
@@ -0,0 +1,90 @@
1
+ import { UseStylingOptions, TokenSettings, ThemeHelper, HasLayer, buildUseStyling } from '@fluentui-react-native/use-styling';
2
+ import { ComposableFunction, stagedComponent } from '@fluentui-react-native/use-slot';
3
+ import { UseSlotOptions, buildUseSlots, Slots } from '@fluentui-react-native/use-slots';
4
+ import { immutableMergeCore, MergeOptions } from '@fluentui-react-native/immutable-merge';
5
+
6
+ export type UseStyledSlots<TProps, TSlotProps> = (props: TProps, lookup?: HasLayer) => Slots<TSlotProps>;
7
+
8
+ export type ComposeFactoryOptions<TProps, TSlotProps, TTokens, TTheme, TStatics extends object = object> = UseStylingOptions<
9
+ TProps,
10
+ TSlotProps,
11
+ TTokens,
12
+ TTheme
13
+ > &
14
+ UseSlotOptions<TSlotProps> & {
15
+ /**
16
+ * Includes from UseStylingOptions:
17
+ *
18
+ */
19
+ displayName?: string;
20
+
21
+ /**
22
+ * staged render function that takes props and a useSlots hook as an input
23
+ */
24
+ render: (props: TProps, useSlots: UseStyledSlots<TProps, TSlotProps>) => React.FunctionComponent<TProps>;
25
+
26
+ /**
27
+ * optional statics to attach to the component
28
+ */
29
+ statics?: TStatics;
30
+ };
31
+
32
+ export type ComposeFactoryComponent<TProps, TSlotProps, TTokens, TTheme, TStatics extends object = object> = ComposableFunction<TProps> & {
33
+ __options: ComposeFactoryOptions<TProps, TSlotProps, TTokens, TTheme, TStatics>;
34
+ customize: (...tokens: TokenSettings<TTokens, TTheme>[]) => ComposeFactoryComponent<TProps, TSlotProps, TTokens, TTheme, TStatics>;
35
+ compose: (
36
+ options: Partial<ComposeFactoryOptions<TProps, TSlotProps, TTokens, TTheme, TStatics>>,
37
+ ) => ComposeFactoryComponent<TProps, TSlotProps, TTokens, TTheme, TStatics>;
38
+ } & TStatics;
39
+
40
+ /**
41
+ * options get deep merged except the tokens array gets appended
42
+ */
43
+ const mergeOptions: MergeOptions = {
44
+ tokens: 'appendArray',
45
+ object: true,
46
+ };
47
+
48
+ export function composeFactory<TProps, TSlotProps, TTokens, TTheme, TStatics extends object = object>(
49
+ options: ComposeFactoryOptions<TProps, TSlotProps, TTokens, TTheme, TStatics>,
50
+ themeHelper: ThemeHelper<TTheme>,
51
+ base?: ComposeFactoryComponent<TProps, TSlotProps, TTokens, TTheme, TStatics>,
52
+ ): ComposeFactoryComponent<TProps, TSlotProps, TTokens, TTheme, TStatics> {
53
+ type LocalComponent = ComposeFactoryComponent<TProps, TSlotProps, TTokens, TTheme, TStatics>;
54
+ type LocalOptions = ComposeFactoryOptions<TProps, TSlotProps, TTokens, TTheme, TStatics>;
55
+
56
+ // merge options together if a base is specified
57
+ const baseOptions: LocalOptions = base?.__options as LocalOptions;
58
+ options = baseOptions ? immutableMergeCore<LocalOptions>(mergeOptions, baseOptions, options) : { ...options };
59
+
60
+ // build styling if styling options are specified
61
+ options.useStyling = options.slotProps || options.tokens ? buildUseStyling(options, themeHelper) : () => ({} as TSlotProps);
62
+
63
+ // build the slots hook, which will use the styling hook if it has been built
64
+ const useSlots = buildUseSlots(options) as UseStyledSlots<TProps, TSlotProps>;
65
+
66
+ // build the staged component
67
+ const component = stagedComponent<TProps>((props) => options.render(props, useSlots)) as LocalComponent;
68
+
69
+ // attach additional props to the returned component
70
+ component.displayName = options.displayName;
71
+ component.__options = options;
72
+ component.customize = (...tokens: LocalOptions['tokens']) =>
73
+ composeFactory<TProps, TSlotProps, TTokens, TTheme, TStatics>(
74
+ immutableMergeCore(mergeOptions, options, { tokens: tokens } as LocalOptions),
75
+ themeHelper,
76
+ );
77
+
78
+ component.compose = (customOptions: Partial<LocalOptions>) =>
79
+ composeFactory<TProps, TSlotProps, TTokens, TTheme, TStatics>(
80
+ immutableMergeCore(mergeOptions, options, customOptions) as LocalOptions,
81
+ themeHelper,
82
+ );
83
+
84
+ // attach statics if specified
85
+ if (options.statics) {
86
+ Object.assign(component, options.statics);
87
+ }
88
+
89
+ return component;
90
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './composeFactory';