@campxdev/react-native-blueprint 0.1.15 → 0.1.17

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.
Files changed (58) hide show
  1. package/global.css +672 -0
  2. package/lib/module/assets/Success-Tick.json +1 -0
  3. package/lib/module/assets/lotties/index.js +2 -1
  4. package/lib/module/assets/lotties/index.js.map +1 -1
  5. package/lib/module/components/DataDisplay/Banner/Banner.figma.js +25 -0
  6. package/lib/module/components/DataDisplay/Banner/Banner.figma.js.map +1 -0
  7. package/lib/module/components/DataDisplay/Banner/Banner.js +101 -0
  8. package/lib/module/components/DataDisplay/Banner/Banner.js.map +1 -0
  9. package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js +15 -0
  10. package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js.map +1 -0
  11. package/lib/module/components/DataDisplay/Greeting/Greeting.js +121 -0
  12. package/lib/module/components/DataDisplay/Greeting/Greeting.js.map +1 -0
  13. package/lib/module/components/DataDisplay/MonthCalendar/MonthCalendar.figma.js +5 -7
  14. package/lib/module/components/DataDisplay/MonthCalendar/MonthCalendar.figma.js.map +1 -1
  15. package/lib/module/components/Input/TextField/Textfield.js +77 -21
  16. package/lib/module/components/Input/TextField/Textfield.js.map +1 -1
  17. package/lib/module/components/ui/index.js +2 -1
  18. package/lib/module/components/ui/index.js.map +1 -1
  19. package/lib/module/index.js +3 -0
  20. package/lib/module/index.js.map +1 -1
  21. package/lib/module/patterns/pattern-components/BottomSheetPattern/index.js +4 -0
  22. package/lib/module/patterns/pattern-components/BottomSheetPattern/index.js.map +1 -0
  23. package/lib/module/patterns/pattern-components/CalendarPattern/index.js +4 -0
  24. package/lib/module/patterns/pattern-components/CalendarPattern/index.js.map +1 -0
  25. package/lib/module/patterns/pattern-components/DashboardPattern/index.js +4 -0
  26. package/lib/module/patterns/pattern-components/DashboardPattern/index.js.map +1 -0
  27. package/lib/module/patterns/pattern-components/EntityPatternGuided/index.js +4 -0
  28. package/lib/module/patterns/pattern-components/EntityPatternGuided/index.js.map +1 -0
  29. package/lib/module/patterns/pattern-components/SuccessPattern/SuccessPattern.figma.js +38 -0
  30. package/lib/module/patterns/pattern-components/SuccessPattern/SuccessPattern.figma.js.map +1 -0
  31. package/lib/module/patterns/pattern-components/SuccessPattern/SuccessPattern.js +91 -0
  32. package/lib/module/patterns/pattern-components/SuccessPattern/SuccessPattern.js.map +1 -0
  33. package/lib/module/patterns/pattern-components/SuccessPattern/index.js +4 -0
  34. package/lib/module/patterns/pattern-components/SuccessPattern/index.js.map +1 -0
  35. package/lib/module/patterns/pattern-components/index.js +4 -3
  36. package/lib/module/patterns/pattern-components/index.js.map +1 -1
  37. package/package.json +5 -3
  38. package/src/assets/Success-Tick.json +1 -0
  39. package/src/assets/lotties/index.ts +1 -0
  40. package/src/components/DataDisplay/Banner/Banner.figma.tsx +26 -0
  41. package/src/components/DataDisplay/Banner/Banner.tsx +108 -0
  42. package/src/components/DataDisplay/Greeting/Greeting.figma.tsx +12 -0
  43. package/src/components/DataDisplay/Greeting/Greeting.tsx +154 -0
  44. package/src/components/DataDisplay/MonthCalendar/MonthCalendar.figma.tsx +7 -11
  45. package/src/components/Input/TextField/Textfield.tsx +118 -33
  46. package/src/components/ui/index.ts +3 -1
  47. package/src/index.tsx +3 -0
  48. package/src/patterns/pattern-components/BottomSheetPattern/index.ts +1 -0
  49. package/src/patterns/pattern-components/CalendarPattern/index.ts +1 -0
  50. package/src/patterns/pattern-components/DashboardPattern/index.ts +1 -0
  51. package/src/patterns/pattern-components/EntityPatternGuided/index.ts +1 -0
  52. package/src/patterns/pattern-components/SuccessPattern/SuccessPattern.figma.tsx +38 -0
  53. package/src/patterns/pattern-components/SuccessPattern/SuccessPattern.tsx +119 -0
  54. package/src/patterns/pattern-components/SuccessPattern/index.ts +2 -0
  55. package/src/patterns/pattern-components/index.ts +2 -1
  56. package/lib/module/components/ui/Greeting-Card.js +0 -393
  57. package/lib/module/components/ui/Greeting-Card.js.map +0 -1
  58. package/src/components/ui/Greeting-Card.tsx +0 -472
