@idealyst/components 1.1.7 → 1.1.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.
- package/package.json +3 -3
- package/plugin/web.js +280 -532
- package/src/Accordion/Accordion.native.tsx +8 -6
- package/src/Accordion/Accordion.styles.old.tsx +298 -0
- package/src/Accordion/Accordion.styles.tsx +102 -236
- package/src/Accordion/Accordion.web.tsx +1 -3
- package/src/ActivityIndicator/ActivityIndicator.styles.old.tsx +94 -0
- package/src/ActivityIndicator/ActivityIndicator.styles.tsx +44 -74
- package/src/Alert/Alert.native.tsx +16 -6
- package/src/Alert/Alert.styles.old.tsx +209 -0
- package/src/Alert/Alert.styles.tsx +67 -149
- package/src/Alert/Alert.web.tsx +3 -4
- package/src/Avatar/Avatar.styles.old.tsx +99 -0
- package/src/Avatar/Avatar.styles.tsx +35 -80
- package/src/Badge/Badge.styles.old.tsx +157 -0
- package/src/Badge/Badge.styles.tsx +61 -121
- package/src/Badge/Badge.web.tsx +8 -15
- package/src/Breadcrumb/Breadcrumb.styles.old.tsx +231 -0
- package/src/Breadcrumb/Breadcrumb.styles.tsx +83 -200
- package/src/Breadcrumb/Breadcrumb.web.tsx +31 -30
- package/src/Button/Button.native.tsx +14 -21
- package/src/Button/Button.styles.tsx +103 -140
- package/src/Button/Button.web.tsx +9 -19
- package/src/Card/Card.native.tsx +7 -11
- package/src/Card/Card.styles.old.tsx +160 -0
- package/src/Card/Card.styles.tsx +105 -142
- package/src/Card/Card.web.tsx +5 -4
- package/src/Checkbox/Checkbox.native.tsx +9 -5
- package/src/Checkbox/Checkbox.styles.old.tsx +271 -0
- package/src/Checkbox/Checkbox.styles.tsx +104 -216
- package/src/Checkbox/Checkbox.web.tsx +7 -8
- package/src/Chip/Chip.styles.old.tsx +184 -0
- package/src/Chip/Chip.styles.tsx +34 -72
- package/src/Chip/Chip.web.tsx +3 -5
- package/src/Dialog/Dialog.native.tsx +7 -4
- package/src/Dialog/Dialog.styles.old.tsx +202 -0
- package/src/Dialog/Dialog.styles.tsx +69 -133
- package/src/Dialog/Dialog.web.tsx +3 -3
- package/src/Dialog/types.ts +1 -1
- package/src/Divider/Divider.styles.old.tsx +172 -0
- package/src/Divider/Divider.styles.tsx +62 -84
- package/src/Icon/Icon.native.tsx +8 -8
- package/src/Icon/Icon.styles.old.tsx +81 -0
- package/src/Icon/Icon.styles.tsx +52 -66
- package/src/Icon/Icon.web.tsx +62 -21
- package/src/Icon/IconRegistry.native.ts +41 -0
- package/src/Icon/IconRegistry.ts +107 -0
- package/src/Icon/IconSvg/IconSvg.web.tsx +28 -5
- package/src/Icon/icon-resolver.ts +12 -43
- package/src/Icon/index.native.ts +2 -1
- package/src/Icon/index.ts +1 -0
- package/src/Icon/index.web.ts +1 -0
- package/src/Image/Image.styles.old.tsx +69 -0
- package/src/Image/Image.styles.tsx +46 -60
- package/src/Input/Input.native.tsx +138 -53
- package/src/Input/Input.styles.old.tsx +289 -0
- package/src/Input/Input.styles.tsx +134 -232
- package/src/Input/Input.web.tsx +5 -8
- package/src/List/List.native.tsx +5 -2
- package/src/List/List.styles.old.tsx +242 -0
- package/src/List/List.styles.tsx +179 -215
- package/src/List/ListItem.native.tsx +16 -11
- package/src/List/ListItem.web.tsx +26 -16
- package/src/Menu/Menu.styles.old.tsx +197 -0
- package/src/Menu/Menu.styles.tsx +68 -150
- package/src/Menu/MenuItem.native.tsx +5 -3
- package/src/Menu/MenuItem.styles.old.tsx +114 -0
- package/src/Menu/MenuItem.styles.tsx +57 -89
- package/src/Menu/MenuItem.web.tsx +10 -7
- package/src/Popover/Popover.native.tsx +10 -4
- package/src/Popover/Popover.styles.old.tsx +135 -0
- package/src/Popover/Popover.styles.tsx +51 -112
- package/src/Pressable/Pressable.styles.old.tsx +27 -0
- package/src/Pressable/Pressable.styles.tsx +35 -27
- package/src/Progress/Progress.styles.old.tsx +200 -0
- package/src/Progress/Progress.styles.tsx +75 -164
- package/src/RadioButton/RadioButton.native.tsx +4 -3
- package/src/RadioButton/RadioButton.styles.old.tsx +175 -0
- package/src/RadioButton/RadioButton.styles.tsx +83 -154
- package/src/RadioButton/RadioButton.web.tsx +2 -2
- package/src/SVGImage/SVGImage.styles.old.tsx +86 -0
- package/src/SVGImage/SVGImage.styles.tsx +35 -78
- package/src/Screen/Screen.native.tsx +19 -26
- package/src/Screen/Screen.styles.old.tsx +87 -0
- package/src/Screen/Screen.styles.tsx +103 -68
- package/src/Screen/Screen.web.tsx +2 -2
- package/src/Select/Select.native.tsx +42 -33
- package/src/Select/Select.styles.old.tsx +353 -0
- package/src/Select/Select.styles.tsx +214 -300
- package/src/Select/Select.web.tsx +45 -33
- package/src/Skeleton/Skeleton.styles.old.tsx +67 -0
- package/src/Skeleton/Skeleton.styles.tsx +29 -53
- package/src/Slider/Slider.styles.old.tsx +259 -0
- package/src/Slider/Slider.styles.tsx +153 -234
- package/src/Slider/Slider.web.tsx +2 -4
- package/src/Switch/Switch.native.tsx +9 -7
- package/src/Switch/Switch.styles.old.tsx +203 -0
- package/src/Switch/Switch.styles.tsx +101 -174
- package/src/Switch/Switch.web.tsx +7 -8
- package/src/TabBar/TabBar.native.tsx +3 -2
- package/src/TabBar/TabBar.styles.old.tsx +343 -0
- package/src/TabBar/TabBar.styles.tsx +145 -279
- package/src/Table/Table.native.tsx +180 -68
- package/src/Table/Table.styles.old.tsx +311 -0
- package/src/Table/Table.styles.tsx +140 -281
- package/src/Table/Table.web.tsx +169 -70
- package/src/Text/Text.native.tsx +1 -3
- 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 -84
- package/src/Text/Text.web.tsx +3 -2
- package/src/Text/index.ts +1 -0
- package/src/TextArea/TextArea.native.tsx +21 -8
- package/src/TextArea/TextArea.styles.old.tsx +213 -0
- package/src/TextArea/TextArea.styles.tsx +87 -187
- package/src/TextArea/TextArea.web.tsx +17 -6
- package/src/Tooltip/Tooltip.styles.old.tsx +82 -0
- package/src/Tooltip/Tooltip.styles.tsx +32 -56
- package/src/Video/Video.styles.old.tsx +51 -0
- package/src/Video/Video.styles.tsx +32 -44
- package/src/View/View.native.tsx +41 -13
- package/src/View/View.styles.old.tsx +125 -0
- package/src/View/View.styles.tsx +76 -106
- package/src/View/View.web.tsx +5 -21
- package/src/View/types.ts +31 -3
- package/src/examples/ButtonExamples.tsx +20 -0
- package/src/examples/CardExamples.tsx +0 -6
- package/src/extensions/extendComponent.ts +61 -0
- package/src/index.ts +1 -1
package/src/View/View.native.tsx
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
|
-
import { View as RNView, ScrollView as RNScrollView, ViewStyle } from 'react-native';
|
|
2
|
+
import { View as RNView, ScrollView as RNScrollView, ViewStyle, StyleSheet } from 'react-native';
|
|
3
|
+
import { useResponsiveStyle, ResponsiveStyle } from '@idealyst/theme';
|
|
3
4
|
import { ViewProps } from './types';
|
|
4
5
|
import { viewStyles } from './View.styles';
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Check if a style object contains any responsive values
|
|
9
|
+
*/
|
|
10
|
+
function hasResponsiveValues(style: any): style is ResponsiveStyle {
|
|
11
|
+
if (!style || typeof style !== 'object' || Array.isArray(style)) return false;
|
|
12
|
+
for (const key in style) {
|
|
13
|
+
const value = style[key];
|
|
14
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && !('$$typeof' in value)) {
|
|
15
|
+
// Check if it looks like a breakpoint map (has breakpoint-like keys)
|
|
16
|
+
const keys = Object.keys(value);
|
|
17
|
+
if (keys.some(k => ['xs', 'sm', 'md', 'lg', 'xl'].includes(k))) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
6
25
|
const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
7
26
|
children,
|
|
8
27
|
background = 'transparent',
|
|
@@ -26,6 +45,7 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
|
26
45
|
testID,
|
|
27
46
|
id,
|
|
28
47
|
}, ref) => {
|
|
48
|
+
// Set active variants for this render
|
|
29
49
|
viewStyles.useVariants({
|
|
30
50
|
background,
|
|
31
51
|
radius,
|
|
@@ -39,25 +59,33 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
|
39
59
|
marginHorizontal,
|
|
40
60
|
});
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
// Call style as function to get theme-reactive styles
|
|
63
|
+
const viewStyle = (viewStyles.view as any)({});
|
|
64
|
+
|
|
65
|
+
// Override styles for direct prop values
|
|
66
|
+
const overrideStyles: ViewStyle = {};
|
|
67
|
+
if (backgroundColor) overrideStyles.backgroundColor = backgroundColor;
|
|
68
|
+
if (borderRadius !== undefined) overrideStyles.borderRadius = borderRadius;
|
|
69
|
+
if (borderWidth !== undefined) overrideStyles.borderWidth = borderWidth;
|
|
70
|
+
if (borderColor) overrideStyles.borderColor = borderColor;
|
|
44
71
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (borderWidth !== undefined) baseStyles.borderWidth = borderWidth;
|
|
48
|
-
if (borderColor) baseStyles.borderColor = borderColor;
|
|
72
|
+
// Flatten style array if needed and check for responsive values
|
|
73
|
+
const flattenedStyle = Array.isArray(style) ? StyleSheet.flatten(style) : style;
|
|
49
74
|
|
|
50
|
-
|
|
51
|
-
|
|
75
|
+
// Resolve responsive values if present (this hook is reactive to breakpoint changes)
|
|
76
|
+
const resolvedStyle = useResponsiveStyle(
|
|
77
|
+
hasResponsiveValues(flattenedStyle) ? flattenedStyle : {}
|
|
78
|
+
);
|
|
52
79
|
|
|
53
|
-
|
|
80
|
+
// Use resolved style if responsive, otherwise use original
|
|
81
|
+
const finalStyle = hasResponsiveValues(flattenedStyle) ? resolvedStyle : style;
|
|
54
82
|
|
|
55
83
|
if (scrollable) {
|
|
56
84
|
return (
|
|
57
85
|
<RNScrollView
|
|
58
86
|
ref={ref as any}
|
|
59
|
-
style={[{ flex: 1 },
|
|
60
|
-
contentContainerStyle={[viewStyle,
|
|
87
|
+
style={[viewStyle, { flex: 1 }, overrideStyles, finalStyle]}
|
|
88
|
+
contentContainerStyle={[viewStyle, overrideStyles]}
|
|
61
89
|
testID={testID}
|
|
62
90
|
nativeID={id}
|
|
63
91
|
>
|
|
@@ -67,7 +95,7 @@ const View = forwardRef<RNView | RNScrollView, ViewProps>(({
|
|
|
67
95
|
}
|
|
68
96
|
|
|
69
97
|
return (
|
|
70
|
-
<RNView ref={ref as any} style={[viewStyle,
|
|
98
|
+
<RNView ref={ref as any} style={[viewStyle, overrideStyles, finalStyle]} testID={testID} nativeID={id}>
|
|
71
99
|
{children}
|
|
72
100
|
</RNView>
|
|
73
101
|
);
|
|
@@ -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,125 +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
|
-
import { applyExtensions } from '../extensions/applyExtension';
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
};
|
|
10
|
+
// Required: Unistyles must see StyleSheet usage in original source to process this file
|
|
11
|
+
void StyleSheet;
|
|
28
12
|
|
|
29
|
-
|
|
13
|
+
// Wrap theme for $iterator support
|
|
14
|
+
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
30
15
|
|
|
31
|
-
export type
|
|
32
|
-
|
|
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;
|
|
33
27
|
};
|
|
34
28
|
|
|
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
|
-
}
|
|
29
|
+
export type ViewDynamicProps = Partial<ViewVariants>;
|
|
54
30
|
|
|
55
31
|
/**
|
|
56
|
-
*
|
|
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.
|
|
57
36
|
*/
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
// Style creators for extension support
|
|
91
|
-
function createViewStyles(theme: Theme) {
|
|
92
|
-
return () => ({
|
|
37
|
+
export const viewStyles = defineStyle('View', (theme: Theme) => ({
|
|
38
|
+
view: (_props: ViewDynamicProps) => ({
|
|
93
39
|
display: 'flex' as const,
|
|
40
|
+
// Theme marker for Unistyles reactivity (invisible, overridden by variants)
|
|
41
|
+
borderColor: theme.colors.border.primary,
|
|
42
|
+
borderWidth: 0,
|
|
94
43
|
variants: {
|
|
95
|
-
background:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
+
},
|
|
105
88
|
},
|
|
106
89
|
_web: {
|
|
107
90
|
display: 'flex',
|
|
108
91
|
flexDirection: 'column',
|
|
109
92
|
boxSizing: 'border-box',
|
|
110
93
|
},
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
|
|
115
|
-
// transform on native cannot resolve function calls to extract variant structures.
|
|
116
|
-
export const viewStyles = StyleSheet.create((theme: Theme) => {
|
|
117
|
-
// Apply extensions to main visual elements
|
|
118
|
-
const extended = applyExtensions('View', theme, {
|
|
119
|
-
view: createViewStyles(theme),
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
...extended,
|
|
124
|
-
};
|
|
125
|
-
});
|
|
94
|
+
}),
|
|
95
|
+
}));
|
package/src/View/View.web.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, useMemo } from 'react';
|
|
2
|
-
import { StyleSheet } from 'react-native';
|
|
3
2
|
import { getWebProps } from 'react-native-unistyles/web';
|
|
3
|
+
import { useResponsiveStyle } from '@idealyst/theme';
|
|
4
4
|
import { ViewProps } from './types';
|
|
5
5
|
import { viewStyles } from './View.styles';
|
|
6
6
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
@@ -41,31 +41,15 @@ const View = forwardRef<HTMLDivElement, ViewProps>(({
|
|
|
41
41
|
marginHorizontal,
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
//
|
|
45
|
-
const dynamicStyles: any = {};
|
|
46
|
-
|
|
47
|
-
if (backgroundColor) dynamicStyles.backgroundColor = backgroundColor;
|
|
48
|
-
if (borderRadius !== undefined) dynamicStyles.borderRadius = borderRadius;
|
|
49
|
-
if (borderWidth !== undefined) dynamicStyles.borderWidth = borderWidth;
|
|
50
|
-
if (borderColor) dynamicStyles.borderColor = borderColor;
|
|
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
|
-
|
|
44
|
+
// Call style as function to get theme-reactive styles
|
|
61
45
|
/** @ts-ignore */
|
|
62
|
-
const webProps = getWebProps(
|
|
63
|
-
|
|
46
|
+
const webProps = getWebProps((viewStyles.view as any)({}));
|
|
47
|
+
|
|
64
48
|
const mergedRef = useMergeRefs(ref, webProps.ref);
|
|
65
49
|
|
|
66
50
|
return (
|
|
67
51
|
<div
|
|
68
|
-
style={
|
|
52
|
+
style={style as any}
|
|
69
53
|
{...webProps}
|
|
70
54
|
ref={mergedRef}
|
|
71
55
|
id={id}
|
package/src/View/types.ts
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
|
-
import { Size, Surface } from '@idealyst/theme';
|
|
1
|
+
import { Size, Surface, ResponsiveStyle } from '@idealyst/theme';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
4
4
|
import { ContainerStyleProps } from '../utils/viewStyleProps';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Style prop type that accepts both regular styles and responsive styles.
|
|
8
|
+
* Responsive styles allow breakpoint-based values:
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* // Regular style
|
|
12
|
+
* <View style={{ flexDirection: 'column' }} />
|
|
13
|
+
*
|
|
14
|
+
* // Responsive style
|
|
15
|
+
* <View style={{ flexDirection: { xs: 'column', md: 'row' } }} />
|
|
16
|
+
*
|
|
17
|
+
* // Style array (native only)
|
|
18
|
+
* <View style={[styles.container, { padding: 10 }]} />
|
|
19
|
+
*
|
|
20
|
+
* // Web-only CSS properties
|
|
21
|
+
* <View style={{ display: 'inline-block' }} />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export type ViewStyleProp = StyleProp<ViewStyle> | ResponsiveStyle | React.CSSProperties;
|
|
25
|
+
|
|
6
26
|
// Component-specific type aliases for future extensibility
|
|
7
27
|
export type ViewBackgroundVariant = Surface | 'transparent';
|
|
8
28
|
export type ViewRadiusVariant = Size | 'none';
|
|
@@ -50,9 +70,17 @@ export interface ViewProps extends ContainerStyleProps {
|
|
|
50
70
|
borderColor?: string;
|
|
51
71
|
|
|
52
72
|
/**
|
|
53
|
-
* Additional styles
|
|
73
|
+
* Additional styles. Supports responsive values for any property.
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* // Responsive flexDirection
|
|
77
|
+
* <View style={{ flexDirection: { xs: 'column', md: 'row' } }} />
|
|
78
|
+
*
|
|
79
|
+
* // Mix responsive and static values
|
|
80
|
+
* <View style={{ padding: { xs: 8, lg: 16 }, backgroundColor: '#fff' }} />
|
|
81
|
+
* ```
|
|
54
82
|
*/
|
|
55
|
-
style?:
|
|
83
|
+
style?: ViewStyleProp;
|
|
56
84
|
|
|
57
85
|
/**
|
|
58
86
|
* Enable scrollable content (uses ScrollView on native, overflow:auto on web)
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Screen, View, Button, Text } from '@idealyst/components';
|
|
3
|
+
import { useUnistyles } from 'react-native-unistyles';
|
|
3
4
|
|
|
4
5
|
export const ButtonExamples = () => {
|
|
5
6
|
const handlePress = (buttonType: string) => {
|
|
6
7
|
console.log(`Button pressed: ${buttonType}`);
|
|
7
8
|
};
|
|
8
9
|
|
|
10
|
+
const { theme } = useUnistyles()
|
|
11
|
+
|
|
9
12
|
return (
|
|
10
13
|
<Screen background="primary">
|
|
11
14
|
<View gap="xl">
|
|
@@ -41,6 +44,23 @@ export const ButtonExamples = () => {
|
|
|
41
44
|
</View>
|
|
42
45
|
</View>
|
|
43
46
|
|
|
47
|
+
{/* Show all intents in theme (including extended intents) */}
|
|
48
|
+
<View gap="md">
|
|
49
|
+
<Text typography="subtitle1">All Intents</Text>
|
|
50
|
+
<View style={{ flexDirection: 'row', gap: 12, flexWrap: 'wrap' }}>
|
|
51
|
+
{ (Object.keys(theme.intents) as Array<keyof typeof theme.intents>).map((intent) => (
|
|
52
|
+
<Button
|
|
53
|
+
key={intent}
|
|
54
|
+
type="contained"
|
|
55
|
+
intent={intent}
|
|
56
|
+
onPress={() => handlePress(`intent-${intent}`)}
|
|
57
|
+
>
|
|
58
|
+
{intent.charAt(0).toUpperCase() + intent.slice(1)}
|
|
59
|
+
</Button>
|
|
60
|
+
)) }
|
|
61
|
+
</View>
|
|
62
|
+
</View>
|
|
63
|
+
|
|
44
64
|
{/* Button Sizes */}
|
|
45
65
|
<View gap="md">
|
|
46
66
|
<Text typography="subtitle1">Sizes</Text>
|
|
@@ -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>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Theme } from '@idealyst/theme';
|
|
2
|
+
import { UnistylesRuntime } from 'react-native-unistyles';
|
|
2
3
|
import {
|
|
3
4
|
ComponentStyleElements,
|
|
4
5
|
ComponentName,
|
|
@@ -18,6 +19,57 @@ const extensionRegistry = new Map<ComponentName, StyleExtension<any>[]>();
|
|
|
18
19
|
*/
|
|
19
20
|
const replacementRegistry = new Map<ComponentName, StyleExtension<any>>();
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Compute all extensions for a given theme.
|
|
24
|
+
* Returns an object with component names as keys and merged element extensions as values.
|
|
25
|
+
*/
|
|
26
|
+
function computeExtensionsForTheme(theme: Theme): Record<string, Record<string, any>> {
|
|
27
|
+
const result: Record<string, Record<string, any>> = {};
|
|
28
|
+
|
|
29
|
+
for (const [component, extensions] of extensionRegistry) {
|
|
30
|
+
if (!extensions || extensions.length === 0) continue;
|
|
31
|
+
|
|
32
|
+
// Resolve all extensions (call functions with theme)
|
|
33
|
+
const resolved = extensions.map(ext =>
|
|
34
|
+
typeof ext === 'function' ? ext(theme) : ext
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Merge all extensions in order (later ones win)
|
|
38
|
+
result[component] = deepMergeAll(...resolved);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Update theme's __extensions to trigger Unistyles reactivity.
|
|
46
|
+
* This is called whenever extensions change.
|
|
47
|
+
*/
|
|
48
|
+
function syncExtensionsToThemes(): void {
|
|
49
|
+
try {
|
|
50
|
+
// Update both light and dark themes with computed extensions
|
|
51
|
+
UnistylesRuntime.updateTheme('light', (currentTheme) => {
|
|
52
|
+
const extensions = computeExtensionsForTheme(currentTheme);
|
|
53
|
+
return {
|
|
54
|
+
...currentTheme,
|
|
55
|
+
__extensions: extensions,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
UnistylesRuntime.updateTheme('dark', (currentTheme) => {
|
|
60
|
+
const extensions = computeExtensionsForTheme(currentTheme);
|
|
61
|
+
return {
|
|
62
|
+
...currentTheme,
|
|
63
|
+
__extensions: extensions,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
// UnistylesRuntime may not be available in all contexts (e.g., SSR)
|
|
68
|
+
// Silently ignore errors - extensions will still work via getExtension
|
|
69
|
+
console.warn('Unable to sync extensions to theme:', error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
21
73
|
/**
|
|
22
74
|
* Completely replace the styles of a component.
|
|
23
75
|
*
|
|
@@ -249,6 +301,9 @@ export function extendComponent<K extends ComponentName>(
|
|
|
249
301
|
const existing = extensionRegistry.get(component) ?? [];
|
|
250
302
|
existing.push(extension);
|
|
251
303
|
extensionRegistry.set(component, existing);
|
|
304
|
+
|
|
305
|
+
// Sync extensions to theme for Unistyles reactivity
|
|
306
|
+
syncExtensionsToThemes();
|
|
252
307
|
}
|
|
253
308
|
|
|
254
309
|
/**
|
|
@@ -298,6 +353,9 @@ export function getExtension<K extends ComponentName>(
|
|
|
298
353
|
*/
|
|
299
354
|
export function clearExtension<K extends ComponentName>(component: K): void {
|
|
300
355
|
extensionRegistry.delete(component);
|
|
356
|
+
|
|
357
|
+
// Sync extensions to theme for Unistyles reactivity
|
|
358
|
+
syncExtensionsToThemes();
|
|
301
359
|
}
|
|
302
360
|
|
|
303
361
|
/**
|
|
@@ -313,6 +371,9 @@ export function clearExtension<K extends ComponentName>(component: K): void {
|
|
|
313
371
|
*/
|
|
314
372
|
export function clearAllExtensions(): void {
|
|
315
373
|
extensionRegistry.clear();
|
|
374
|
+
|
|
375
|
+
// Sync extensions to theme for Unistyles reactivity
|
|
376
|
+
syncExtensionsToThemes();
|
|
316
377
|
}
|
|
317
378
|
|
|
318
379
|
/**
|
package/src/index.ts
CHANGED
|
@@ -40,7 +40,7 @@ export * from './Avatar/types';
|
|
|
40
40
|
export { default as Screen } from './Screen';
|
|
41
41
|
export * from './Screen/types';
|
|
42
42
|
|
|
43
|
-
export { default as Icon } from './Icon';
|
|
43
|
+
export { default as Icon, IconRegistry } from './Icon';
|
|
44
44
|
export * from './Icon/types';
|
|
45
45
|
|
|
46
46
|
export { default as SVGImage } from './SVGImage';
|