@idealyst/components 1.2.14 → 1.2.15
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/src/Accordion/Accordion.web.tsx +1 -1
- package/src/Alert/Alert.native.tsx +1 -1
- package/src/Alert/Alert.web.tsx +1 -1
- package/src/Badge/Badge.web.tsx +6 -2
- package/src/Badge/types.ts +5 -0
- package/src/Button/Button.native.tsx +3 -3
- package/src/Button/Button.web.tsx +5 -1
- package/src/Button/types.ts +5 -0
- package/src/Card/Card.web.tsx +4 -1
- package/src/Card/types.ts +5 -0
- package/src/Dialog/Dialog.native.tsx +1 -1
- package/src/Divider/Divider.web.tsx +2 -2
- package/src/Icon/Icon.web.tsx +2 -2
- package/src/Image/Image.styles.tsx +5 -5
- package/src/Image/Image.web.tsx +3 -3
- package/src/List/List.native.tsx +1 -2
- package/src/List/List.web.tsx +1 -2
- package/src/List/ListSection.web.tsx +3 -3
- package/src/Menu/Menu.web.tsx +8 -10
- package/src/Menu/MenuItem.web.tsx +1 -1
- package/src/Popover/Popover.web.tsx +1 -1
- package/src/Pressable/Pressable.web.tsx +1 -1
- package/src/Progress/Progress.styles.tsx +76 -30
- package/src/Progress/Progress.web.tsx +13 -15
- package/src/SVGImage/SVGImage.web.tsx +1 -1
- package/src/Select/Select.web.tsx +2 -2
- package/src/Slider/Slider.styles.tsx +131 -44
- package/src/Slider/Slider.web.tsx +22 -22
- package/src/Text/Text.web.tsx +29 -3
- package/src/Text/types.ts +14 -1
- package/src/TextArea/TextArea.styles.tsx +96 -57
- package/src/TextArea/TextArea.web.tsx +19 -28
- package/src/Tooltip/Tooltip.web.tsx +3 -3
- package/src/Video/Video.styles.tsx +3 -3
- package/src/Video/Video.web.tsx +1 -1
- package/src/View/View.styles.tsx +2 -2
- package/src/View/View.web.tsx +93 -9
- package/src/View/types.ts +5 -1
- package/src/examples/ViewExamples.tsx +34 -0
- package/src/extensions/index.ts +0 -7
- package/src/hooks/useMergeRefs.ts +12 -6
- package/src/utils/accessibility/keyboardPatterns.ts +4 -0
- package/src/utils/accessibility/types.ts +5 -1
- package/src/utils/accessibility/useAnnounce.ts +1 -1
- package/src/utils/accessibility/useKeyboardNavigation.ts +1 -1
- package/src/utils/index.ts +0 -3
- package/src/utils/viewStyleProps.ts +2 -0
- package/src/extensions/applyExtension.ts +0 -210
- package/src/utils/buildSizeVariants.ts +0 -16
|
@@ -258,7 +258,7 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(({
|
|
|
258
258
|
</div>
|
|
259
259
|
<PositionedPortal
|
|
260
260
|
open={isOpen}
|
|
261
|
-
anchor={triggerRef}
|
|
261
|
+
anchor={triggerRef as React.RefObject<HTMLElement>}
|
|
262
262
|
placement="bottom-start"
|
|
263
263
|
offset={4}
|
|
264
264
|
onClickOutside={handleClose}
|
|
@@ -280,12 +280,12 @@ const Select = forwardRef<HTMLDivElement, SelectProps>(({
|
|
|
280
280
|
{searchable && (
|
|
281
281
|
<div {...getWebProps([searchContainerStyle])}>
|
|
282
282
|
<input
|
|
283
|
+
{...getWebProps([searchInputStyle])}
|
|
283
284
|
ref={searchInputRef}
|
|
284
285
|
type="text"
|
|
285
286
|
placeholder="Search options..."
|
|
286
287
|
value={searchTerm}
|
|
287
288
|
onChange={handleSearchChange}
|
|
288
|
-
{...getWebProps([searchInputStyle])}
|
|
289
289
|
/>
|
|
290
290
|
</div>
|
|
291
291
|
)}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Slider styles using
|
|
2
|
+
* Slider styles using static styles with variants.
|
|
3
3
|
*/
|
|
4
4
|
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
-
import { defineStyle, ThemeStyleWrapper } from '@idealyst/theme';
|
|
5
|
+
import { defineStyle, ThemeStyleWrapper, CompoundVariants } from '@idealyst/theme';
|
|
6
6
|
import type { Theme as BaseTheme, Intent, Size } from '@idealyst/theme';
|
|
7
7
|
import { ViewStyleSize } from '../utils/viewStyleProps';
|
|
8
8
|
|
|
@@ -12,20 +12,47 @@ void StyleSheet;
|
|
|
12
12
|
// Wrap theme for $iterator support
|
|
13
13
|
type Theme = ThemeStyleWrapper<BaseTheme>;
|
|
14
14
|
|
|
15
|
-
export type
|
|
16
|
-
size
|
|
17
|
-
intent
|
|
18
|
-
disabled
|
|
15
|
+
export type SliderVariants = {
|
|
16
|
+
size: Size;
|
|
17
|
+
intent: Intent;
|
|
18
|
+
disabled: boolean;
|
|
19
19
|
margin?: ViewStyleSize;
|
|
20
20
|
marginVertical?: ViewStyleSize;
|
|
21
21
|
marginHorizontal?: ViewStyleSize;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
// Create intent variants dynamically from theme
|
|
25
|
+
function createIntentVariants(theme: Theme) {
|
|
26
|
+
const variants: Record<string, object> = {};
|
|
27
|
+
for (const intent in theme.intents) {
|
|
28
|
+
variants[intent] = {};
|
|
29
|
+
}
|
|
30
|
+
return variants;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create compound variants for intent-specific styles
|
|
34
|
+
function createSliderCompoundVariants(theme: Theme): CompoundVariants<keyof SliderVariants> {
|
|
35
|
+
const compoundVariants: CompoundVariants<keyof SliderVariants> = [];
|
|
36
|
+
|
|
37
|
+
for (const intent in theme.intents) {
|
|
38
|
+
const intentValue = theme.intents[intent as Intent];
|
|
39
|
+
|
|
40
|
+
// filledTrack intent colors are handled inline since they need per-element targeting
|
|
41
|
+
// thumb border color by intent
|
|
42
|
+
compoundVariants.push({
|
|
43
|
+
intent,
|
|
44
|
+
styles: {},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return compoundVariants;
|
|
49
|
+
}
|
|
50
|
+
|
|
24
51
|
/**
|
|
25
|
-
* Slider styles with
|
|
52
|
+
* Slider styles with static styles and variants.
|
|
26
53
|
*/
|
|
27
54
|
export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
|
|
28
|
-
container:
|
|
55
|
+
container: {
|
|
29
56
|
gap: 4,
|
|
30
57
|
paddingVertical: 8,
|
|
31
58
|
variants: {
|
|
@@ -39,44 +66,67 @@ export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
|
|
|
39
66
|
marginHorizontal: theme.sizes.$view.padding,
|
|
40
67
|
},
|
|
41
68
|
},
|
|
42
|
-
}
|
|
69
|
+
},
|
|
43
70
|
|
|
44
|
-
sliderWrapper:
|
|
71
|
+
sliderWrapper: {
|
|
45
72
|
position: 'relative' as const,
|
|
46
73
|
paddingVertical: 4,
|
|
47
|
-
}
|
|
74
|
+
},
|
|
48
75
|
|
|
49
|
-
track:
|
|
76
|
+
track: {
|
|
50
77
|
backgroundColor: theme.colors.surface.tertiary,
|
|
51
78
|
borderRadius: 9999,
|
|
52
79
|
position: 'relative' as const,
|
|
53
|
-
opacity: disabled ? 0.5 : 1,
|
|
54
80
|
variants: {
|
|
55
81
|
size: {
|
|
56
82
|
height: theme.sizes.$slider.trackHeight,
|
|
57
83
|
},
|
|
84
|
+
disabled: {
|
|
85
|
+
true: {
|
|
86
|
+
opacity: 0.5,
|
|
87
|
+
_web: {
|
|
88
|
+
cursor: 'not-allowed',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
false: {
|
|
92
|
+
opacity: 1,
|
|
93
|
+
_web: {
|
|
94
|
+
cursor: 'pointer',
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
58
98
|
},
|
|
59
|
-
|
|
60
|
-
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
61
|
-
},
|
|
62
|
-
}),
|
|
99
|
+
},
|
|
63
100
|
|
|
64
|
-
filledTrack:
|
|
101
|
+
filledTrack: {
|
|
65
102
|
position: 'absolute' as const,
|
|
66
103
|
height: '100%',
|
|
67
104
|
borderRadius: 9999,
|
|
68
105
|
top: 0,
|
|
69
106
|
left: 0,
|
|
70
|
-
|
|
71
|
-
|
|
107
|
+
variants: {
|
|
108
|
+
intent: createIntentVariants(theme),
|
|
109
|
+
},
|
|
110
|
+
compoundVariants: (() => {
|
|
111
|
+
const cv: CompoundVariants<keyof SliderVariants> = [];
|
|
112
|
+
for (const intent in theme.intents) {
|
|
113
|
+
cv.push({
|
|
114
|
+
intent,
|
|
115
|
+
styles: {
|
|
116
|
+
backgroundColor: theme.intents[intent as Intent].primary,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return cv;
|
|
121
|
+
})(),
|
|
122
|
+
},
|
|
72
123
|
|
|
73
|
-
thumb:
|
|
124
|
+
thumb: {
|
|
74
125
|
position: 'absolute' as const,
|
|
75
126
|
backgroundColor: theme.colors.surface.primary,
|
|
76
127
|
borderRadius: 9999,
|
|
77
128
|
borderWidth: 2,
|
|
78
129
|
borderStyle: 'solid' as const,
|
|
79
|
-
borderColor: theme.intents[intent].primary,
|
|
80
130
|
top: '50%',
|
|
81
131
|
display: 'flex' as const,
|
|
82
132
|
alignItems: 'center' as const,
|
|
@@ -86,35 +136,59 @@ export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
|
|
|
86
136
|
shadowOpacity: 0.2,
|
|
87
137
|
shadowRadius: 4,
|
|
88
138
|
elevation: 2,
|
|
89
|
-
opacity: disabled ? 0.6 : 1,
|
|
90
139
|
variants: {
|
|
91
140
|
size: {
|
|
92
141
|
width: theme.sizes.$slider.thumbSize,
|
|
93
142
|
height: theme.sizes.$slider.thumbSize,
|
|
94
143
|
},
|
|
144
|
+
intent: createIntentVariants(theme),
|
|
145
|
+
disabled: {
|
|
146
|
+
true: {
|
|
147
|
+
opacity: 0.6,
|
|
148
|
+
_web: {
|
|
149
|
+
cursor: 'not-allowed',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
false: {
|
|
153
|
+
opacity: 1,
|
|
154
|
+
_web: {
|
|
155
|
+
cursor: 'grab',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
95
159
|
},
|
|
160
|
+
compoundVariants: (() => {
|
|
161
|
+
const cv: CompoundVariants<keyof SliderVariants> = [];
|
|
162
|
+
for (const intent in theme.intents) {
|
|
163
|
+
cv.push({
|
|
164
|
+
intent,
|
|
165
|
+
styles: {
|
|
166
|
+
borderColor: theme.intents[intent as Intent].primary,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return cv;
|
|
171
|
+
})(),
|
|
96
172
|
_web: {
|
|
97
173
|
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
|
|
98
174
|
transform: 'translate(-50%, -50%)',
|
|
99
175
|
transition: 'transform 0.15s ease, box-shadow 0.2s ease',
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
_active: disabled ? {} : { cursor: 'grabbing', transform: 'translate(-50%, -50%) scale(1.1)' },
|
|
176
|
+
_hover: { transform: 'translate(-50%, -50%) scale(1.05)' },
|
|
177
|
+
_active: { cursor: 'grabbing', transform: 'translate(-50%, -50%) scale(1.1)' },
|
|
103
178
|
},
|
|
104
|
-
}
|
|
179
|
+
},
|
|
105
180
|
|
|
106
|
-
thumbActive:
|
|
181
|
+
thumbActive: {
|
|
107
182
|
_web: {
|
|
108
183
|
transform: 'translate(-50%, -50%) scale(1.1)',
|
|
109
184
|
},
|
|
110
|
-
}
|
|
185
|
+
},
|
|
111
186
|
|
|
112
|
-
thumbIcon:
|
|
187
|
+
thumbIcon: {
|
|
113
188
|
display: 'flex' as const,
|
|
114
189
|
alignItems: 'center' as const,
|
|
115
190
|
justifyContent: 'center' as const,
|
|
116
191
|
flexShrink: 0,
|
|
117
|
-
color: theme.intents[intent].primary,
|
|
118
192
|
variants: {
|
|
119
193
|
size: {
|
|
120
194
|
width: theme.sizes.$slider.thumbIconSize,
|
|
@@ -124,36 +198,49 @@ export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
|
|
|
124
198
|
minHeight: theme.sizes.$slider.thumbIconSize,
|
|
125
199
|
maxHeight: theme.sizes.$slider.thumbIconSize,
|
|
126
200
|
},
|
|
201
|
+
intent: createIntentVariants(theme),
|
|
127
202
|
},
|
|
128
|
-
|
|
203
|
+
compoundVariants: (() => {
|
|
204
|
+
const cv: CompoundVariants<keyof SliderVariants> = [];
|
|
205
|
+
for (const intent in theme.intents) {
|
|
206
|
+
cv.push({
|
|
207
|
+
intent,
|
|
208
|
+
styles: {
|
|
209
|
+
color: theme.intents[intent as Intent].primary,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return cv;
|
|
214
|
+
})(),
|
|
215
|
+
},
|
|
129
216
|
|
|
130
|
-
valueLabel:
|
|
217
|
+
valueLabel: {
|
|
131
218
|
fontSize: 12,
|
|
132
219
|
fontWeight: '600' as const,
|
|
133
220
|
color: theme.colors.text.primary,
|
|
134
221
|
textAlign: 'center' as const,
|
|
135
|
-
}
|
|
222
|
+
},
|
|
136
223
|
|
|
137
|
-
minMaxLabels:
|
|
224
|
+
minMaxLabels: {
|
|
138
225
|
flexDirection: 'row' as const,
|
|
139
226
|
justifyContent: 'space-between' as const,
|
|
140
227
|
marginTop: 4,
|
|
141
|
-
}
|
|
228
|
+
},
|
|
142
229
|
|
|
143
|
-
minMaxLabel:
|
|
230
|
+
minMaxLabel: {
|
|
144
231
|
fontSize: 12,
|
|
145
232
|
color: theme.colors.text.secondary,
|
|
146
|
-
}
|
|
233
|
+
},
|
|
147
234
|
|
|
148
|
-
marks:
|
|
235
|
+
marks: {
|
|
149
236
|
position: 'absolute' as const,
|
|
150
237
|
width: '100%',
|
|
151
238
|
height: '100%',
|
|
152
239
|
top: 0,
|
|
153
240
|
left: 0,
|
|
154
|
-
}
|
|
241
|
+
},
|
|
155
242
|
|
|
156
|
-
mark:
|
|
243
|
+
mark: {
|
|
157
244
|
position: 'absolute' as const,
|
|
158
245
|
width: 2,
|
|
159
246
|
backgroundColor: theme.colors.border.secondary,
|
|
@@ -166,9 +253,9 @@ export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
|
|
|
166
253
|
_web: {
|
|
167
254
|
transform: 'translate(-50%, -50%)',
|
|
168
255
|
},
|
|
169
|
-
}
|
|
256
|
+
},
|
|
170
257
|
|
|
171
|
-
markLabel:
|
|
258
|
+
markLabel: {
|
|
172
259
|
position: 'absolute' as const,
|
|
173
260
|
fontSize: 10,
|
|
174
261
|
color: theme.colors.text.secondary,
|
|
@@ -178,5 +265,5 @@ export const sliderStyles = defineStyle('Slider', (theme: Theme) => ({
|
|
|
178
265
|
transform: 'translateX(-50%)',
|
|
179
266
|
whiteSpace: 'nowrap',
|
|
180
267
|
},
|
|
181
|
-
}
|
|
268
|
+
},
|
|
182
269
|
}));
|
|
@@ -5,7 +5,7 @@ import type { SliderProps } from './types';
|
|
|
5
5
|
import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
|
|
6
6
|
import { isIconName } from '../Icon/icon-resolver';
|
|
7
7
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
8
|
-
import { getWebRangeAriaProps, generateAccessibilityId, SLIDER_KEYS } from '../utils/accessibility';
|
|
8
|
+
import { getWebRangeAriaProps, generateAccessibilityId, SLIDER_KEYS, matchesKey } from '../utils/accessibility';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Range slider for selecting numeric values within a min/max range.
|
|
@@ -55,20 +55,21 @@ const Slider = forwardRef<HTMLDivElement, SliderProps>(({
|
|
|
55
55
|
// Apply variants
|
|
56
56
|
sliderStyles.useVariants({
|
|
57
57
|
size,
|
|
58
|
+
intent,
|
|
58
59
|
disabled,
|
|
59
60
|
margin,
|
|
60
61
|
marginVertical,
|
|
61
62
|
marginHorizontal,
|
|
62
63
|
});
|
|
63
64
|
|
|
64
|
-
const containerProps = getWebProps([
|
|
65
|
-
const wrapperProps = getWebProps([sliderStyles.sliderWrapper]);
|
|
66
|
-
const trackProps = getWebProps([
|
|
67
|
-
const thumbIconProps = getWebProps([
|
|
68
|
-
const valueLabelProps = getWebProps([sliderStyles.valueLabel]);
|
|
69
|
-
const minMaxLabelsProps = getWebProps([sliderStyles.minMaxLabels]);
|
|
70
|
-
const minMaxLabelProps = getWebProps([sliderStyles.minMaxLabel]);
|
|
71
|
-
const marksProps = getWebProps([sliderStyles.marks]);
|
|
65
|
+
const containerProps = getWebProps([sliderStyles.container as any, style as any]);
|
|
66
|
+
const wrapperProps = getWebProps([sliderStyles.sliderWrapper as any]);
|
|
67
|
+
const trackProps = getWebProps([sliderStyles.track as any]);
|
|
68
|
+
const thumbIconProps = getWebProps([sliderStyles.thumbIcon as any]);
|
|
69
|
+
const valueLabelProps = getWebProps([sliderStyles.valueLabel as any]);
|
|
70
|
+
const minMaxLabelsProps = getWebProps([sliderStyles.minMaxLabels as any]);
|
|
71
|
+
const minMaxLabelProps = getWebProps([sliderStyles.minMaxLabel as any]);
|
|
72
|
+
const marksProps = getWebProps([sliderStyles.marks as any]);
|
|
72
73
|
|
|
73
74
|
const clampValue = useCallback((val: number) => {
|
|
74
75
|
const clampedValue = Math.min(Math.max(val, min), max);
|
|
@@ -138,26 +139,25 @@ const Slider = forwardRef<HTMLDivElement, SliderProps>(({
|
|
|
138
139
|
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
|
|
139
140
|
if (disabled) return;
|
|
140
141
|
|
|
141
|
-
const key = e.key;
|
|
142
142
|
let newValue = value;
|
|
143
143
|
const largeStep = (max - min) / 10; // 10% of range for PageUp/PageDown
|
|
144
144
|
|
|
145
|
-
if (SLIDER_KEYS.increase
|
|
145
|
+
if (matchesKey(e, SLIDER_KEYS.increase)) {
|
|
146
146
|
e.preventDefault();
|
|
147
147
|
newValue = clampValue(value + step);
|
|
148
|
-
} else if (SLIDER_KEYS.decrease
|
|
148
|
+
} else if (matchesKey(e, SLIDER_KEYS.decrease)) {
|
|
149
149
|
e.preventDefault();
|
|
150
150
|
newValue = clampValue(value - step);
|
|
151
|
-
} else if (SLIDER_KEYS.min
|
|
151
|
+
} else if (matchesKey(e, SLIDER_KEYS.min)) {
|
|
152
152
|
e.preventDefault();
|
|
153
153
|
newValue = min;
|
|
154
|
-
} else if (SLIDER_KEYS.max
|
|
154
|
+
} else if (matchesKey(e, SLIDER_KEYS.max)) {
|
|
155
155
|
e.preventDefault();
|
|
156
156
|
newValue = max;
|
|
157
|
-
} else if (
|
|
157
|
+
} else if (matchesKey(e, SLIDER_KEYS.increaseLarge)) {
|
|
158
158
|
e.preventDefault();
|
|
159
159
|
newValue = clampValue(value + largeStep);
|
|
160
|
-
} else if (
|
|
160
|
+
} else if (matchesKey(e, SLIDER_KEYS.decreaseLarge)) {
|
|
161
161
|
e.preventDefault();
|
|
162
162
|
newValue = clampValue(value - largeStep);
|
|
163
163
|
}
|
|
@@ -215,10 +215,10 @@ const Slider = forwardRef<HTMLDivElement, SliderProps>(({
|
|
|
215
215
|
const percentage = ((value - min) / (max - min)) * 100;
|
|
216
216
|
|
|
217
217
|
// Dynamic styles with percentage
|
|
218
|
-
const filledTrackProps = getWebProps([
|
|
218
|
+
const filledTrackProps = getWebProps([sliderStyles.filledTrack as any, { width: `${percentage}%` }]);
|
|
219
219
|
const thumbProps = getWebProps([
|
|
220
|
-
|
|
221
|
-
isDragging && sliderStyles.thumbActive,
|
|
220
|
+
sliderStyles.thumb as any,
|
|
221
|
+
isDragging && (sliderStyles.thumbActive as any),
|
|
222
222
|
{ left: `${percentage}%` }
|
|
223
223
|
]);
|
|
224
224
|
|
|
@@ -269,8 +269,8 @@ const Slider = forwardRef<HTMLDivElement, SliderProps>(({
|
|
|
269
269
|
<div {...marksProps}>
|
|
270
270
|
{marks.map((mark) => {
|
|
271
271
|
const markPercentage = ((mark.value - min) / (max - min)) * 100;
|
|
272
|
-
const markProps = getWebProps([sliderStyles.mark, { left: `${markPercentage}%` }]);
|
|
273
|
-
const markLabelProps = getWebProps([sliderStyles.markLabel, { left: `${markPercentage}%` }]);
|
|
272
|
+
const markProps = getWebProps([sliderStyles.mark as any, { left: `${markPercentage}%` }]);
|
|
273
|
+
const markLabelProps = getWebProps([sliderStyles.markLabel as any, { left: `${markPercentage}%` }]);
|
|
274
274
|
return (
|
|
275
275
|
<div key={mark.value}>
|
|
276
276
|
<div {...markProps} />
|
|
@@ -287,8 +287,8 @@ const Slider = forwardRef<HTMLDivElement, SliderProps>(({
|
|
|
287
287
|
|
|
288
288
|
{/* Thumb */}
|
|
289
289
|
<div
|
|
290
|
-
ref={thumbRef}
|
|
291
290
|
{...thumbProps}
|
|
291
|
+
ref={thumbRef}
|
|
292
292
|
>
|
|
293
293
|
{renderIcon()}
|
|
294
294
|
</div>
|
package/src/Text/Text.web.tsx
CHANGED
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import { getWebProps } from 'react-native-unistyles/web';
|
|
3
|
-
import {
|
|
3
|
+
import type { Typography, Size } from '@idealyst/theme';
|
|
4
|
+
import { TextProps, TextSizeVariant } from './types';
|
|
4
5
|
import { textStyles } from './Text.styles';
|
|
5
6
|
import useMergeRefs from '../hooks/useMergeRefs';
|
|
6
7
|
|
|
8
|
+
// Map Size values to Typography values
|
|
9
|
+
const SIZE_TO_TYPOGRAPHY: Record<Size, Typography> = {
|
|
10
|
+
'xs': 'caption',
|
|
11
|
+
'sm': 'body2',
|
|
12
|
+
'md': 'body1',
|
|
13
|
+
'lg': 'subtitle1',
|
|
14
|
+
'xl': 'h5',
|
|
15
|
+
'2xl': 'h4',
|
|
16
|
+
'3xl': 'h3',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Convert TextSizeVariant to Typography (handles both Size and Typography values)
|
|
20
|
+
function resolveTypography(value: TextSizeVariant | undefined): Typography {
|
|
21
|
+
if (!value) return 'body1';
|
|
22
|
+
// If it's a Size value, map it to Typography
|
|
23
|
+
if (value in SIZE_TO_TYPOGRAPHY) {
|
|
24
|
+
return SIZE_TO_TYPOGRAPHY[value as Size];
|
|
25
|
+
}
|
|
26
|
+
// Otherwise it's already a Typography value
|
|
27
|
+
return value as Typography;
|
|
28
|
+
}
|
|
29
|
+
|
|
7
30
|
/**
|
|
8
31
|
* Typography component for displaying text with predefined styles and semantic variants.
|
|
9
32
|
* Supports multiple typography scales, colors, weights, and alignments.
|
|
10
33
|
*/
|
|
11
34
|
const Text = forwardRef<HTMLSpanElement, TextProps>(({
|
|
12
35
|
children,
|
|
13
|
-
typography
|
|
36
|
+
typography: typographyProp,
|
|
37
|
+
size,
|
|
14
38
|
weight,
|
|
15
39
|
color = 'primary',
|
|
16
40
|
align = 'left',
|
|
17
|
-
pre = false,
|
|
18
41
|
// Spacing variants from TextSpacingStyleProps
|
|
19
42
|
gap,
|
|
20
43
|
padding,
|
|
@@ -24,6 +47,9 @@ const Text = forwardRef<HTMLSpanElement, TextProps>(({
|
|
|
24
47
|
testID,
|
|
25
48
|
id,
|
|
26
49
|
}, ref) => {
|
|
50
|
+
// size is an alias for typography - size takes precedence if both are set
|
|
51
|
+
const typography = resolveTypography(size ?? typographyProp);
|
|
52
|
+
|
|
27
53
|
textStyles.useVariants({
|
|
28
54
|
typography,
|
|
29
55
|
weight,
|
package/src/Text/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Text, Typography } from '@idealyst/theme';
|
|
1
|
+
import { Text, Typography, Size } from '@idealyst/theme';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import type { StyleProp, TextStyle } from 'react-native';
|
|
4
4
|
import { TextSpacingStyleProps } from '../utils/viewStyleProps';
|
|
@@ -8,6 +8,12 @@ export type TextColorVariant = Text;
|
|
|
8
8
|
export type TextWeightVariant = 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
|
|
9
9
|
export type TextAlignVariant = 'left' | 'center' | 'right';
|
|
10
10
|
export type TextTypographyVariant = Typography;
|
|
11
|
+
/**
|
|
12
|
+
* Text size variant - accepts both Typography values and Size shorthand
|
|
13
|
+
* Typography: 'h1', 'h2', 'body1', 'caption', etc.
|
|
14
|
+
* Size: 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'
|
|
15
|
+
*/
|
|
16
|
+
export type TextSizeVariant = Typography | Size;
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
19
|
* Typography component for rendering text with consistent styling.
|
|
@@ -25,6 +31,13 @@ export interface TextProps extends TextSpacingStyleProps {
|
|
|
25
31
|
*/
|
|
26
32
|
typography?: TextTypographyVariant;
|
|
27
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Text size - accepts Typography names or Size shorthand.
|
|
36
|
+
* Typography: 'h1', 'h2', 'body1', 'caption', etc.
|
|
37
|
+
* Size: 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'
|
|
38
|
+
*/
|
|
39
|
+
size?: TextSizeVariant;
|
|
40
|
+
|
|
28
41
|
/**
|
|
29
42
|
* The weight of the text.
|
|
30
43
|
* Overrides the weight from typography if both are set.
|