@@ -5,7 +5,7 @@ import * as Slot from '@rn-primitives/slot';
5
5
  import type { SlottableViewProps, ViewRef } from '@rn-primitives/types';
6
6
  import { cva, type VariantProps } from 'class-variance-authority';
7
7
  import { cssInterop } from 'nativewind';
8
- import { View, TextInput } from 'react-native';
8
+ import { View, TextInput, Pressable } from 'react-native';
9
9
  import type { LucideIcon } from 'lucide-react-native';
10
10
  import LottieView from 'lottie-react-native';
11
11
  import { SquircleView } from 'react-native-figma-squircle';
@@ -259,9 +259,67 @@ const TextField = React.forwardRef<ViewRef, TextFieldProps>(
259
259
  };
260
260
 
261
261
  // Handle code type (OTP-style boxes)
262
+ const hiddenInputRef = React.useRef<TextInput>(null);
263
+ const [isFocused, setIsFocused] = React.useState(false);
264
+ const [selection, setSelection] = React.useState({
265
+ start: (inputProps?.value as string)?.length || 0,
266
+ end: (inputProps?.value as string)?.length || 0,
267
+ });
268
+
269
+ const codeLength = 6;
270
+ const codeValue = (inputProps?.value as string) || '';
271
+
272
+ const handlePress = React.useCallback((index: number) => {
273
+ setIsFocused(true);
274
+ setSelection({ start: index, end: index });
275
+ // Focus on next frame to avoid navigation context issues
276
+ setTimeout(() => {
277
+ hiddenInputRef.current?.focus();
278
+ }, 0);
279
+ }, []);
280
+
281
+ const handleChangeText = React.useCallback(
282
+ (text: string) => {
283
+ // Only keep numbers
284
+ const numericText = text.replace(/[^0-9]/g, '');
285
+
286
+ // Update the value through inputProps.onChangeText if available
287
+ if (inputProps?.onChangeText) {
288
+ inputProps.onChangeText(numericText);
289
+ }
290
+
291
+ // Auto-focus to next box when digit is entered
292
+ if (
293
+ numericText.length < codeLength &&
294
+ selection.start < codeLength - 1
295
+ ) {
296
+ setSelection({
297
+ start: selection.start + 1,
298
+ end: selection.start + 1,
299
+ });
300
+ }
301
+ },
302
+ [selection.start, codeLength, inputProps]
303
+ );
304
+
305
+ const handleKeyPress = React.useCallback(
306
+ (e: any) => {
307
+ // Handle backspace to go to previous box
308
+ if (
309
+ e.nativeEvent.key === 'Backspace' &&
310
+ selection.start > 0 &&
311
+ codeValue.length === selection.start
312
+ ) {
313
+ setSelection({
314
+ start: selection.start - 1,
315
+ end: selection.start - 1,
316
+ });
317
+ }
318
+ },
319
+ [selection.start, codeValue.length]
320
+ );
321
+
262
322
  if (type === 'code') {
263
- const codeLength = 6;
264
- const codeValue = (inputProps?.value as string) || '';
265
323
  const codeBoxes = Array.from({ length: codeLength }).map(
266
324
  (_, i) => codeValue[i] || ''
267
325
  );
@@ -276,39 +334,61 @@ const TextField = React.forwardRef<ViewRef, TextFieldProps>(
276
334
  )}
277
335
 
278
336
  <StyledView className="flex-row gap-2 justify-between">
