@cdx-ui/components 0.0.1-alpha.20 → 0.0.1-alpha.22

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 (50) hide show
  1. package/lib/commonjs/components/BottomSheet/index.js +248 -0
  2. package/lib/commonjs/components/BottomSheet/index.js.map +1 -0
  3. package/lib/commonjs/components/BottomSheet/styles.js +61 -0
  4. package/lib/commonjs/components/BottomSheet/styles.js.map +1 -0
  5. package/lib/commonjs/components/Link/index.js +58 -2
  6. package/lib/commonjs/components/Link/index.js.map +1 -1
  7. package/lib/commonjs/components/Link/styles.js +4 -2
  8. package/lib/commonjs/components/Link/styles.js.map +1 -1
  9. package/lib/commonjs/components/ProgressSegmented/index.js +62 -0
  10. package/lib/commonjs/components/ProgressSegmented/index.js.map +1 -0
  11. package/lib/commonjs/components/ProgressSegmented/styles.js +21 -0
  12. package/lib/commonjs/components/ProgressSegmented/styles.js.map +1 -0
  13. package/lib/commonjs/components/index.js +24 -0
  14. package/lib/commonjs/components/index.js.map +1 -1
  15. package/lib/module/components/BottomSheet/index.js +242 -0
  16. package/lib/module/components/BottomSheet/index.js.map +1 -0
  17. package/lib/module/components/BottomSheet/styles.js +58 -0
  18. package/lib/module/components/BottomSheet/styles.js.map +1 -0
  19. package/lib/module/components/Link/index.js +60 -4
  20. package/lib/module/components/Link/index.js.map +1 -1
  21. package/lib/module/components/Link/styles.js +4 -2
  22. package/lib/module/components/Link/styles.js.map +1 -1
  23. package/lib/module/components/ProgressSegmented/index.js +58 -0
  24. package/lib/module/components/ProgressSegmented/index.js.map +1 -0
  25. package/lib/module/components/ProgressSegmented/styles.js +17 -0
  26. package/lib/module/components/ProgressSegmented/styles.js.map +1 -0
  27. package/lib/module/components/index.js +2 -0
  28. package/lib/module/components/index.js.map +1 -1
  29. package/lib/typescript/components/BottomSheet/index.d.ts +61 -0
  30. package/lib/typescript/components/BottomSheet/index.d.ts.map +1 -0
  31. package/lib/typescript/components/BottomSheet/styles.d.ts +16 -0
  32. package/lib/typescript/components/BottomSheet/styles.d.ts.map +1 -0
  33. package/lib/typescript/components/Link/index.d.ts +20 -2
  34. package/lib/typescript/components/Link/index.d.ts.map +1 -1
  35. package/lib/typescript/components/Link/styles.d.ts +2 -0
  36. package/lib/typescript/components/Link/styles.d.ts.map +1 -1
  37. package/lib/typescript/components/ProgressSegmented/index.d.ts +15 -0
  38. package/lib/typescript/components/ProgressSegmented/index.d.ts.map +1 -0
  39. package/lib/typescript/components/ProgressSegmented/styles.d.ts +8 -0
  40. package/lib/typescript/components/ProgressSegmented/styles.d.ts.map +1 -0
  41. package/lib/typescript/components/index.d.ts +2 -0
  42. package/lib/typescript/components/index.d.ts.map +1 -1
  43. package/package.json +5 -4
  44. package/src/components/BottomSheet/index.tsx +316 -0
  45. package/src/components/BottomSheet/styles.ts +79 -0
  46. package/src/components/Link/index.tsx +61 -5
  47. package/src/components/Link/styles.ts +7 -3
  48. package/src/components/ProgressSegmented/index.tsx +81 -0
  49. package/src/components/ProgressSegmented/styles.ts +19 -0
  50. package/src/components/index.ts +2 -0
