@campxdev/react-native-blueprint 0.1.19 → 0.1.23

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.
@@ -1,25 +1,17 @@
1
1
  // @ts-nocheck
2
+ import { cva, type VariantProps } from 'class-variance-authority';
2
3
  import * as React from 'react';
3
4
  import {
4
5
  Pressable,
5
- View,
6
6
  Text as RNText,
7
+ View,
7
8
  type GestureResponderEvent,
9
+ type PressableProps,
8
10
  type StyleProp,
9
11
  type ViewStyle,
10
- type PressableProps,
11
12
  } from 'react-native';
12
- import { cssInterop } from 'nativewind';
13
13
  import { SquircleView } from 'react-native-figma-squircle';
14
- import { cva, type VariantProps } from 'class-variance-authority';
15
-
16
- import { cn } from '../../../lib/utils';
17
- import { useThemeColors } from '../../../lib/theme';
18
-
19
- // NativeWind interop (className -> style)
20
- cssInterop(Pressable, { className: 'style' });
21
- cssInterop(View, { className: 'style' });
22
- cssInterop(RNText, { className: 'style' });
14
+ import { useTheme } from '../../shared/theme';
23
15
 
24
16
  /**
25
17
  * ✅ Canonical values (match Figma)
@@ -30,31 +22,38 @@ export const ButtonVariants = {
30
22
  } as const;
31
23
 
32
24
  /**
33
- * Local lightweight placeholder icon (used in demos/tests)
34
- * ✅ No inline styles (satisfies react-native/no-inline-styles)
25
+ * Local lightweight placeholder icon
35
26
  */
36
27
  function DummyIcon({ testID }: { testID?: string }) {
37
- return <View testID={testID} className="w-4 h-4 rounded bg-text-inverse" />;
28
+ return (
29
+ <View
30
+ testID={testID}
31
+ style={{
32
+ width: 16,
33
+ height: 16,
34
+ borderRadius: 4,
35
+ backgroundColor: '#6a7282',
36
+ }}
37
+ />
38
+ );
38
39
  }
39
40
 
40
41
  /**
41
- * Returns squircle fill & stroke colors per variant from THEME tokens
42
+ * Returns squircle fill & stroke colors per variant from theme
42
43
  */