279
- {codeBoxes.map((char, index) => (
280
- <StyledView
281
- key={index}
282
- className={cn(
283
- 'flex-1 items-center justify-center border rounded-md px-3 py-4',
284
- index === codeValue.length
285
- ? 'border-brand-primary ring-1 ring-brand-primary'
286
- : state === 'error'
287
- ? 'border-highlight-alert-red'
288
- : 'border-border-default',
289
- 'bg-surface-default'
290
- )}
291
- >
292
- <Text
293
- className={cn(
294
- 'text-sm font-medium',
295
- state === 'error'
296
- ? 'text-highlight-alert-red'
297
- : 'text-text-primary'
298
- )}
337
+ {codeBoxes.map((char, index) => {
338
+ const isActive = selection.start === index && isFocused;
339
+
340
+ return (
341
+ <Pressable
342
+ key={index}
343
+ onPress={() => handlePress(index)}
344
+ className="flex-1"
299
345
  >
300
- {char || 'X'}
301
- </Text>
302
- </StyledView>
303
- ))}
346
+ <StyledView
347
+ className={cn(
348
+ 'items-center justify-center border rounded-md px-3 py-4',
349
+ isActive
350
+ ? 'border-brand-primary ring-1 ring-brand-primary'
351
+ : state === 'error'
352
+ ? 'border-highlight-alert-red'
353
+ : 'border-border-default',
354
+ 'bg-surface-default'
355
+ )}
356
+ >
357
+ <Text
358
+ className={cn(
359
+ 'text-sm font-medium',
360
+ state === 'error'
361
+ ? 'text-highlight-alert-red'
362
+ : 'text-text-primary'
363
+ )}
364
+ >
365
+ {char || ''}
366
+ </Text>
367
+ </StyledView>
368
+ </Pressable>
369
+ );
370
+ })}
304
371
  </StyledView>
305
372
 
306
373
  {/* Hidden input for actual text input */}
307
374
  <StyledTextInput
308
375
  {...inputProps}
376
+ ref={hiddenInputRef}
309
377
  maxLength={codeLength}
310
378
  editable={!isDisabled}
311
- style={{ position: 'absolute', opacity: 0, width: 0, height: 0 }}
379
+ keyboardType="number-pad"
380
+ textContentType="oneTimeCode"
381
+ value={codeValue}
382
+ onChangeText={handleChangeText}
383
+ onKeyPress={handleKeyPress}
384
+ selection={selection}
385
+ onSelectionChange={(e: any) =>
386
+ setSelection(e.nativeEvent.selection)
387
+ }
388
+ onFocus={() => setIsFocused(true)}
389
+ onBlur={() => setIsFocused(false)}
390
+ multiline={false}
391
+ className="absolute opacity-0 w-0 h-0"
312
392
  />
313
393
 
