@compsych/mobile-ui 1.0.19 → 1.0.21

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compsych/mobile-ui",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "ComPsych React Native Design System — 19 mobile UI components with self-contained design tokens",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -2,13 +2,13 @@ import React from 'react';
2
2
 
3
3
  import {
4
4
  Pressable,
5
+ ScrollView,
5
6
  StyleProp,
6
7
  StyleSheet,
7
- View,
8
8
  ViewStyle,
9
9
  } from 'react-native';
10
10
 
11
- import { ICON_MAP, type IconName } from '../../icons';
11
+ import { type IconName, SIZE_MAP, resolveIcon } from '../../icons';
12
12
  import { useTheme } from '../../theme';
13
13
  import { BodyText } from '../BodyText';
14
14
 
@@ -23,7 +23,6 @@ export interface SegmentedControlProps {
23
23
  options: SegmentedControlOption[];
24
24
  value: string;
25
25
  onChange: (value: string) => void;
26
- fullWidth?: boolean;
27
26
  style?: StyleProp<ViewStyle>;
28
27
  }
29
28
 
@@ -31,27 +30,19 @@ export function SegmentedControl({
31
30
  options,
32
31
  value,
33
32
  onChange,
34
- fullWidth = false,
35
33
  style,
36
34
  }: SegmentedControlProps) {
37
35
  const { colorRoles: cr, dimensions: dim } = useTheme();
38
36
 
39
37
  return (
40
- <View
41
- style={[
42
- styles.container,
43
- {
44
- backgroundColor:
45
- cr.surface.surfaceContainer.sysSurfaceContainerLowest,
46
- borderWidth: dim.borderWidth.sysStrokeThin,
47
- borderColor: cr.outline.sysOutline,
48
- borderRadius: dim.borderRadius.sysRadiusFull,
49
- padding: dim.spacing.padding.sysPadding4,
50
- gap: dim.spacing.padding.sysPadding4,
51
- },
52
- fullWidth && styles.fullWidth,
53
- style,
38
+ <ScrollView
39
+ horizontal
40
+ showsHorizontalScrollIndicator={false}
41
+ contentContainerStyle={[
42
+ styles.contentContainer,
43
+ { gap: dim.spacing.padding.sysPadding4 },
54
44
  ]}
45
+ style={[styles.scroll, style]}
55
46
  >
56
47
  {options.map((option) => {
57
48
  const isActive = option.value === value;
@@ -60,7 +51,8 @@ export function SegmentedControl({
60
51
  const iconColor = isActive
61
52
  ? cr.accent.primary.sysOnPrimary
62
53
  : cr.surface.surface.sysOnSurfaceVariant;
63
- const IconComponent = option.icon ? ICON_MAP[option.icon] : null;
54
+ const IconComponent = option.icon ? resolveIcon(option.icon) : null;
55
+ const { size: iconPx, strokeWidth: iconSW } = SIZE_MAP['xsmall'];
64
56
 
65
57
  return (
66
58
  <Pressable
@@ -76,17 +68,21 @@ export function SegmentedControl({
76
68
  paddingVertical: dim.spacing.padding.sysPadding6,
77
69
  gap: dim.spacing.padding.sysPadding4,
78
70
  borderRadius: dim.borderRadius.sysRadiusFull,
71
+ backgroundColor: isActive
72
+ ? cr.accent.primary.sysPrimary
73
+ : cr.surface.surfaceContainer.sysSurfaceContainerHigh,
79
74
  },
80
- isActive && { backgroundColor: cr.accent.primary.sysPrimary },
81
- !isActive &&
82
- pressed &&
83
- !isDisabled && {
84
- backgroundColor: cr.transparent.neutral.sysBlack10,
85
- },
75
+ !isActive && pressed && !isDisabled && { opacity: 0.7 },
86
76
  isDisabled && styles.disabled,
87
77
  ]}
88
78
  >
89
- {IconComponent && <IconComponent size="xsmall" color={iconColor} />}
79
+ {IconComponent && (
80
+ <IconComponent
81
+ size={iconPx}
82
+ strokeWidth={iconSW}
83
+ color={iconColor}
84
+ />
85
+ )}
90
86
  <BodyText
91
87
  variant="small"
92
88
  emphasized={isActive}
@@ -98,27 +94,20 @@ export function SegmentedControl({
98
94
  </Pressable>
99
95
  );
100
96
  })}
101
- </View>
97
+ </ScrollView>
102
98
  );
103
99
  }
104
100
 
105
101
  const styles = StyleSheet.create({
106
- container: {
102
+ scroll: {
103
+ width: '100%',
104
+ },
105
+ contentContainer: {
107
106
  flexDirection: 'row',
108
107
  alignItems: 'center',
109
- alignSelf: 'flex-start',
110
- // Elevation/lv1: two Figma drop shadows combined into one RN shadow
111
- shadowColor: '#000',
112
- shadowOffset: { width: 0, height: 2 },
113
- shadowOpacity: 0.08,
114
- shadowRadius: 8,
115
- elevation: 2,
116
- },
117
- fullWidth: {
118
- alignSelf: 'stretch',
108
+ paddingVertical: 2,
119
109
  },
120
110
  item: {
121
- flex: 1,
122
111
  flexDirection: 'row',
123
112
  alignItems: 'center',
124
113
  justifyContent: 'center',
@@ -211,7 +211,8 @@ export function ServiceCard({
211
211
  v.elevated && ELEVATION,
212
212
  fullWidth && { alignSelf: 'stretch' as const },
213
213
  isRow ? styles.rowRoot : styles.colRoot,
214
- !isRow && { gap: s.gap },
214
+ !isRow && variant !== 'image' && { gap: s.gap },
215
+ variant === 'image' && { justifyContent: 'space-between' },
215
216
  style,
216
217
  ];
217
218
 
@@ -294,13 +295,12 @@ export function ServiceCard({
294
295
  resizeMode="cover"
295
296
  accessible={false}
296
297
  />
297
- <View
298
+ <LinearGradient
299
+ colors={['rgba(0,0,0,0.4)', 'rgba(0,0,0,0.05)', 'rgba(0,0,0,0.5)']}
300
+ locations={[0.012, 0.268, 1]}
298
301
  style={[
299
302
  { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 },
300
- {
301
- borderRadius: s.borderRadius,
302
- backgroundColor: 'rgba(0,0,0,0.30)',
303
- },
303
+ { borderRadius: s.borderRadius },
304
304
  ]}
305
305
  pointerEvents="none"
306
306
  />
@@ -311,10 +311,14 @@ export function ServiceCard({
311
311
  {renderedIcon}
312
312
  </View>
313
313
  )}
314
- {textBlock}
315
- {isRow && ChevronRight && (
316
- <ChevronRight size={20} color="#ffffff" strokeWidth={1.5} />
317
- )}
314
+ <View style={styles.imageBottom}>
315
+ <View style={{ flex: 1 }}>{textBlock}</View>
316
+ {onPress && ChevronRight && (
317
+ <View style={styles.imageArrowButton}>
318
+ <ChevronRight size={16} color={cr.surface.surface.sysOnSurface} strokeWidth={1.5} />
319
+ </View>
320
+ )}
321
+ </View>
318
322
  {children}
319
323
  </>
320
324
  );
@@ -398,6 +402,21 @@ const styles = StyleSheet.create({
398
402
  alignItems: 'center',
399
403
  gap: 12,
400
404
  },
405
+ imageBottom: {
406
+ flexDirection: 'row',
407
+ alignItems: 'flex-end',
408
+ width: '100%',
409
+ gap: 16,
410
+ },
411
+ imageArrowButton: {
412
+ width: 32,
413
+ height: 32,
414
+ borderRadius: 999,
415
+ backgroundColor: '#ffffff',
416
+ alignItems: 'center',
417
+ justifyContent: 'center',
418
+ flexShrink: 0,
419
+ },
401
420
  rowTextBlock: {
402
421
  flex: 1,
403
422
  minWidth: 0,