@idealyst/components 1.1.6 → 1.1.8
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/package.json +8 -3
- package/src/Accordion/Accordion.native.tsx +22 -14
- package/src/Accordion/Accordion.styles.old.tsx +298 -0
- package/src/Accordion/Accordion.styles.tsx +139 -248
- package/src/Accordion/Accordion.web.tsx +12 -7
- package/src/ActivityIndicator/ActivityIndicator.native.tsx +3 -2
- package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
- package/src/ActivityIndicator/ActivityIndicator.styles.tsx +43 -62
- package/src/ActivityIndicator/ActivityIndicator.web.tsx +2 -2
- package/src/Alert/Alert.native.tsx +26 -15
- package/src/Alert/Alert.styles.old.tsx +209 -0
- package/src/Alert/Alert.styles.tsx +108 -281
- package/src/Alert/Alert.web.tsx +6 -10
- package/src/Avatar/Avatar.native.tsx +5 -2
- package/src/Avatar/Avatar.styles.old.tsx +99 -0
- package/src/Avatar/Avatar.styles.tsx +47 -62
- package/src/Avatar/Avatar.web.tsx +2 -2
- package/src/Badge/Badge.native.tsx +2 -2
- package/src/Badge/Badge.styles.old.tsx +157 -0
- package/src/Badge/Badge.styles.tsx +69 -108
- package/src/Badge/Badge.web.tsx +6 -6
- package/src/Breadcrumb/Breadcrumb.native.tsx +12 -5
- package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
- package/src/Breadcrumb/Breadcrumb.styles.tsx +93 -209
- package/src/Breadcrumb/Breadcrumb.web.tsx +39 -27
- package/src/Button/Button.native.tsx +39 -14
- package/src/Button/Button.styles.tsx +99 -253
- package/src/Button/Button.web.tsx +10 -8
- package/src/Card/Card.native.tsx +8 -4
- package/src/Card/Card.styles.old.tsx +160 -0
- package/src/Card/Card.styles.tsx +107 -142
- package/src/Card/Card.web.tsx +6 -4
- package/src/Checkbox/Checkbox.native.tsx +14 -6
- package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
- package/src/Checkbox/Checkbox.styles.tsx +109 -197
- package/src/Checkbox/Checkbox.web.tsx +7 -7
- package/src/Chip/Chip.native.tsx +5 -5
- package/src/Chip/Chip.styles.old.tsx +184 -0
- package/src/Chip/Chip.styles.tsx +34 -22
- package/src/Chip/Chip.web.tsx +5 -5
- package/src/Dialog/Dialog.native.tsx +16 -7
- package/src/Dialog/Dialog.styles.old.tsx +202 -0
- package/src/Dialog/Dialog.styles.tsx +108 -132
- package/src/Dialog/Dialog.web.tsx +4 -4
- package/src/Divider/Divider.native.tsx +29 -42
- package/src/Divider/Divider.styles.old.tsx +172 -0
- package/src/Divider/Divider.styles.tsx +116 -242
- package/src/Divider/Divider.web.tsx +17 -14
- package/src/Icon/Icon.native.tsx +12 -4
- package/src/Icon/Icon.styles.old.tsx +81 -0
- package/src/Icon/Icon.styles.tsx +52 -60
- package/src/Icon/Icon.web.tsx +43 -7
- package/src/Icon/IconSvg/IconSvg.web.tsx +2 -0
- package/src/Image/Image.styles.old.tsx +69 -0
- package/src/Image/Image.styles.tsx +45 -43
- package/src/Input/Input.native.tsx +140 -56
- package/src/Input/Input.styles.old.tsx +289 -0
- package/src/Input/Input.styles.tsx +177 -228
- package/src/Input/Input.web.tsx +5 -8
- package/src/Link/Link.native.tsx +4 -1
- package/src/List/List.native.tsx +5 -2
- package/src/List/List.styles.old.tsx +242 -0
- package/src/List/List.styles.tsx +178 -240
- package/src/List/ListItem.native.tsx +16 -8
- package/src/List/ListItem.web.tsx +26 -15
- package/src/Menu/Menu.native.tsx +1 -1
- package/src/Menu/Menu.styles.old.tsx +197 -0
- package/src/Menu/Menu.styles.tsx +90 -156
- package/src/Menu/Menu.web.tsx +2 -2
- package/src/Menu/MenuItem.native.tsx +9 -5
- package/src/Menu/MenuItem.styles.old.tsx +114 -0
- package/src/Menu/MenuItem.styles.tsx +71 -104
- package/src/Menu/MenuItem.web.tsx +23 -5
- package/src/Popover/Popover.native.tsx +10 -4
- package/src/Popover/Popover.styles.old.tsx +135 -0
- package/src/Popover/Popover.styles.tsx +46 -96
- package/src/Popover/Popover.web.tsx +1 -1
- package/src/Pressable/Pressable.native.tsx +3 -1
- package/src/Pressable/Pressable.styles.old.tsx +27 -0
- package/src/Pressable/Pressable.styles.tsx +35 -20
- package/src/Pressable/Pressable.web.tsx +1 -1
- package/src/Progress/Progress.native.tsx +15 -6
- package/src/Progress/Progress.styles.old.tsx +200 -0
- package/src/Progress/Progress.styles.tsx +69 -118
- package/src/Progress/Progress.web.tsx +10 -9
- package/src/RadioButton/RadioButton.native.tsx +10 -4
- package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
- package/src/RadioButton/RadioButton.styles.tsx +81 -145
- package/src/RadioButton/RadioButton.web.tsx +4 -4
- package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
- package/src/SVGImage/SVGImage.styles.tsx +35 -66
- package/src/Screen/Screen.native.tsx +30 -27
- package/src/Screen/Screen.styles.old.tsx +87 -0
- package/src/Screen/Screen.styles.tsx +120 -71
- package/src/Screen/Screen.web.tsx +2 -2
- package/src/Select/Select.native.tsx +44 -29
- package/src/Select/Select.styles.old.tsx +353 -0
- package/src/Select/Select.styles.tsx +244 -293
- package/src/Select/Select.web.tsx +5 -5
- package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
- package/src/Skeleton/Skeleton.styles.tsx +31 -43
- package/src/Slider/Slider.native.tsx +9 -5
- package/src/Slider/Slider.styles.old.tsx +259 -0
- package/src/Slider/Slider.styles.tsx +157 -227
- package/src/Slider/Slider.web.tsx +5 -5
- package/src/Switch/Switch.native.tsx +11 -5
- package/src/Switch/Switch.styles.old.tsx +203 -0
- package/src/Switch/Switch.styles.tsx +103 -149
- package/src/Switch/Switch.web.tsx +8 -8
- package/src/TabBar/TabBar.native.tsx +24 -31
- package/src/TabBar/TabBar.styles.old.tsx +343 -0
- package/src/TabBar/TabBar.styles.tsx +204 -494
- package/src/TabBar/TabBar.web.tsx +21 -33
- package/src/Table/Table.native.tsx +18 -9
- package/src/Table/Table.styles.old.tsx +311 -0
- package/src/Table/Table.styles.tsx +151 -278
- package/src/Table/Table.web.tsx +1 -1
- package/src/Text/Text.native.tsx +1 -4
- package/src/Text/Text.style.demo.tsx +16 -0
- package/src/Text/Text.styles.old.tsx +219 -0
- package/src/Text/Text.styles.tsx +94 -78
- package/src/Text/Text.web.tsx +2 -2
- package/src/Text/index.ts +1 -0
- package/src/TextArea/TextArea.styles.old.tsx +213 -0
- package/src/TextArea/TextArea.styles.tsx +101 -157
- package/src/Tooltip/Tooltip.native.tsx +2 -2
- package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
- package/src/Tooltip/Tooltip.styles.tsx +38 -53
- package/src/Tooltip/Tooltip.web.tsx +2 -2
- package/src/Video/Video.styles.old.tsx +51 -0
- package/src/Video/Video.styles.tsx +32 -28
- package/src/View/View.native.tsx +12 -12
- package/src/View/View.styles.old.tsx +125 -0
- package/src/View/View.styles.tsx +84 -103
- package/src/View/View.web.tsx +14 -2
- package/src/examples/CardExamples.tsx +0 -6
- package/src/extensions/applyExtension.ts +210 -0
- package/src/extensions/extendComponent.ts +438 -0
- package/src/extensions/index.ts +102 -0
- package/src/extensions/types.ts +497 -0
- package/src/globals.ts +16 -0
- package/src/index.native.ts +4 -0
- package/src/index.ts +28 -0
- package/src/utils/deepMerge.ts +54 -2
package/src/View/View.native.tsx
CHANGED
|
@@ -26,6 +26,7 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
|
26
26
|
testID,
|
|
27
27
|
id,
|
|
28
28
|
}, ref) => {
|
|
29
|
+
// Set active variants for this render
|
|
29
30
|
viewStyles.useVariants({
|
|
30
31
|
background,
|
|
31
32
|
radius,
|
|
@@ -39,23 +40,22 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
|
39
40
|
marginHorizontal,
|
|
40
41
|
});
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
// Call style as function to get theme-reactive styles
|
|
44
|
+
const viewStyle = (viewStyles.view as any)({});
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
46
|
+
// Override styles for direct prop values
|
|
47
|
+
const overrideStyles: ViewStyle = {};
|
|
48
|
+
if (backgroundColor) overrideStyles.backgroundColor = backgroundColor;
|
|
49
|
+
if (borderRadius !== undefined) overrideStyles.borderRadius = borderRadius;
|
|
50
|
+
if (borderWidth !== undefined) overrideStyles.borderWidth = borderWidth;
|
|
51
|
+
if (borderColor) overrideStyles.borderColor = borderColor;
|
|
52
52
|
|
|
53
53
|
if (scrollable) {
|
|
54
54
|
return (
|
|
55
55
|
<RNScrollView
|
|
56
56
|
ref={ref as any}
|
|
57
|
-
style={[{ flex: 1 }, style]}
|
|
58
|
-
contentContainerStyle={[
|
|
57
|
+
style={[viewStyle, { flex: 1 }, overrideStyles, style]}
|
|
58
|
+
contentContainerStyle={[viewStyle, overrideStyles]}
|
|
59
59
|
testID={testID}
|
|
60
60
|
nativeID={id}
|
|
61
61
|
>
|
|
@@ -65,7 +65,7 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
return (
|
|
68
|
-
<RNView ref={ref as any} style={[
|
|
68
|
+
<RNView ref={ref as any} style={[viewStyle, overrideStyles, style]} testID={testID} nativeID={id}>
|
|
69
69
|
{children}
|
|
70
70
|
</RNView>
|
|
71
71
|
);
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
+
import { Theme, StylesheetStyles, Surface } from '@idealyst/theme';
|
|
3
|
+
import {
|
|
4
|
+
buildGapVariants,
|
|
5
|
+
buildPaddingVariants,
|
|
6
|
+
buildPaddingVerticalVariants,
|
|
7
|
+
buildPaddingHorizontalVariants,
|
|
8
|
+
buildMarginVariants,
|
|
9
|
+
buildMarginVerticalVariants,
|
|
10
|
+
buildMarginHorizontalVariants,
|
|
11
|
+
} from '../utils/buildViewStyleVariants';
|
|
12
|
+
import { ViewBackgroundVariant, ViewBorderVariant, ViewRadiusVariant } from './types';
|
|
13
|
+
import { ViewStyleSize } from '../utils/viewStyleProps';
|
|
14
|
+
import { applyExtensions } from '../extensions/applyExtension';
|
|
15
|
+
|
|
16
|
+
type ViewVariants = {
|
|
17
|
+
background: ViewBackgroundVariant;
|
|
18
|
+
radius: ViewRadiusVariant;
|
|
19
|
+
border: ViewBorderVariant;
|
|
20
|
+
gap: ViewStyleSize;
|
|
21
|
+
padding: ViewStyleSize;
|
|
22
|
+
paddingVertical: ViewStyleSize;
|
|
23
|
+
paddingHorizontal: ViewStyleSize;
|
|
24
|
+
margin: ViewStyleSize;
|
|
25
|
+
marginVertical: ViewStyleSize;
|
|
26
|
+
marginHorizontal: ViewStyleSize;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type ExpandedViewStyles = StylesheetStyles<keyof ViewVariants>;
|
|
30
|
+
|
|
31
|
+
export type ViewStylesheet = {
|
|
32
|
+
view: ExpandedViewStyles;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create background variants for view
|
|
37
|
+
*/
|
|
38
|
+
function createBackgroundVariants(theme: Theme) {
|
|
39
|
+
const variants: any = {
|
|
40
|
+
transparent: {
|
|
41
|
+
backgroundColor: 'transparent',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Add all surface colors programmatically
|
|
46
|
+
for (const surface in theme.colors.surface) {
|
|
47
|
+
variants[surface] = {
|
|
48
|
+
backgroundColor: theme.colors.surface[surface as Surface],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return variants;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create radius variants for view
|
|
57
|
+
*/
|
|
58
|
+
function createRadiusVariants() {
|
|
59
|
+
return {
|
|
60
|
+
none: { borderRadius: 0 },
|
|
61
|
+
xs: { borderRadius: 2 },
|
|
62
|
+
sm: { borderRadius: 4 },
|
|
63
|
+
md: { borderRadius: 8 },
|
|
64
|
+
lg: { borderRadius: 12 },
|
|
65
|
+
xl: { borderRadius: 16 },
|
|
66
|
+
} as const;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create border variants for view
|
|
71
|
+
*/
|
|
72
|
+
function createBorderVariants(theme: Theme) {
|
|
73
|
+
return {
|
|
74
|
+
none: {
|
|
75
|
+
borderWidth: 0,
|
|
76
|
+
},
|
|
77
|
+
thin: {
|
|
78
|
+
borderWidth: 1,
|
|
79
|
+
borderStyle: 'solid',
|
|
80
|
+
borderColor: theme.colors['gray.300'],
|
|
81
|
+
},
|
|
82
|
+
thick: {
|
|
83
|
+
borderWidth: 2,
|
|
84
|
+
borderStyle: 'solid',
|
|
85
|
+
borderColor: theme.colors['gray.300'],
|
|
86
|
+
},
|
|
87
|
+
} as const;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create dynamic view styles.
|
|
92
|
+
* Returns a function to ensure Unistyles can track theme changes.
|
|
93
|
+
* All styles must be dynamic functions (not static objects) to work with
|
|
94
|
+
* Unistyles' Babel transform and theme reactivity on native.
|
|
95
|
+
*/
|
|
96
|
+
function createViewStyles(theme: Theme) {
|
|
97
|
+
return (_props?: {}) => ({
|
|
98
|
+
display: 'flex' as const,
|
|
99
|
+
variants: {
|
|
100
|
+
background: createBackgroundVariants(theme),
|
|
101
|
+
radius: createRadiusVariants(),
|
|
102
|
+
border: createBorderVariants(theme),
|
|
103
|
+
gap: buildGapVariants(theme),
|
|
104
|
+
padding: buildPaddingVariants(theme),
|
|
105
|
+
paddingVertical: buildPaddingVerticalVariants(theme),
|
|
106
|
+
paddingHorizontal: buildPaddingHorizontalVariants(theme),
|
|
107
|
+
margin: buildMarginVariants(theme),
|
|
108
|
+
marginVertical: buildMarginVerticalVariants(theme),
|
|
109
|
+
marginHorizontal: buildMarginHorizontalVariants(theme),
|
|
110
|
+
},
|
|
111
|
+
_web: {
|
|
112
|
+
display: 'flex',
|
|
113
|
+
flexDirection: 'column',
|
|
114
|
+
boxSizing: 'border-box',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Styles use applyExtensions to enable theme extensions and ensure proper
|
|
120
|
+
// reactivity with Unistyles' native Shadow Tree updates.
|
|
121
|
+
export const viewStyles = StyleSheet.create((theme: Theme) => {
|
|
122
|
+
return applyExtensions('View', theme, {
|
|
123
|
+
view: createViewStyles(theme),
|
|
124
|
+
});
|
|
125
|
+
});
|
package/src/View/View.styles.tsx
CHANGED
|
@@ -1,114 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View styles using defineStyle with $iterator expansion.
|
|
3
|
+
*/
|
|
1
4
|
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
buildGapVariants,
|
|
5
|
-
buildPaddingVariants,
|
|
6
|
-
buildPaddingVerticalVariants,
|
|
7
|
-
buildPaddingHorizontalVariants,
|
|
8
|
-
buildMarginVariants,
|
|
9
|
-
buildMarginVerticalVariants,
|
|
10
|
-
buildMarginHorizontalVariants,
|
|
11
|
-
} from '../utils/buildViewStyleVariants';
|
|
5
|
+
import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
|
|
6
|
+
import type { Theme as BaseTheme } from '@idealyst/theme';
|
|
12
7
|
import { ViewBackgroundVariant, ViewBorderVariant, ViewRadiusVariant } from './types';
|
|
13
8
|
import { ViewStyleSize } from '../utils/viewStyleProps';
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
radius: ViewRadiusVariant;
|
|
18
|
-
border: ViewBorderVariant;
|
|
19
|
-
gap: ViewStyleSize;
|
|
20
|
-
padding: ViewStyleSize;
|
|
21
|
-
paddingVertical: ViewStyleSize;
|
|
22
|
-
paddingHorizontal: ViewStyleSize;
|
|
23
|
-
margin: ViewStyleSize;
|
|
24
|
-
marginVertical: ViewStyleSize;
|
|
25
|
-
marginHorizontal: ViewStyleSize;
|
|
26
|
-
};
|
|
10
|
+
// Required: Unistyles must see StyleSheet usage in original source to process this file
|
|
11
|
+
void StyleSheet;
|
|
27
12
|
|
|
28
|
-
|
|
13
|
+
// Wrap theme for $iterator support
|
|
14
|
+
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
29
15
|
|
|
30
|
-
export type
|
|
31
|
-
|
|
16
|
+
export type ViewVariants = {
|
|
17
|
+
background: ViewBackgroundVariant;
|
|
18
|
+
radius: ViewRadiusVariant;
|
|
19
|
+
border: ViewBorderVariant;
|
|
20
|
+
gap: ViewStyleSize;
|
|
21
|
+
padding: ViewStyleSize;
|
|
22
|
+
paddingVertical: ViewStyleSize;
|
|
23
|
+
paddingHorizontal: ViewStyleSize;
|
|
24
|
+
margin: ViewStyleSize;
|
|
25
|
+
marginVertical: ViewStyleSize;
|
|
26
|
+
marginHorizontal: ViewStyleSize;
|
|
32
27
|
};
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
* Create background variants for view
|
|
36
|
-
*/
|
|
37
|
-
function createBackgroundVariants(theme: Theme) {
|
|
38
|
-
const variants: any = {
|
|
39
|
-
transparent: {
|
|
40
|
-
backgroundColor: 'transparent',
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// Add all surface colors programmatically
|
|
45
|
-
for (const surface in theme.colors.surface) {
|
|
46
|
-
variants[surface] = {
|
|
47
|
-
backgroundColor: theme.colors.surface[surface as Surface],
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return variants;
|
|
52
|
-
}
|
|
29
|
+
export type ViewDynamicProps = Partial<ViewVariants>;
|
|
53
30
|
|
|
54
31
|
/**
|
|
55
|
-
*
|
|
32
|
+
* View styles with $iterator expansion for spacing variants.
|
|
33
|
+
*
|
|
34
|
+
* NOTE: At least one top-level theme access is required for Unistyles to trace
|
|
35
|
+
* theme dependencies. We use a transparent borderColor as a marker.
|
|
56
36
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
})
|
|
37
|
+
export const viewStyles = defineStyle('View', (theme: Theme) => ({
|
|
38
|
+
view: (_props: ViewDynamicProps) => ({
|
|
39
|
+
display: 'flex' as const,
|
|
40
|
+
// Theme marker for Unistyles reactivity (invisible, overridden by variants)
|
|
41
|
+
borderColor: theme.colors.border.primary,
|
|
42
|
+
borderWidth: 0,
|
|
43
|
+
variants: {
|
|
44
|
+
background: {
|
|
45
|
+
transparent: { backgroundColor: 'transparent' },
|
|
46
|
+
primary: { backgroundColor: theme.colors.surface.primary },
|
|
47
|
+
secondary: { backgroundColor: theme.colors.surface.secondary },
|
|
48
|
+
tertiary: { backgroundColor: theme.colors.surface.tertiary },
|
|
49
|
+
inverse: { backgroundColor: theme.colors.surface.inverse },
|
|
50
|
+
'inverse-secondary': { backgroundColor: theme.colors.surface['inverse-secondary'] },
|
|
51
|
+
'inverse-tertiary': { backgroundColor: theme.colors.surface['inverse-tertiary'] },
|
|
52
|
+
},
|
|
53
|
+
radius: {
|
|
54
|
+
none: { borderRadius: 0 },
|
|
55
|
+
xs: { borderRadius: 2 },
|
|
56
|
+
sm: { borderRadius: 4 },
|
|
57
|
+
md: { borderRadius: 8 },
|
|
58
|
+
lg: { borderRadius: 12 },
|
|
59
|
+
xl: { borderRadius: 16 },
|
|
60
|
+
},
|
|
61
|
+
border: {
|
|
62
|
+
none: { borderWidth: 0 },
|
|
63
|
+
thin: { borderWidth: 1, borderStyle: 'solid' as const, borderColor: theme.colors['gray.300'] },
|
|
64
|
+
thick: { borderWidth: 2, borderStyle: 'solid' as const, borderColor: theme.colors['gray.300'] },
|
|
65
|
+
},
|
|
66
|
+
// $iterator expands for each view size
|
|
67
|
+
gap: {
|
|
68
|
+
gap: theme.sizes.$view.spacing,
|
|
69
|
+
},
|
|
70
|
+
padding: {
|
|
71
|
+
padding: theme.sizes.$view.padding,
|
|
72
|
+
},
|
|
73
|
+
paddingVertical: {
|
|
74
|
+
paddingVertical: theme.sizes.$view.padding,
|
|
75
|
+
},
|
|
76
|
+
paddingHorizontal: {
|
|
77
|
+
paddingHorizontal: theme.sizes.$view.padding,
|
|
78
|
+
},
|
|
79
|
+
margin: {
|
|
80
|
+
margin: theme.sizes.$view.padding,
|
|
81
|
+
},
|
|
82
|
+
marginVertical: {
|
|
83
|
+
marginVertical: theme.sizes.$view.padding,
|
|
84
|
+
},
|
|
85
|
+
marginHorizontal: {
|
|
86
|
+
marginHorizontal: theme.sizes.$view.padding,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
_web: {
|
|
90
|
+
display: 'flex',
|
|
91
|
+
flexDirection: 'column',
|
|
92
|
+
boxSizing: 'border-box',
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
}));
|
package/src/View/View.web.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { forwardRef } from 'react';
|
|
1
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
2
3
|
import { getWebProps } from 'react-native-unistyles/web';
|
|
3
4
|
import { ViewProps } from './types';
|
|
4
5
|
import { viewStyles } from './View.styles';
|
|
@@ -48,13 +49,24 @@ const View = forwardRef<HTMLDivElement, ViewProps>(({
|
|
|
48
49
|
if (borderWidth !== undefined) dynamicStyles.borderWidth = borderWidth;
|
|
49
50
|
if (borderColor) dynamicStyles.borderColor = borderColor;
|
|
50
51
|
|
|
52
|
+
// Flatten style array to object (HTML divs don't support style arrays)
|
|
53
|
+
const flattenedStyle = useMemo(() => {
|
|
54
|
+
if (!style) return undefined;
|
|
55
|
+
if (Array.isArray(style)) {
|
|
56
|
+
return StyleSheet.flatten(style);
|
|
57
|
+
}
|
|
58
|
+
return style;
|
|
59
|
+
}, [style]);
|
|
60
|
+
|
|
61
|
+
// Call style as function to get theme-reactive styles
|
|
51
62
|
/** @ts-ignore */
|
|
52
|
-
const webProps = getWebProps([viewStyles.view
|
|
63
|
+
const webProps = getWebProps([(viewStyles.view as any)({}), dynamicStyles]);
|
|
53
64
|
|
|
54
65
|
const mergedRef = useMergeRefs(ref, webProps.ref);
|
|
55
66
|
|
|
56
67
|
return (
|
|
57
68
|
<div
|
|
69
|
+
style={flattenedStyle as any}
|
|
58
70
|
{...webProps}
|
|
59
71
|
ref={mergedRef}
|
|
60
72
|
id={id}
|
|
@@ -17,12 +17,6 @@ export const CardExamples = () => {
|
|
|
17
17
|
<View gap="md">
|
|
18
18
|
<Text typography="subtitle1">Variants</Text>
|
|
19
19
|
<View gap="sm" style={{ gap: 10 }}>
|
|
20
|
-
<Card type="default" padding="md">
|
|
21
|
-
<Text>Default Card</Text>
|
|
22
|
-
<Text typography="caption" color="secondary">
|
|
23
|
-
This is a default card with standard styling
|
|
24
|
-
</Text>
|
|
25
|
-
</Card>
|
|
26
20
|
|
|
27
21
|
<Card type="outlined" padding="md">
|
|
28
22
|
<Text>Outlined Card</Text>
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { deepMerge } from '../utils/deepMerge';
|
|
2
|
+
import { Styles, ElementStyle, ComponentName } from './types';
|
|
3
|
+
import { getExtension, getReplacement } from './extendComponent';
|
|
4
|
+
import { Theme } from '@idealyst/theme';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Wrap a dynamic style function to merge with extension styles.
|
|
8
|
+
*
|
|
9
|
+
* All styles in Unistyles must be dynamic functions (not static objects)
|
|
10
|
+
* to avoid Babel transform issues. This utility wraps a style function
|
|
11
|
+
* to automatically merge extension styles when the function is called.
|
|
12
|
+
*
|
|
13
|
+
* @param styleFn - The original dynamic style function
|
|
14
|
+
* @param elementExtension - Extension styles for this element (can be undefined).
|
|
15
|
+
* Can be either a static styles object or a function (props) => styles
|
|
16
|
+
* for prop-aware extensions.
|
|
17
|
+
* @returns A new function that returns merged styles
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { withExtension } from '../extensions/applyExtension';
|
|
22
|
+
* import { getExtension } from '../extensions/extendComponent';
|
|
23
|
+
*
|
|
24
|
+
* export const buttonStyles = StyleSheet.create((theme: Theme) => {
|
|
25
|
+
* const ext = getExtension('Button', theme);
|
|
26
|
+
*
|
|
27
|
+
* return {
|
|
28
|
+
* button: withExtension(createButtonStyles(theme), ext?.button),
|
|
29
|
+
* text: withExtension(createTextStyles(theme), ext?.text),
|
|
30
|
+
* };
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* - If no extension is provided, returns the original function unchanged
|
|
36
|
+
* - Extension styles take priority over base styles (deep merged)
|
|
37
|
+
* - Works with any style function signature
|
|
38
|
+
* - If extension is a function, it receives the same props as the base style function
|
|
39
|
+
*/
|
|
40
|
+
export function withExtension<TProps, TResult extends Styles>(
|
|
41
|
+
styleFn: (props: TProps) => TResult,
|
|
42
|
+
elementExtension: Styles | ((props: TProps) => Styles) | undefined
|
|
43
|
+
): (props: TProps) => TResult {
|
|
44
|
+
// If no extension, return original function unchanged
|
|
45
|
+
if (!elementExtension) {
|
|
46
|
+
return styleFn;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Return wrapped function that merges extension
|
|
50
|
+
return (props: TProps): TResult => {
|
|
51
|
+
const baseStyles = styleFn(props);
|
|
52
|
+
// If extension is a function, call it with props; otherwise use as-is
|
|
53
|
+
const extStyles = typeof elementExtension === 'function'
|
|
54
|
+
? elementExtension(props)
|
|
55
|
+
: elementExtension;
|
|
56
|
+
return deepMerge(baseStyles, extStyles) as TResult;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Wrap a parameterless style function with extension.
|
|
62
|
+
*
|
|
63
|
+
* Use this for style functions that don't take any parameters.
|
|
64
|
+
* This is common for simpler elements like iconContainer.
|
|
65
|
+
*
|
|
66
|
+
* @param styleFn - The original style function (no parameters)
|
|
67
|
+
* @param elementExtension - Extension styles for this element
|
|
68
|
+
* @returns A new function that returns merged styles
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const createIconContainerStyles = (theme: Theme) => {
|
|
73
|
+
* return () => ({
|
|
74
|
+
* display: 'flex',
|
|
75
|
+
* flexDirection: 'row',
|
|
76
|
+
* gap: 4,
|
|
77
|
+
* });
|
|
78
|
+
* };
|
|
79
|
+
*
|
|
80
|
+
* // In StyleSheet.create:
|
|
81
|
+
* iconContainer: withSimpleExtension(
|
|
82
|
+
* createIconContainerStyles(theme),
|
|
83
|
+
* ext?.iconContainer
|
|
84
|
+
* ),
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function withSimpleExtension<TResult extends Styles>(
|
|
88
|
+
styleFn: () => TResult,
|
|
89
|
+
elementExtension: Styles | undefined
|
|
90
|
+
): () => TResult {
|
|
91
|
+
if (!elementExtension) {
|
|
92
|
+
return styleFn;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return (): TResult => {
|
|
96
|
+
const baseStyles = styleFn();
|
|
97
|
+
return deepMerge(baseStyles, elementExtension) as TResult;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Normalize a style value (from replacement) into a dynamic function.
|
|
103
|
+
*
|
|
104
|
+
* Replacements can be either:
|
|
105
|
+
* - A function (props) => styles - used directly
|
|
106
|
+
* - A static styles object - wrapped in a function
|
|
107
|
+
*
|
|
108
|
+
* @param value - The replacement value (function or static object)
|
|
109
|
+
* @param defaultFn - Default function to use if value is undefined
|
|
110
|
+
* @returns The default function (type-safe) - replacement handling is done at runtime
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const replacement = getReplacement('Button', theme);
|
|
115
|
+
*
|
|
116
|
+
* // If replacement.button is a function, use it directly
|
|
117
|
+
* // If replacement.button is an object, wrap it in () => replacement.button
|
|
118
|
+
* // If undefined, use createButtonStyles(theme)
|
|
119
|
+
* button: withExtension(
|
|
120
|
+
* normalizeStyleFn(replacement?.button, createButtonStyles(theme)),
|
|
121
|
+
* ext?.button
|
|
122
|
+
* ),
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function normalizeStyleFn<TProps, TResult>(
|
|
126
|
+
value: unknown,
|
|
127
|
+
defaultFn: (props: TProps) => TResult
|
|
128
|
+
): (props: TProps) => TResult {
|
|
129
|
+
if (value === undefined || value === null) {
|
|
130
|
+
return defaultFn;
|
|
131
|
+
}
|
|
132
|
+
if (typeof value === 'function') {
|
|
133
|
+
return value as (props: TProps) => TResult;
|
|
134
|
+
}
|
|
135
|
+
// Static object - wrap in a function that ignores props
|
|
136
|
+
return (() => value) as (props: TProps) => TResult;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Normalize a simple style value (no props) into a parameterless function.
|
|
141
|
+
*
|
|
142
|
+
* @param value - The replacement value (function or static object)
|
|
143
|
+
* @param defaultFn - Default function to use if value is undefined
|
|
144
|
+
* @returns A parameterless function that returns styles
|
|
145
|
+
*/
|
|
146
|
+
export function normalizeSimpleStyleFn<TResult>(
|
|
147
|
+
value: unknown,
|
|
148
|
+
defaultFn: () => TResult
|
|
149
|
+
): () => TResult {
|
|
150
|
+
if (value === undefined || value === null) {
|
|
151
|
+
return defaultFn;
|
|
152
|
+
}
|
|
153
|
+
if (typeof value === 'function') {
|
|
154
|
+
return value as () => TResult;
|
|
155
|
+
}
|
|
156
|
+
// Static object - wrap in a function
|
|
157
|
+
return (() => value) as () => TResult;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Apply extensions and replacements to a set of style creators.
|
|
162
|
+
*
|
|
163
|
+
* This is a simplified helper that handles the common pattern of:
|
|
164
|
+
* 1. Getting extensions and replacements for a component
|
|
165
|
+
* 2. Applying normalizeStyleFn for each element
|
|
166
|
+
* 3. Merging extensions on top
|
|
167
|
+
*
|
|
168
|
+
* @param component - The component name
|
|
169
|
+
* @param theme - The current theme
|
|
170
|
+
* @param styleCreators - Object mapping element names to their style creator functions
|
|
171
|
+
* @returns Object with the same keys, but with extensions/replacements applied
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* export const buttonStyles = StyleSheet.create((theme: Theme) => {
|
|
176
|
+
* return applyExtensions('Button', theme, {
|
|
177
|
+
* button: createButtonStyles(theme),
|
|
178
|
+
* text: createTextStyles(theme),
|
|
179
|
+
* icon: createIconStyles(theme),
|
|
180
|
+
* });
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function applyExtensions<
|
|
185
|
+
K extends ComponentName,
|
|
186
|
+
T extends Record<string, ((...args: any[]) => any)>
|
|
187
|
+
>(
|
|
188
|
+
component: K,
|
|
189
|
+
theme: Theme,
|
|
190
|
+
styleCreators: T
|
|
191
|
+
): T {
|
|
192
|
+
const ext = getExtension(component, theme);
|
|
193
|
+
const replacement = getReplacement(component, theme);
|
|
194
|
+
|
|
195
|
+
const result = {} as T;
|
|
196
|
+
|
|
197
|
+
for (const key in styleCreators) {
|
|
198
|
+
const creator = styleCreators[key];
|
|
199
|
+
const elementExt = ext?.[key as string as keyof typeof ext] as ElementStyle | undefined;
|
|
200
|
+
const elementReplacement = replacement?.[key as string as keyof typeof replacement];
|
|
201
|
+
|
|
202
|
+
// Apply replacement (if any) then extension (if any)
|
|
203
|
+
result[key] = withExtension(
|
|
204
|
+
normalizeStyleFn(elementReplacement, creator),
|
|
205
|
+
elementExt
|
|
206
|
+
) as T[typeof key];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return result;
|
|
210
|
+
}
|