314
394
  {showHelpText && (
@@ -330,7 +410,10 @@ const TextField = React.forwardRef<ViewRef, TextFieldProps>(
330
410
  </StyledView>
331
411
  )}
332
412
 
333
- <View style={{ overflow: 'hidden', borderRadius: CORNER_RADIUS }}>
413
+ <View
414
+ key={`squircle-${state}`}
415
+ style={{ overflow: 'hidden', borderRadius: CORNER_RADIUS }}
416
+ >
334
417
  <SquircleView
335
418
  squircleParams={{
336
419
  cornerRadius: CORNER_RADIUS,
@@ -352,7 +435,7 @@ const TextField = React.forwardRef<ViewRef, TextFieldProps>(
352
435
 
353
436
  <StyledTextInput
354
437
  {...inputProps}
355
- multiline
438
+ multiline={type === 'composer' || inputProps?.multiline}
356
439
  editable={!isDisabled}
357
440
  placeholder={getPlaceholder()}
358
441
  className={cn(
@@ -377,17 +460,19 @@ const TextField = React.forwardRef<ViewRef, TextFieldProps>(
377
460
  loop
378
461
  style={{ width: 48, height: 48, marginLeft: 8 }}
379
462
  />
380
- ) : showRightIcon && RightIcon ? (
463
+ ) : showRightIcon &&
464
+ RightIcon &&
465
+ typeof RightIcon !== 'undefined' ? (
381
466
  typeof RightIcon === 'function' ? (
382
467
  <RightIcon
383
468
  size={16}
384
469
  className={cn('ml-2 mt-1', iconVariants({ state }))}
385
470
  />
386
- ) : (
471
+ ) : React.isValidElement(RightIcon) ? (
387
472
  <StyledView className={cn('ml-2 mt-1')}>
388
473
  {RightIcon}
389
474
  </StyledView>
390
- )
475
+ ) : null
391
476
  ) : null}
392
477
  </Component>
393
478
  </SquircleView>
@@ -8,6 +8,7 @@ export * from '../Navigation/Appbar/AppBar';
8
8
  export * from '../Layout/AspectRatio/Aspect-Ratio';
9
9
  export * from '../DataDisplay/Avatar/Avatar';
10
10
  export * from '../DataDisplay/Badge/Badge';
11
+ export * from '../DataDisplay/Banner/Banner';
11
12
  export * from '../DataDisplay/Chips/Chips';
12
13
  export * from '../DataDisplay/ChipsRow/ChipsRow';
13
14
  export * from '../DataDisplay/BannerRow/BannerRow';
@@ -18,6 +19,7 @@ export * from '../Layout/Bottomsheet/Bottom-Sheet';
18
19
  export * from '../Input/Button/Button';
19
20
  export * from '../DataDisplay/Card/Card';
20
21
  export * from '../DataDisplay/CalendarItem/CalendarItem';
22
+ export * from '../DataDisplay/Greeting/Greeting';
21
23
  export * from '../DataDisplay/MonthCalendar/MonthCalendar';
22
24
  export * from '../DataDisplay/DataCard/DataCard';
23
25
  export * from '../Input/Checkbox/Checkbox';
@@ -27,7 +29,7 @@ export * from './Custom-Card';
27
29
  export * from '../Navigation/Dialog/Dialog';
28
30
  export * from './Dropdown-Menu';
29
31
  export * from '../Navigation/FloatingAction/Floating-Action';
30
- export * from './Greeting-Card';
32
+
31
33
  export * from './Hover-Card';
32
34
  export * from './Icon';
33
35
  export * from './Input';
package/src/index.tsx CHANGED
@@ -1,6 +1,9 @@
1
1
  // Export components
2
2
  export * from './components/ui';
3
3
 
4
+ // Export patterns
5
+ export * from './patterns/pattern-components';
6
+
4
7
  // Export layout
5
8
  export { default as RootLayout } from './app/_layout';
6
9
 
@@ -0,0 +1 @@
1
+ export { BottomSheetPattern } from './BottomSheetPattern';
@@ -0,0 +1 @@
1
+ export { CalendarPattern } from './CalendarPattern';
@@ -0,0 +1 @@
1
+ export { DashboardPattern } from './DashboardPattern';
@@ -0,0 +1 @@
1
+ export { EntityPatternGuided } from './EntityPatternGuided';
@@ -0,0 +1,38 @@
1
+ import figma from '@figma/code-connect';
2
+ import { SuccessPattern } from './SuccessPattern';
3
+
4
+ const FIGMA_URL =
5
+ 'https://www.figma.com/design/66WaqopqU3WXgwVtyQuTUf/React-Native-Blueprint-Library?node-id=411-3184';
6
+
7
+ /**
8
+ * SuccessPattern - Success state pattern with animated checkmark
9
+ *
10
+ * Use cases:
11
+ * - Order confirmation screens
12
+ * - Form submission success
13
+ * - Action completion feedback
14
+ * - Payment confirmation
15
+ * - Task completion states
16
+ *
17
+ * Features:
18
+ * - Animated success tick using Lottie (Success-Tick.json)
19
+ * - Customizable success message
20
+ * - Optional description text
21
+ * - Configurable animation behavior (loop, autoplay, duration)
22
+ * - Callback when animation completes
23
+ */
24
+ figma.connect(SuccessPattern, FIGMA_URL, {
25
+ props: {
26
+ successMessage: figma.string('SuccessMessage'),
27
+ description: figma.string('Description'),
28
+ },
29
+ example: (props) => (
30
+ <SuccessPattern
31
+ successMessage={props.successMessage}
32
+ description={props.description}
33
+ showAnimation={true}
34
+ autoplay={true}
35
+ loop={false}
36
+ />
37
+ ),
38
+ });
@@ -0,0 +1,119 @@
1
+ // @ts-nocheck
2
+ import React from 'react';
3
+ import { View as RNView } from 'react-native';
4
+ import { cssInterop } from 'nativewind';
5
+ import LottieView from 'lottie-react-native';
6
+ import { cn } from '../../../lib/utils';
7
+ import { Text } from '../../../components/Input/Text/Text';
8
+
9
+ cssInterop(RNView, { className: 'style' });
10
+
11
+ const View = RNView as React.ComponentType<
12
+ React.ComponentProps<typeof RNView> & { className?: string }
13
+ >;
14
+
15
+ /* ============================================================================
16
+ * Types
17
+ * ============================================================================ */
18
+
19
+ export interface SuccessPatternProps {
20
+ /** Main success message text */
21
+ successMessage?: string;
22
+ /** Secondary description text */
23
+ description?: string;
24
+ /** Whether to show the lottie animation */
25
+ showAnimation?: boolean;
26
+ /** Animation duration in milliseconds */
27
+ animationDuration?: number;
28
+ /** Loop the animation */
29
+ loop?: boolean;
30
+ /** Auto-play the animation */
31
+ autoplay?: boolean;
32
+ /** Custom className for styling */
33
+ className?: string;
34
+ /** Test ID for testing */
35
+ testID?: string;
36
+ /** Callback when animation completes */
37
+ onAnimationFinish?: () => void;
38
+ }
39
+
40
+ /* ============================================================================
41
+ * Component
42
+ * ============================================================================ */
43
+
44
+ /**
45
+ * SuccessPattern Component
46
+ *
47
+ * A pattern component that displays a success state with:
48
+ * - Animated success tick/checkmark (Lottie animation)
49
+ * - Success message
50
+ * - Description text
51
+ *
52
+ * Perfect for use after form submissions, confirmations, or successful operations.
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * <SuccessPattern
57
+ * successMessage="Order Placed Successfully!"
58
+ * description="Your order has been confirmed"
59
+ * showAnimation={true}
60
+ * onAnimationFinish={() => navigation.navigate('Home')}
61
+ * />
62
+ * ```
63
+ */
64
+ export const SuccessPattern = ({
65
+ successMessage = 'This is the Success Message',
66
+ description = 'Success message descriptions goes here',
67
+ showAnimation = true,
68
+ animationDuration = 2000,
69
+ loop = false,
70
+ autoplay = true,
71
+ className,
72
+ testID,
73
+ onAnimationFinish,
74
+ }: SuccessPatternProps) => {
75
+ const animationRef = React.useRef<any>(null);
76
+
77
+ React.useEffect(() => {
78
+ if (autoplay && animationRef.current && showAnimation) {
79
+ animationRef.current.play();
80
+ }
81
+ }, [showAnimation, autoplay]);
82
+
83
+ return (
84
+ <View
85
+ testID={testID}
86
+ className={cn(
87
+ 'w-full items-center justify-center bg-surface-page',
88
+ className
89
+ )}
90
+ >
91
+ {/* Animation Container */}
92
+ {showAnimation && (
93
+ <View className="h-60 w-60 items-center justify-center">
94
+ <LottieView
95
+ ref={animationRef}
96
+ source={require('../../../assets/Success-Tick.json')}
97
+ autoPlay={autoplay}
98
+ loop={loop}
99
+ duration={animationDuration}
100
+ onAnimationFinish={onAnimationFinish}
101
+ style={{ width: 300, height: 300 }}
102
+ />
103
+ </View>
104
+ )}
105
+
106
+ {/* Content Section */}
107
+ <View className="w-full items-center gap-2 text-center px-4 py-6">
108
+ <Text className="text-lg font-semibold text-text-primary">
109
+ {successMessage}
110
+ </Text>
111
+ <Text className="text-sm font-medium text-text-secondary">
112
+ {description}
113
+ </Text>
114
+ </View>
115
+ </View>
116
+ );
117
+ };
118
+
119
+ SuccessPattern.displayName = 'SuccessPattern';
@@ -0,0 +1,2 @@
1
+ export { SuccessPattern } from './SuccessPattern';
2
+ export type { SuccessPatternProps } from './SuccessPattern';
@@ -7,9 +7,10 @@ export * from './CardListPattern';
7
7
  export * from './AlertPattern';
8
8
  export * from './DialogPattern';
9
9
  export * from './SkeletonPattern';
10
+ export * from './SuccessPattern';
10
11
  export * from './FormPattern';
11
12
  export * from './EntityPatternOverview';
12
13
  export * from './EntityPatternStructured';
13
14
  export * from './EntityPatternGuided';
14
- export * from './CalendarPattern/CalendarPattern';
15
+ export * from './CalendarPattern';
15
16
  export * from './MonthlyCalendarPattern';