@@ -1,8 +1,26 @@
1
- import { type View } from 'react-native';
1
+ import { type ReactNode } from 'react';
2
+ import { Text as RNText, type TextProps, type View } from 'react-native';
2
3
  import { type ILinkProps } from '@cdx-ui/primitives';
4
+ import { type IconProps } from '../Icon';
3
5
  export { LinkProvider, type LinkConfig, type LinkAction } from '@cdx-ui/primitives';
4
6
  export interface LinkProps extends ILinkProps {
5
7
  className?: string;
6
8
  }
7
- export declare const Link: import("react").ForwardRefExoticComponent<LinkProps & import("react").RefAttributes<View>>;
9
+ declare const LinkRoot: import("react").ForwardRefExoticComponent<LinkProps & import("react").RefAttributes<View>>;
10
+ export interface LinkLabelProps extends TextProps {
11
+ className?: string;
12
+ children?: ReactNode;
13
+ }
14
+ declare const LinkLabel: import("react").ForwardRefExoticComponent<LinkLabelProps & import("react").RefAttributes<RNText>>;
15
+ export interface LinkIconProps extends Omit<IconProps, 'children'> {
16
+ }
17
+ declare const LinkIcon: {
18
+ ({ className, style, as, ...props }: LinkIconProps): import("react/jsx-runtime").JSX.Element;
19
+ displayName: string;
20
+ };
21
+ type LinkCompoundComponent = typeof LinkRoot & {
22
+ Label: typeof LinkLabel;
23
+ Icon: typeof LinkIcon;
24
+ };
25
+ export declare const Link: LinkCompoundComponent;
8
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Link/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,IAAI,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIjE,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAMpF,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,IAAI,4FAQf,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Link/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAa,IAAI,IAAI,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,IAAI,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAUpF,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,QAAQ,4FAQZ,CAAC;AAQH,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,QAAA,MAAM,SAAS,mGAUd,CAAC;AAQF,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;CAAG;AAErE,QAAA,MAAM,QAAQ;yCAAwC,aAAa;;CAIlE,CAAC;AAQF,KAAK,qBAAqB,GAAG,OAAO,QAAQ,GAAG;IAC7C,KAAK,EAAE,OAAO,SAAS,CAAC;IACxB,IAAI,EAAE,OAAO,QAAQ,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,IAAI,EAGX,qBAAqB,CAAC"}
@@ -1,2 +1,4 @@
1
1
  export declare const linkRootVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
2
+ export declare const linkLabelVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
3
+ export declare const linkIconVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
2
4
  //# sourceMappingURL=styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/Link/styles.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,gBAAgB,oFAW3B,CAAC"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/Link/styles.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,gBAAgB,oFAW3B,CAAC;AAEH,eAAO,MAAM,iBAAiB,oFAAgD,CAAC;AAE/E,eAAO,MAAM,gBAAgB,oFAAmC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+ import { type ProgressSegmentedVariants } from './styles';