43
- function useVariantSquircleParams(variant: string) {
44
- const colors = useThemeColors();
45
-
44
+ function useVariantSquircleParams(variant: string, colors: any) {
46
45
  const map: Record<
47
46
  string,
48
47
  { fillColor: string; strokeColor: string; strokeWidth: number }
49
48
  > = {
50
49
  default: {
51
- fillColor: colors.brandPrimary,
50
+ fillColor: colors.primary,
52
51
  strokeColor: 'transparent',
53
52
  strokeWidth: 0,
54
53
  },
55
54
  secondary: {
56
- fillColor: colors.brandSecondary,
57
- strokeColor: colors.brandPrimary,
55
+ fillColor: colors.secondary,
56
+ strokeColor: colors.primary,
58
57
  strokeWidth: 1,
59
58
  },
60
59
  outline: {
@@ -82,37 +81,34 @@ function useVariantSquircleParams(variant: string) {
82
81
  return map[variant] ?? map.default;
83
82
  }
84
83
 
85
- const CORNER_RADIUS = 8; // radius-lg
86
- const CORNER_SMOOTHING = 1; // maximum smoothing
84
+ const CORNER_RADIUS = 12;
85
+ const CORNER_SMOOTHING = 1;
87
86
 
88
87
  const buttonVariants = cva('flex-row items-center justify-center', {
89
88
  variants: {
90
89
  variant: {
91
- default: 'gap-2 active:opacity-90',
92
- secondary: 'active:opacity-90',
93
- outline: 'active:opacity-90',
94
- ghost: 'active:opacity-90',
95
- destructive: 'active:opacity-90',
90
+ default: 'gap-2',
91
+ secondary: 'gap-2',
92
+ outline: 'gap-2',
93
+ ghost: 'gap-2',
94
+ destructive: 'gap-2',
96
95
  link: '',
97
96
  },
98
97
  size: {
99
- // ✅ Figma-like sizing
100
98
  default: 'py-3 px-5',
101
- lg: 'py-5 px-6',
99
+ lg: 'py-4 px-6',
102
100
  icon: 'h-10 w-10',
103
101
  },
104
102
  disabled: {
105
103
  false: '',
106
104
  true: 'opacity-50',
107
105
  },
108
- // Optional icon toggles still affect spacing correctly
109
106
  hasIcons: {
110
107
  false: '',
111
108
  true: 'gap-2',
112
109
  },
113
110
  },
114
111
  compoundVariants: [
115
- // ✅ Link should not have forced height/padding
116
112
  { variant: 'link', size: 'default', className: 'h-auto p-0' },
117
113
  { variant: 'link', size: 'lg', className: 'h-auto p-0' },
118
114
  { variant: 'link', size: 'icon', className: 'h-auto p-0 w-auto' },
@@ -128,11 +124,11 @@ const buttonVariants = cva('flex-row items-center justify-center', {
128
124
  const buttonTextVariants = cva('font-semibold', {
129
125
  variants: {
130
126
  variant: {
131
- default: 'text-text-inverse',
127
+ default: 'text-white',
132
128
  secondary: 'text-foreground',
133
129
  outline: 'text-foreground',
134
130
  ghost: 'text-foreground',
135
- destructive: 'text-primary-foreground',
131
+ destructive: 'text-white',
136
132
  link: 'text-primary underline',
137
133
  },
138
134
  size: {
@@ -152,21 +148,11 @@ const buttonTextVariants = cva('font-semibold', {
152
148
  },
153
149
  });
154
150
 
155
- /**
156
- * ✅ Strict rule: className must NOT be accepted as a prop.
157
- * So we omit it explicitly from PressableProps.
158
- */
159
151
  type PressablePropsWithoutClassName = Omit<PressableProps, 'style'> & {
160
152
  className?: never;
161
153
  };
162
154
 
163
- /**
164
- * ✅ Backward compatible types:
165
- * - supports boolean disabled (new)
166
- * - supports 'True'/'False' and 'true'/'false' and '1'/'0' (old)
167
- * - supports capitalized variant/size (old)
168
- */
169
- export type ButtonProps = PressablePropsWithoutClassName &
155
+ export type ButtonComponentProps = PressablePropsWithoutClassName &
170
156
  VariantProps<typeof buttonVariants> & {
171
157
  variant?:
172
158
  | (typeof ButtonVariants.variant)[number]
@@ -178,6 +164,8 @@ export type ButtonProps = PressablePropsWithoutClassName &
178
164
 
179
165
  showLeftIcon?: boolean;
180
166
  showRightIcon?: boolean;
167
+ leftIcon?: React.ReactNode;
168
+ rightIcon?: React.ReactNode;
181
169
 
182
170
  style?: StyleProp<ViewStyle>;
183
171
  testID?: string;
@@ -204,13 +192,15 @@ function normalizeDisabled(v: any): boolean {
204
192
  return s === 'true' || s === '1';
205
193
  }
206
194
 
207
- export function Button(props: ButtonProps) {
195
+ export function ButtonComponent(props: ButtonComponentProps) {
208
196
  const {
209
197
  variant,
210
198
  size,
211
199
  disabled,
212
200
  showLeftIcon,
213
201
  showRightIcon,
202
+ leftIcon,
203
+ rightIcon,
214
204
  style,
215
205
  testID,
216
206
  children,
@@ -218,17 +208,16 @@ export function Button(props: ButtonProps) {
218
208
  ...rest
219
209
  } = props;
220
210
 
211
+ const { colors } = useTheme();
212
+
221
213
  const v = normalizeVariant(variant);
222
214
  const s = normalizeSize(size);
223
215
  const d = normalizeDisabled(disabled);
224
216
 
225
- // ✅ icon button must be square and must NOT show label (prevents long button)
226
217
  const isIconOnly = s === 'icon';
227
-
228
- // spacing only when icons exist
229
218
  const hasIcons = Boolean(showLeftIcon || showRightIcon);
230
219
 
231
- const squircleParams = useVariantSquircleParams(v);
220
+ const squircleParams = useVariantSquircleParams(v, colors);
232
221
 
233
222
  const handlePress = React.useCallback(
234
223
  (e: GestureResponderEvent) => {
@@ -238,9 +227,100 @@ export function Button(props: ButtonProps) {
238
227
  [d, onPress]
239
228
  );
240
229
 
230
+ // Get text color based on variant
231
+ const getTextColor = () => {
232
+ switch (v) {
233
+ case 'default':
234
+ return colors.primaryForeground;
235
+ case 'secondary':
236
+ return colors.secondaryForeground;
237
+ case 'outline':
238
+ return colors.foreground;
239
+ case 'ghost':
240
+ return colors.foreground;
241
+ case 'destructive':
242
+ return colors.destructiveForeground;
243
+ case 'link':
244
+ return colors.primary;
245
+ default:
246
+ return colors.primaryForeground;
247
+ }
248
+ };
249
+
250
+ // Get size styles
251
+ const getSizeStyles = () => {
252
+ switch (s) {
253
+ case 'lg':
254
+ return { height: 52, paddingHorizontal: 16 };
255
+ case 'icon':
256
+ return { height: 40, width: 40 };
257
+ case 'default':
258
+ default:
259
+ return { height: 48, paddingHorizontal: 16 };
260
+ }
261
+ };
262
+
263
+ const sizeStyles = getSizeStyles();
264
+
265
+ if (v === 'link') {
266
+ // Link variant doesn't use SquircleView
267
+ return (
268
+ <Pressable
269
+ testID={testID ?? 'button'}
270
+ accessibilityRole="button"
271
+ accessibilityState={{ disabled: d }}
272
+ disabled={d}
273
+ onPress={handlePress}
274
+ style={[
275
+ {
276
+ flexDirection: 'row',
277
+ alignItems: 'center',
278
+ justifyContent: 'center',
279
+ opacity: d ? 0.5 : 1,
280
+ },
281
+ style,
282
+ ]}
283
+ {...rest}
284
+ >
285
+ {showLeftIcon ? (
286
+ leftIcon ? (
287
+ leftIcon
288
+ ) : (
289
+ <DummyIcon testID="button-left-icon" />
290
+ )
291
+ ) : null}
292
+
293
+ {!isIconOnly ? (
294
+ <RNText
295
+ testID="button-label"
296
+ style={{
297
+ color: getTextColor(),
298
+ fontSize: s === 'lg' ? 16 : 14,
299
+ fontWeight: '600',
300
+ textDecorationLine: 'underline',
301
+ }}
302
+ numberOfLines={1}
303
+ ellipsizeMode="tail"
304
+ >
305
+ {children}
306
+ </RNText>
307
+ ) : null}
308
+
309
+ {showRightIcon ? (
310
+ rightIcon ? (
311
+ rightIcon
312
+ ) : (
313
+ <DummyIcon testID="button-right-icon" />
314
+ )
315
+ ) : null}
316
+ </Pressable>
317
+ );
318
+ }
319
+
241
320
  return (
242
321
  <View style={style}>
243
322
  <SquircleView
323
+ style={sizeStyles}
244
324
  squircleParams={{
245
325
  cornerRadius: CORNER_RADIUS,
246
326
  cornerSmoothing: CORNER_SMOOTHING,
@@ -253,24 +333,32 @@ export function Button(props: ButtonProps) {
253
333
  accessibilityState={{ disabled: d }}
254
334
  disabled={d}
255
335
  onPress={handlePress}
256
- className={cn(
257
- buttonVariants({
258
- variant: v,
259
- size: s,
260
- disabled: d,
261
- hasIcons,
262
- })
263
- )}
336
+ style={{
337
+ flex: 1,
338
+ flexDirection: 'row',
339
+ alignItems: 'center',
340
+ justifyContent: 'center',
341
+ gap: hasIcons ? 8 : 0,
342
+ opacity: d ? 0.5 : 1,
343
+ }}
264
344
  {...rest}
265
345
  >
266
- {showLeftIcon ? <DummyIcon testID="button-left-icon" /> : null}
346
+ {showLeftIcon ? (
347
+ leftIcon ? (
348
+ leftIcon
349
+ ) : (
350
+ <DummyIcon testID="button-left-icon" />
351
+ )
352
+ ) : null}
267
353
 
268
354
  {!isIconOnly ? (
269
355
  <RNText
270
356
  testID="button-label"
271
- className={cn(
272
- buttonTextVariants({ variant: v, size: s, disabled: d })
273
- )}
357
+ style={{
358
+ color: getTextColor(),
359
+ fontSize: s === 'lg' ? 16 : 14,
360
+ fontWeight: '600',
361
+ }}
274
362
  numberOfLines={1}
275
363
  ellipsizeMode="tail"
276
364
  >
@@ -278,13 +366,19 @@ export function Button(props: ButtonProps) {
278
366
  </RNText>
279
367
  ) : null}
280
368
 
281
- {showRightIcon ? <DummyIcon testID="button-right-icon" /> : null}
369
+ {showRightIcon ? (
370
+ rightIcon ? (
371
+ rightIcon
372
+ ) : (
373
+ <DummyIcon testID="button-right-icon" />
374
+ )
375
+ ) : null}
282
376
  </Pressable>
283
377
  </SquircleView>
284
378
  </View>
285
379
  );
286
380
  }
287
381
 
288
- Button.displayName = 'Button';
382
+ ButtonComponent.displayName = 'Button';
289
383
 
290
- export { buttonTextVariants, buttonVariants };
384
+ export { ButtonComponent as Button, buttonTextVariants, buttonVariants };
@@ -1,13 +1,13 @@
1
1
  // @ts-nocheck
2
2
  import * as React from 'react';
3
- import { View, Text, type StyleProp, type ViewStyle } from 'react-native';
3
+ import { Text, View, type StyleProp, type ViewStyle } from 'react-native';
4
4
 
5
5
  import { Button } from '../../Input/Button/Button';
6
6
  import {
7
+ PopoverContainer,
8
+ PopoverContent,
7
9
  Popover as PopoverPrimitive,
8
10
  PopoverTrigger,
9
- PopoverContent,
10
- PopoverContainer,
11
11
  } from '../../Layout/PopoverContainer/Popover-Container';
12
12
 
13
13
  /**
@@ -1,62 +1,67 @@
1
1
  // @ts-nocheck
2
- export * from '../DataDisplay/Accordion/Accordion';
3
- export * from '../DataDisplay/AccordionItem/AccordionItem';
4
2
  export * from '../Feedback/Alert/Alert';
5
3
  export * from '../Feedback/AlertDialog/Alert-Dialog';
6
4
  export * from '../Feedback/InfoBar/InfoBar';
5
+ export * from '../Feedback/ProgressCircular/Progress-circular';
6
+ export * from '../Feedback/ProgressLinear/Progress-linear';
7
+ export * from '../Feedback/Stepper/Stepper';
8
+
7
9
  export * from '../Navigation/Appbar/AppBar';
10
+ export * from '../Navigation/ContextMenu/Context-Menu';
11
+ export * from '../Navigation/Dialog/Dialog';
12
+ export * from '../Navigation/FloatingAction/Floating-Action';
13
+ export * from '../Navigation/Navbar/NavBar';
14
+ export * from '../Navigation/Popover/Popover';
15
+ export * from '../Navigation/Themetoggle/Theme-Toggle';
16
+
8
17
  export * from '../Layout/AspectRatio/Aspect-Ratio';
18
+ export * from '../Layout/Bottomsheet/Bottom-Sheet';
19
+ export * from '../Layout/PageContent/PageContent';
20
+ export * from '../Layout/PageLayoutFocused/PageLayoutFocused';
21
+ export * from '../Layout/PageLayoutShell/PageLayoutShell';
22
+ export * from '../Layout/PopoverContainer/Popover-Container';
23
+ export * from '../Layout/Tabs/Tabs';
24
+
9
25
  export * from '../DataDisplay/Avatar/Avatar';
26
+ export * from '../DataDisplay/Accordion/Accordion';
27
+ export * from '../DataDisplay/AccordionItem/AccordionItem';
10
28
  export * from '../DataDisplay/Badge/Badge';
11
29
  export * from '../DataDisplay/Banner/Banner';
12
- export * from '../DataDisplay/Chips/Chips';
13
- export * from '../DataDisplay/ChipsRow/ChipsRow';
14
30
  export * from '../DataDisplay/BannerRow/BannerRow';
15
- export * from '../Layout/PageLayoutShell/PageLayoutShell';
16
- export * from '../Layout/PageLayoutFocused/PageLayoutFocused';
17
- export * from '../Layout/PageContent/PageContent';
18
- export * from '../Layout/Bottomsheet/Bottom-Sheet';
19
- export * from '../Input/Button/Button';
20
- export * from '../DataDisplay/Card/Card';
21
31
  export * from '../DataDisplay/CalendarItem/CalendarItem';
32
+ export * from '../DataDisplay/Card/Card';
33
+ export * from '../DataDisplay/Chips/Chips';
34
+ export * from '../DataDisplay/ChipsRow/ChipsRow';
35
+ export * from '../DataDisplay/DataCard/DataCard';
36
+ export * from '../DataDisplay/Datalist/Datalist';
37
+ export * from '../DataDisplay/DataListItem/DataListItem';
22
38
  export * from '../DataDisplay/FeedCard/FeedCard';
23
39
  export * from '../DataDisplay/Greeting/Greeting';
24
40
  export * from '../DataDisplay/MonthCalendar/MonthCalendar';
25
- export * from '../DataDisplay/DataCard/DataCard';
41
+ export * from '../DataDisplay/Separator/Separator';
42
+ export * from '../DataDisplay/Skeleton/Skeleton';
43
+ export * from '../DataDisplay/Tooltip/Tooltip';
44
+
45
+ export * from '../Input/Button/Button';
26
46
  export * from '../Input/Checkbox/Checkbox';
47
+ export * from '../Input/RadioGroup/Radio-Group';
48
+ export * from '../Input/Select/Select';
49
+ export * from '../Input/switch/Switch';
50
+ export * from '../Input/Text/Text';
51
+ export * from '../Input/TextField/Textfield';
52
+ export * from '../Input/Toggle/Toggle';
53
+ export * from '../Input/ToggleGroup/Toggle-Group';
54
+
27
55
  export * from './Collapsible';
28
- export * from '../Navigation/ContextMenu/Context-Menu';
29
56
  export * from './Custom-Card';
30
- export * from '../Navigation/Dialog/Dialog';
31
57
  export * from './Dropdown-Menu';
32
- export * from '../Navigation/FloatingAction/Floating-Action';
33
58
 
34
59
  export * from './Hover-Card';
35
60
  export * from './Icon';
36
61
  export * from './Input';
37
62
  export * from './Label';
38
63
  export * from './Menubar';
39
- export * from '../Navigation/Navbar/NavBar';
40
- export * from '../Navigation/Popover/Popover';
41
- export * from '../Layout/PopoverContainer/Popover-Container';
42
- export * from '../Feedback/ProgressLinear/Progress-linear';
43
- export * from '../Feedback/ProgressCircular/Progress-circular';
44
- export * from '../Feedback/Stepper/Stepper';
45
- export * from '../Input/RadioGroup/Radio-Group';
46
- export * from '../Input/Select/Select';
47
- export * from '../DataDisplay/Separator/Separator';
48
64
  export * from './SizedBox';
49
- export * from '../DataDisplay/Skeleton/Skeleton';
50
65
  export * from './Slider';
51
- export * from '../Input/switch/Switch';
52
66
  export * from './Table';
53
- export * from '../Layout/Tabs/Tabs';
54
- export * from '../Input/Text/Text';
55
- export * from '../Input/TextField/Textfield';
56
- export * from '../Navigation/Themetoggle/Theme-Toggle';
57
67
  export * from './Toast';
58
- export * from '../Input/Toggle/Toggle';
59
- export * from '../Input/ToggleGroup/Toggle-Group';
60
- export * from '../DataDisplay/Tooltip/Tooltip';
61
- export * from '../DataDisplay/DataListItem/DataListItem';
62
- export * from '../DataDisplay/Datalist/Datalist';
@@ -1 +0,0 @@
1
- {"type":"module"}