3
+ export interface ProgressSegmentedProps extends ViewProps, ProgressSegmentedVariants {
4
+ /** Current step (1-based index into the segment count) */
5
+ readonly step: number;
6
+ /** Total number of segments */
7
+ readonly total?: number;
8
+ /** When true, the current step segment is marked as complete rather than in-progress */
9
+ readonly isStepComplete?: boolean;
10
+ /** Returns the accessibility value text announced by screen readers. Receives the clamped step, total, and whether the step is complete. */
11
+ readonly getAccessibilityText?: (step: number, total: number, isStepComplete: boolean) => string;
12
+ readonly className?: string;
13
+ }
14
+ export declare const ProgressSegmented: import("react").ForwardRefExoticComponent<ProgressSegmentedProps & import("react").RefAttributes<View>>;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ProgressSegmented/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,sBAAuB,SAAQ,SAAS,EAAE,yBAAyB;IAClF,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,wFAAwF;IACxF,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAClC,4IAA4I;IAC5I,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,KAAK,MAAM,CAAC;IACjG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,iBAAiB,yGAyD7B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ export declare const progressSegmentedVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
3
+ export declare const segmentVariants: (props?: ({
4
+ state?: "complete" | "incomplete" | "inprogress" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ export type ProgressSegmentedVariants = VariantProps<typeof progressSegmentedVariants>;
7
+ export type SegmentVariants = VariantProps<typeof segmentVariants>;
8
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/ProgressSegmented/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,eAAO,MAAM,yBAAyB,oFAAiC,CAAC;AAExE,eAAO,MAAM,eAAe;;8EAW1B,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,YAAY,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACvF,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,eAAe,CAAC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from './Avatar';
2
+ export * from './BottomSheet';
2
3
  export * from './Box';
3
4
  export * from './Button';
4
5
  export * from './Chip';
@@ -6,6 +7,7 @@ export * from './Card';
6
7
  export * from './Checkbox';
7
8
  export * from './Input';
8
9
  export * from './Link';
10
+ export * from './ProgressSegmented';
9
11
  export * from './Select';
10
12
  export * from './VirtualizedList';
11
13
  export * from './Switch';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,qBAAqB,CAAC;AACpC,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdx-ui/components",
3
- "version": "0.0.1-alpha.20",
3
+ "version": "0.0.1-alpha.22",
4
4
  "main": "lib/commonjs/index.js",
5
5
  "module": "lib/module/index.js",
6
6
  "react-native": "src/index.ts",
@@ -62,11 +62,12 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
+ "@gorhom/bottom-sheet": "^5.2.6",
65
66
  "class-variance-authority": "^0.7.1",
66
67
  "uniwind": "1.4.1",
67
- "@cdx-ui/primitives": "0.0.1-alpha.20",
68
- "@cdx-ui/utils": "0.0.1-alpha.20",
69
- "@cdx-ui/icons": "0.0.1-alpha.20"
68
+ "@cdx-ui/primitives": "0.0.1-alpha.22",
69
+ "@cdx-ui/utils": "0.0.1-alpha.22",
70
+ "@cdx-ui/icons": "0.0.1-alpha.22"
70
71
  },
71
72
  "devDependencies": {
72
73
  "@types/react": "*",
@@ -0,0 +1,316 @@
1
+ import React, { forwardRef, useCallback, useRef, type ReactNode } from 'react';
2
+ import { Dimensions, Pressable, View, ViewStyle } from 'react-native';
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
+ import {
5
+ BottomSheetModal,
6
+ BottomSheetModalProvider,
7
+ BottomSheetScrollView,
8
+ BottomSheetView,
9
+ BottomSheetBackdrop,
10
+ BottomSheetFooter as GorhomBottomSheetFooter,
11
+ type BottomSheetBackdropProps,
12
+ type BottomSheetFooterProps as GorhomBottomSheetFooterProps,
13
+ } from '@gorhom/bottom-sheet';
14
+ import { cn } from '@cdx-ui/utils';
15
+ import { ArrowBackIosNew, Close } from '@cdx-ui/icons';
16
+ import { Heading } from '../Heading';
17
+ import { Icon } from '../Icon';
18
+ import { Text } from '../Text';
19
+ import {
20
+ bottomSheetBackButtonVariants,
21
+ bottomSheetBackIconVariants,
22
+ bottomSheetCloseButtonVariants,
23
+ bottomSheetCloseIconVariants,
24
+ bottomSheetContainerVariants,
25
+ bottomSheetContentVariants,
26
+ bottomSheetFooterVariants,
27
+ bottomSheetHeaderVariants,
28
+ bottomSheetSubtitleVariants,
29
+ handleIndicatorStyle,
30
+ } from './styles';
31
+
32
+ /** Ref type for BottomSheet; forwards the @gorhom modal ref (present, dismiss, snapToIndex, minimize, restore, etc.). */
33
+ export type BottomSheetModalRef = React.ComponentRef<typeof BottomSheetModal>;
34
+
35
+ export interface BottomSheetHeaderProps {
36
+ title?: string;
37
+ subtitle?: string;
38
+ children?: ReactNode;
39
+ className?: string;
40
+ onClose?: () => void;
41
+ closeAccessibilityLabel?: string;
42
+ onBack?: () => void;
43
+ backAccessibilityLabel?: string;
44
+ }
45
+
46
+ function BottomSheetHeaderComponent(
47
+ {
48
+ title,
49
+ subtitle,
50
+ children,
51
+ className,
52
+ onClose,
53
+ closeAccessibilityLabel,
54
+ onBack,
55
+ backAccessibilityLabel = 'Go back',
56
+ }: BottomSheetHeaderProps,
57
+ ref: React.Ref<View>,
58
+ ) {
59
+ const hasTitle = title !== undefined && title !== '';
60
+ const hasContent = hasTitle || !!children || !!onBack;
61
+ const computedClassName = cn(bottomSheetHeaderVariants({ hasTitle: hasContent }), className);
62
+ return (
63
+ <View ref={ref} className={computedClassName}>
64
+ {onBack && (
65
+ <Pressable
66
+ onPress={onBack}
67
+ hitSlop={12}
68
+ accessibilityRole="button"
69
+ accessibilityLabel={backAccessibilityLabel}
70
+ className={cn(bottomSheetBackButtonVariants())}
71
+ >
72
+ <Icon as={ArrowBackIosNew} className={bottomSheetBackIconVariants()} />
73
+ </Pressable>
74
+ )}
75
+ <View className="flex-1">
76
+ {children ??
77
+ (hasTitle ? (
78
+ <View>
79
+ <Heading size="xs" className="text-lg">
80
+ {title}
81
+ </Heading>
82
+ {subtitle ? <Text className={bottomSheetSubtitleVariants()}>{subtitle}</Text> : null}
83
+ </View>
84
+ ) : null)}
85
+ </View>
86
+ {onClose && (
87
+ <BottomSheetCloseButton
88
+ onPress={onClose}
89
+ {...(closeAccessibilityLabel !== undefined && {
90
+ accessibilityLabel: closeAccessibilityLabel,
91
+ })}
92
+ />
93
+ )}
94
+ </View>
95
+ );
96
+ }
97
+
98
+ BottomSheetHeaderComponent.displayName = 'BottomSheet.Header';
99
+
100
+ const BottomSheetHeader = forwardRef<View, BottomSheetHeaderProps>(BottomSheetHeaderComponent);
101
+ BottomSheetHeader.displayName = 'BottomSheet.Header';
102
+
103
+ // =============================================================================
104
+ // CLOSEBUTTON
105
+ // =============================================================================
106
+ interface BottomSheetCloseButtonProps {
107
+ onPress: () => void;
108
+ className?: string;
109
+ accessibilityLabel?: string;
110
+ }
111
+
112
+ function BottomSheetCloseButton({
113
+ onPress,
114
+ className,
115
+ accessibilityLabel = 'Close',
116
+ }: BottomSheetCloseButtonProps) {
117
+ return (
118
+ <Pressable
119
+ onPress={onPress}
120
+ hitSlop={12}
121
+ accessibilityRole="button"
122
+ accessibilityLabel={accessibilityLabel}
123
+ className={cn(bottomSheetCloseButtonVariants(), className)}
124
+ >
125
+ <Icon as={Close} className={bottomSheetCloseIconVariants()} />
126
+ </Pressable>
127
+ );
128
+ }
129
+
130
+ BottomSheetCloseButton.displayName = 'BottomSheet.CloseButton';
131
+
132
+ // =============================================================================
133
+ // CONTENT
134
+ // =============================================================================
135
+
136
+ export interface BottomSheetContentProps {
137
+ children?: ReactNode;
138
+ className?: string;
139
+ hasSafeAreaInset?: boolean;
140
+ style?: ViewStyle;
141
+ }
142
+
143
+ const BottomSheetContent = forwardRef<View, BottomSheetContentProps>(
144
+ ({ children, className, hasSafeAreaInset, style }, ref) => {
145
+ const insets = useSafeAreaInsets();
146
+ const computedClassName = cn(bottomSheetContentVariants(), className);
147
+ return (
148
+ <View
149
+ ref={ref}
150
+ className={computedClassName}
151
+ style={hasSafeAreaInset ? { paddingBottom: insets.bottom, ...style } : style}
152
+ pointerEvents="box-none"
153
+ >
154
+ {children}
155
+ </View>
156
+ );
157
+ },
158
+ );
159
+
160
+ BottomSheetContent.displayName = 'BottomSheet.Content';
161
+
162
+ // =============================================================================
163
+ // FOOTER
164
+ // =============================================================================
165
+ export interface BottomSheetFooterProps {
166
+ children?: ReactNode;
167
+ className?: string;
168
+ style?: ViewStyle;
169
+ }
170
+
171
+ const BottomSheetFooter = forwardRef<View, BottomSheetFooterProps>(
172
+ ({ children, className, style }, ref) => {
173
+ const insets = useSafeAreaInsets();
174
+ const computedClassName = cn(bottomSheetFooterVariants(), className);
175
+ return (
176
+ <View
177
+ ref={ref}
178
+ className={computedClassName}
179
+ style={{ paddingBottom: Math.max(insets.bottom, 24), ...style }}
180
+ pointerEvents="box-none"
181
+ >
182
+ {children}
183
+ </View>
184
+ );
185
+ },
186
+ );
187
+
188
+ BottomSheetFooter.displayName = 'BottomSheet.Footer';
189
+
190
+ // =============================================================================
191
+ // MODAL WRAPPER (WITH STYLES)
192
+ // =============================================================================
193
+
194
+ export interface BottomSheetModalProps extends React.ComponentPropsWithoutRef<
195
+ typeof BottomSheetModal
196
+ > {
197
+ /** Show the drag handle indicator. When false, `handleComponent` is set to null. @default true */
198
+ handleVisible?: boolean;
199
+ /** Footer content rendered via gorhom's BottomSheetFooter for proper animated positioning and safe-area handling. */
200
+ footer?: ReactNode;
201
+ }
202
+
203
+ const MAX_DYNAMIC_CONTENT_SIZE = Dimensions.get('window').height * 0.9;
204
+
205
+ const CustomBackdrop = (props: BottomSheetBackdropProps) => {
206
+ return (
207
+ <BottomSheetBackdrop
208
+ {...props}
209
+ disappearsOnIndex={-1}
210
+ appearsOnIndex={0}
211
+ opacity={0.5}
212
+ pressBehavior="close"
213
+ />
214
+ );
215
+ };
216
+
217
+ const BottomSheetModalStyled = forwardRef<
218
+ React.ComponentRef<typeof BottomSheetModal>,
219
+ BottomSheetModalProps
220
+ >(({ handleVisible = true, footer, ...rest }, ref) => {
221
+ const renderFooter = useCallback(
222
+ (props: GorhomBottomSheetFooterProps) => (
223
+ <GorhomBottomSheetFooter {...props}>{footer}</GorhomBottomSheetFooter>
224
+ ),
225
+ [footer],
226
+ );
227
+
228
+ return (
229
+ <BottomSheetModal
230
+ ref={ref}
231
+ enableDynamicSizing
232
+ maxDynamicContentSize={MAX_DYNAMIC_CONTENT_SIZE}
233
+ handleComponent={handleVisible ? undefined : null}
234
+ handleIndicatorStyle={handleVisible ? handleIndicatorStyle : undefined}
235
+ backdropComponent={CustomBackdrop}
236
+ backgroundComponent={(backgroundProps) => (
237
+ <View {...backgroundProps} className={cn(bottomSheetContainerVariants())} />
238
+ )}
239
+ {...rest}
240
+ {...(footer != null && { footerComponent: renderFooter })}
241
+ />
242
+ );
243
+ });
244
+
245
+ BottomSheetModalStyled.displayName = 'BottomSheet.Modal';
246
+
247
+ // =============================================================================
248
+ // SCROLLVIEW WRAPPER (with footer margin adjustment enabled by default)
249
+ // =============================================================================
250
+
251
+ function BottomSheetScrollViewStyled({
252
+ enableFooterMarginAdjustment = true,
253
+ children,
254
+ ...rest
255
+ }: React.ComponentPropsWithoutRef<typeof BottomSheetScrollView>) {
256
+ return (
257
+ <BottomSheetScrollView enableFooterMarginAdjustment={enableFooterMarginAdjustment} {...rest}>
258
+ {children}
259
+ </BottomSheetScrollView>
260
+ );
261
+ }
262
+
263
+ BottomSheetScrollViewStyled.displayName = 'BottomSheet.ScrollView';
264
+
265
+ // =============================================================================
266
+ // VIEW WRAPPER (with footer margin adjustment enabled by default)
267
+ // =============================================================================
268
+
269
+ function BottomSheetViewStyled({
270
+ enableFooterMarginAdjustment = true,
271
+ children,
272
+ ...rest
273
+ }: React.ComponentPropsWithoutRef<typeof BottomSheetView>) {
274
+ return (
275
+ <BottomSheetView enableFooterMarginAdjustment={enableFooterMarginAdjustment} {...rest}>
276
+ {children}
277
+ </BottomSheetView>
278
+ );
279
+ }
280
+
281
+ BottomSheetViewStyled.displayName = 'BottomSheet.View';
282
+
283
+ // Display names for gorhom components exposed as BottomSheet.*
284
+ interface WithDisplayName {
285
+ displayName?: string;
286
+ }
287
+ (BottomSheetModalProvider as WithDisplayName).displayName = 'BottomSheet.Provider';
288
+
289
+ // ── Public exports ────────────────────────────────────────
290
+
291
+ interface BottomSheetCompound {
292
+ Modal: typeof BottomSheetModalStyled;
293
+ Header: typeof BottomSheetHeader;
294
+ Content: typeof BottomSheetContent;
295
+ Footer: typeof BottomSheetFooter;
296
+ Provider: typeof BottomSheetModalProvider;
297
+ ScrollView: typeof BottomSheetScrollViewStyled;
298
+ View: typeof BottomSheetViewStyled;
299
+ }
300
+
301
+ export const BottomSheet = {
302
+ Modal: BottomSheetModalStyled,
303
+ Header: BottomSheetHeader,
304
+ Content: BottomSheetContent,
305
+ Footer: BottomSheetFooter,
306
+ Provider: BottomSheetModalProvider,
307
+ ScrollView: BottomSheetScrollViewStyled,
308
+ View: BottomSheetViewStyled,
309
+ } as BottomSheetCompound;
310
+
311
+ // ── Hooks ────────────────────────────────────────────────
312
+
313
+ export function useBottomSheet() {
314
+ const ref = useRef<BottomSheetModalRef>(null);
315
+ return { ref, present: () => ref.current?.present(), dismiss: () => ref.current?.dismiss() };
316
+ }
@@ -0,0 +1,79 @@
1
+ import { type ViewStyle } from 'react-native';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+ import {
4
+ COLOR_BG_PRIMARY,
5
+ COLOR_BORDER_DEFAULT,
6
+ COLOR_TEXT_PRIMARY,
7
+ COLOR_TEXT_SECONDARY,
8
+ } from '../../styles/primitives';
9
+
10
+ // ── Container ──────────────────────────────────────────────
11
+
12
+ export const bottomSheetContainerVariants = cva([
13
+ 'rounded-t-3xl border-t border-x overflow-hidden',
14
+ COLOR_BG_PRIMARY,
15
+ COLOR_BORDER_DEFAULT,
16
+ ]);
17
+
18
+ // ── Header ─────────────────────────────────────────────────
19
+
20
+ export const bottomSheetHeaderVariants = cva(
21
+ [
22
+ 'flex-row items-center justify-between min-h-12 px-4 pt-3 pb-2',
23
+ COLOR_BG_PRIMARY,
24
+ COLOR_TEXT_PRIMARY,
25
+ ],
26
+ {
27
+ variants: {
28
+ hasTitle: {
29
+ true: '',
30
+ false: 'justify-end',
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ hasTitle: true,
35
+ },
36
+ },
37
+ );
38
+
39
+ // ── Content ────────────────────────────────────────────────
40
+
41
+ export const bottomSheetContentVariants = cva([COLOR_BG_PRIMARY, 'px-4 pb-6']);
42
+
43
+ // ── Footer ─────────────────────────────────────────────────
44
+
45
+ export const bottomSheetFooterVariants = cva([
46
+ 'px-4 pt-3 pb-4 border-t',
47
+ COLOR_BG_PRIMARY,
48
+ COLOR_BORDER_DEFAULT,
49
+ ]);
50
+
51
+ // ── Subtitle ────────────────────────────────────────────────
52
+
53
+ export const bottomSheetSubtitleVariants = cva(['text-sm', COLOR_TEXT_SECONDARY]);
54
+
55
+ // ── Back Button ─────────────────────────────────────────────
56
+
57
+ export const bottomSheetBackButtonVariants = cva(['p-1 -m-1 mr-2 rounded-full active:opacity-70']);
58
+
59
+ export const bottomSheetBackIconVariants = cva(['size-5 text-slate-500']);
60
+
61
+ // ── Close Button ───────────────────────────────────────────
62
+
63
+ export const bottomSheetCloseButtonVariants = cva(['p-1 -m-1 rounded-full active:opacity-70']);
64
+
65
+ // ── Close Icon ─────────────────────────────────────────────
66
+
67
+ export const bottomSheetCloseIconVariants = cva(['size-5 text-slate-500']);
68
+
69
+ // ── Handle indicator ────────────────────────────────────────
70
+ // Plain ViewStyle — gorhom's handleIndicatorStyle doesn't accept classNames.
71
+ // slate-300 (#cbd5e1) maps to COLOR_BORDER_STRONG; update when raw token palette is available (TODO).
72
+ export const handleIndicatorStyle: ViewStyle = {
73
+ backgroundColor: '#cbd5e1',
74
+ width: 36,
75
+ height: 4,
76
+ borderRadius: 2,
77
+ };
78
+
79
+ export type BottomSheetHeaderVariants = VariantProps<typeof bottomSheetHeaderVariants>;
@@ -1,8 +1,9 @@
1
- import { forwardRef } from 'react';
2
- import { Pressable, type View } from 'react-native';
1
+ import { forwardRef, type ReactNode } from 'react';
2
+ import { Pressable, Text as RNText, type TextProps, type View } from 'react-native';
3
3
  import { createLink, type ILinkProps } from '@cdx-ui/primitives';
4
4
  import { cn } from '@cdx-ui/utils';
5
- import { linkRootVariants } from './styles';
5
+ import { Icon, type IconProps } from '../Icon';
6
+ import { linkRootVariants, linkLabelVariants, linkIconVariants } from './styles';
6
7
 
7
8
  export { LinkProvider, type LinkConfig, type LinkAction } from '@cdx-ui/primitives';
8
9
 
@@ -10,11 +11,15 @@ const LinkPrimitive = createLink({
10
11
  Root: Pressable,
11
12
  });
12
13
 
14
+ // =============================================================================
15
+ // STYLED ROOT COMPONENT
16
+ // =============================================================================
17
+
13
18
  export interface LinkProps extends ILinkProps {
14
19
  className?: string;
15
20
  }
16
21
 
17
- export const Link = forwardRef<View, LinkProps>(({ className, children, style, ...props }, ref) => {
22
+ const LinkRoot = forwardRef<View, LinkProps>(({ className, children, style, ...props }, ref) => {
18
23
  const rootClassName = cn(linkRootVariants(), className);
19
24
 
20
25
  return (
@@ -24,4 +29,55 @@ export const Link = forwardRef<View, LinkProps>(({ className, children, style, .
24
29
  );
25
30
  });
26
31
 
27
- Link.displayName = 'Link';
32
+ LinkRoot.displayName = 'Link';
33
+
34
+ // =============================================================================
35
+ // STYLED LABEL COMPONENT
36
+ // =============================================================================
37
+
38
+ export interface LinkLabelProps extends TextProps {
39
+ className?: string;
40
+ children?: ReactNode;
41
+ }
42
+
43
+ const LinkLabel = forwardRef<RNText, LinkLabelProps>(
44
+ ({ className, children, style, ...props }, ref) => {
45
+ const computedClassName = cn(linkLabelVariants(), className);
46
+
47
+ return (
48
+ <RNText ref={ref} className={computedClassName} style={style} {...props}>
49
+ {children}
50
+ </RNText>
51
+ );
52
+ },
53
+ );
54
+
55
+ LinkLabel.displayName = 'Link.Label';
56
+
57
+ // =============================================================================
58
+ // STYLED ICON COMPONENT
59
+ // =============================================================================
60
+
61
+ export interface LinkIconProps extends Omit<IconProps, 'children'> {}
62
+
63
+ const LinkIcon = ({ className, style, as, ...props }: LinkIconProps) => {
64
+ const computedClassName = cn(linkIconVariants(), className);
65
+
66
+ return <Icon as={as} className={computedClassName} style={style} {...props} />;
67
+ };
68
+
69
+ LinkIcon.displayName = 'Link.Icon';
70
+
71
+ // =============================================================================
72
+ // COMPOUND COMPONENT EXPORT
73
+ // =============================================================================
74
+
75
+ type LinkCompoundComponent = typeof LinkRoot & {
76
+ Label: typeof LinkLabel;
77
+ Icon: typeof LinkIcon;
78
+ };
79
+
80
+ export const Link = Object.assign(LinkRoot, {
81
+ Label: LinkLabel,
82
+ Icon: LinkIcon,
83
+ }) as LinkCompoundComponent;
@@ -1,11 +1,11 @@
1
1
  import { Platform } from 'react-native';
2
2
  import { cva } from 'class-variance-authority';
3
- import { COLOR_TEXT_PRIMARY, TRANSITION_COLORS } from '../../styles/primitives';
3
+ import { TRANSITION_COLORS } from '../../styles/primitives';
4
4
 
5
5
  export const linkRootVariants = cva([
6
- 'flex-row items-center',
6
+ 'flex-row items-center gap-1',
7
7
  'web:outline-none web:focus:outline-none web:focus-visible:outline-none',
8
- COLOR_TEXT_PRIMARY,
8
+ 'text-blue-600',
9
9
  'underline decoration-slate-300 underline-offset-4',
10
10
  TRANSITION_COLORS,
11
11
  Platform.select({
@@ -14,3 +14,7 @@ export const linkRootVariants = cva([
14
14
  }),
15
15
  'web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-slate-400/50 web:data-[focus-visible=true]:ring-offset-2',
16
16
  ]);
17
+
18
+ export const linkLabelVariants = cva(['text-sm font-medium', 'text-blue-600']);
19
+
20
+ export const linkIconVariants = cva(['size-4', 'text-blue-600']);