@cdx-ui/components 0.0.1-beta.10 → 0.0.1-beta.12

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/README.md +1 -1
  2. package/lib/commonjs/components/Button/styles.js +1 -1
  3. package/lib/commonjs/components/Button/styles.js.map +1 -1
  4. package/lib/commonjs/components/Card/index.js +15 -3
  5. package/lib/commonjs/components/Card/index.js.map +1 -1
  6. package/lib/commonjs/components/Card/styles.js +17 -4
  7. package/lib/commonjs/components/Card/styles.js.map +1 -1
  8. package/lib/commonjs/components/IconButton/styles.js +1 -1
  9. package/lib/commonjs/components/IconButton/styles.js.map +1 -1
  10. package/lib/commonjs/components/Input/styles.js +1 -1
  11. package/lib/commonjs/components/Input/styles.js.map +1 -1
  12. package/lib/commonjs/components/Radio/index.js +165 -0
  13. package/lib/commonjs/components/Radio/index.js.map +1 -0
  14. package/lib/commonjs/components/Radio/styles.js +30 -0
  15. package/lib/commonjs/components/Radio/styles.js.map +1 -0
  16. package/lib/commonjs/components/index.js +12 -0
  17. package/lib/commonjs/components/index.js.map +1 -1
  18. package/lib/commonjs/figma/Radio.figma.js +38 -0
  19. package/lib/commonjs/figma/Radio.figma.js.map +1 -0
  20. package/lib/module/components/Button/styles.js +1 -1
  21. package/lib/module/components/Button/styles.js.map +1 -1
  22. package/lib/module/components/Card/index.js +16 -3
  23. package/lib/module/components/Card/index.js.map +1 -1
  24. package/lib/module/components/Card/styles.js +17 -4
  25. package/lib/module/components/Card/styles.js.map +1 -1
  26. package/lib/module/components/IconButton/styles.js +1 -1
  27. package/lib/module/components/IconButton/styles.js.map +1 -1
  28. package/lib/module/components/Input/styles.js +1 -1
  29. package/lib/module/components/Input/styles.js.map +1 -1
  30. package/lib/module/components/Radio/index.js +162 -0
  31. package/lib/module/components/Radio/index.js.map +1 -0
  32. package/lib/module/components/Radio/styles.js +27 -0
  33. package/lib/module/components/Radio/styles.js.map +1 -0
  34. package/lib/module/components/index.js +1 -0
  35. package/lib/module/components/index.js.map +1 -1
  36. package/lib/module/figma/Radio.figma.js +32 -0
  37. package/lib/module/figma/Radio.figma.js.map +1 -0
  38. package/lib/typescript/components/Card/index.d.ts +3 -2
  39. package/lib/typescript/components/Card/index.d.ts.map +1 -1
  40. package/lib/typescript/components/Card/styles.d.ts +9 -2
  41. package/lib/typescript/components/Card/styles.d.ts.map +1 -1
  42. package/lib/typescript/components/Radio/index.d.ts +40 -0
  43. package/lib/typescript/components/Radio/index.d.ts.map +1 -0
  44. package/lib/typescript/components/Radio/styles.d.ts +8 -0
  45. package/lib/typescript/components/Radio/styles.d.ts.map +1 -0
  46. package/lib/typescript/components/index.d.ts +1 -0
  47. package/lib/typescript/components/index.d.ts.map +1 -1
  48. package/lib/typescript/figma/Radio.figma.d.ts +8 -0
  49. package/lib/typescript/figma/Radio.figma.d.ts.map +1 -0
  50. package/package.json +4 -4
  51. package/src/components/Button/styles.ts +1 -1
  52. package/src/components/Card/index.tsx +33 -13
  53. package/src/components/Card/styles.ts +29 -14
  54. package/src/components/IconButton/styles.ts +1 -1
  55. package/src/components/Input/styles.ts +1 -1
  56. package/src/components/Radio/index.tsx +191 -0
  57. package/src/components/Radio/styles.ts +59 -0
  58. package/src/components/index.ts +1 -0
@@ -1,31 +1,47 @@
1
1
  import { forwardRef, type ReactNode } from 'react';
2
2
  import { View, type ViewProps } from 'react-native';
3
- import { cn } from '@cdx-ui/utils';
3
+ import { cn, useStyleContext, withStyleContext } from '@cdx-ui/utils';
4
4
  import {
5
5
  cardContentVariants,
6
6
  cardFooterVariants,
7
7
  cardHeaderVariants,
8
8
  cardRootVariants,
9
+ type CardVariantProps,
10
+ type CardContentVariantProps,
9
11
  } from './styles';
10
12
 
11
13
  // =============================================================================
12
14
  // STYLED ROOT COMPONENT
13
15
  // =============================================================================
14
16
 
15
- export interface CardProps extends ViewProps {
17
+ const SCOPE = 'CARD';
18
+
19
+ const Root = withStyleContext(View, SCOPE);
20
+
21
+ const useCardStyleContext = () => useStyleContext(SCOPE) as CardVariantProps;
22
+
23
+ export interface CardProps extends ViewProps, CardVariantProps {
16
24
  className?: string;
17
25
  children?: ReactNode;
18
26
  }
19
27
 
20
- const CardRoot = forwardRef<View, CardProps>(({ className, children, style, ...props }, ref) => {
21
- const computedClassName = cn(cardRootVariants(), className);
28
+ const CardRoot = forwardRef<View, CardProps>(
29
+ ({ className, children, style, fullBleed, ...props }, ref) => {
30
+ const computedClassName = cn(cardRootVariants(), className);
22
31
 
23
- return (
24
- <View ref={ref} className={computedClassName} style={style} {...props}>
25
- {children}
26
- </View>
27
- );
28
- });
32
+ return (
33
+ <Root
34
+ ref={ref}
35
+ className={computedClassName}
36
+ style={style}
37
+ context={{ fullBleed }}
38
+ {...props}
39
+ >
40
+ {children}
41
+ </Root>
42
+ );
43
+ },
44
+ );
29
45
 
30
46
  CardRoot.displayName = 'Card';
31
47
 
@@ -56,14 +72,18 @@ CardHeader.displayName = 'Card.Header';
56
72
  // STYLED CONTENT COMPONENT
57
73
  // =============================================================================
58
74
 
59
- export interface CardContentProps extends ViewProps {
75
+ export interface CardContentProps extends ViewProps, CardContentVariantProps {
60
76
  className?: string;
61
77
  children?: ReactNode;
62
78
  }
63
79
 
64
80
  const CardContent = forwardRef<View, CardContentProps>(
65
- ({ className, children, style, ...props }, ref) => {
66
- const computedClassName = cn(cardContentVariants(), className);
81
+ ({ className, children, style, fullBleed, ...props }, ref) => {
82
+ const { fullBleed: fullBleedFromContext } = useCardStyleContext();
83
+ const computedClassName = cn(
84
+ cardContentVariants({ fullBleed: fullBleed ?? fullBleedFromContext }),
85
+ className,
86
+ );
67
87
 
68
88
  return (
69
89
  <View ref={ref} className={computedClassName} style={style} {...props}>
@@ -1,18 +1,28 @@
1
- import { cva } from 'class-variance-authority';
1
+ import { cva, VariantProps } from 'class-variance-authority';
2
2
 
3
3
  // ── Root ────────────────────────────────────────────────────
4
4
 
5
- export const cardRootVariants = cva([
6
- 'bg-surface-primary',
7
- 'border border-stroke-secondary',
8
- 'rounded-[var(--border-radius-default)]',
9
- 'overflow-hidden',
10
- ]);
5
+ export const cardRootVariants = cva(
6
+ [
7
+ 'bg-surface-primary',
8
+ 'border border-stroke-secondary',
9
+ 'rounded-[var(--border-radius-default)]',
10
+ 'overflow-hidden',
11
+ ],
12
+ {
13
+ variants: {
14
+ fullBleed: {
15
+ true: '',
16
+ false: '',
17
+ },
18
+ },
19
+ },
20
+ );
11
21
 
12
22
  // ── Header ──────────────────────────────────────────────────
13
23
 
14
24
  export const cardHeaderVariants = cva([
15
- 'flex-row items-center justify-between p-4',
25
+ 'flex-row items-center justify-between px-5 py-3',
16
26
  'border-t-8 border-t-surface-brand-strong',
17
27
  'border-b border-b-solid border-b-stroke-secondary',
18
28
  ]);
@@ -23,12 +33,17 @@ export const cardTitleVariants = cva(['flex-1']);
23
33
 
24
34
  // ── Content ─────────────────────────────────────────────────
25
35
 
26
- export const cardContentVariants = cva(['text-content-primary', 'p-4']);
36
+ export const cardContentVariants = cva(['text-content-primary', 'p-5'], {
37
+ variants: {
38
+ fullBleed: {
39
+ true: 'p-0',
40
+ },
41
+ },
42
+ });
27
43
 
28
44
  // ── Footer ──────────────────────────────────────────────────
29
45
 
30
- export const cardFooterVariants = cva([
31
- 'p-4 border-t',
32
- 'border-stroke-secondary',
33
- 'flex-row items-center gap-2',
34
- ]);
46
+ export const cardFooterVariants = cva(['p-5 pt-0', 'flex-row items-center gap-2']);
47
+
48
+ export type CardVariantProps = VariantProps<typeof cardRootVariants>;
49
+ export type CardContentVariantProps = VariantProps<typeof cardContentVariants>;
@@ -8,7 +8,7 @@ export const iconButtonRootVariants = cva(
8
8
  'rounded-[var(--border-radius-round)]',
9
9
  'web:outline-none web:focus:outline-none web:focus-visible:outline-none',
10
10
  TRANSITION_COLORS,
11
- 'data-[disabled=true]:opacity-[--opacity-disabled]',
11
+ 'data-[disabled=true]:opacity-[var(--opacity-disabled)]',
12
12
  DISABLED_CURSOR,
13
13
  'web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-[--color-stroke-ring] web:data-[focus-visible=true]:ring-offset-2',
14
14
  ],
@@ -9,7 +9,7 @@ export const inputRootVariants = cva(
9
9
  'rounded-[var(--border-radius-default)]',
10
10
  TRANSITION_COLORS,
11
11
  'data-[disabled=true]:bg-surface-secondary',
12
- 'data-[disabled=true]:opacity-[--opacity-disabled]',
12
+ 'data-[disabled=true]:opacity-[var(--opacity-disabled)]',
13
13
  DISABLED_CURSOR,
14
14
  'data-[readonly=true]:cursor-default',
15
15
  'data-[readonly=true]:bg-surface-secondary',
@@ -0,0 +1,191 @@
1
+ import { forwardRef, type ReactNode } from 'react';
2
+ import { Pressable, Text, type TextProps, View, type ViewProps } from 'react-native';
3
+ import { createRadio, dataAttributes, type IRadioProps } from '@cdx-ui/primitives';
4
+ import { cn } from '@cdx-ui/utils';
5
+ import {
6
+ radioGroupVariants,
7
+ radioIndicatorVariants,
8
+ radioInnerDotVariants,
9
+ radioLabelVariants,
10
+ radioRootVariants,
11
+ } from './styles';
12
+
13
+ // =============================================================================
14
+ // STYLED INDICATOR BASE
15
+ // =============================================================================
16
+
17
+ const RadioIndicatorBase = forwardRef<View, ViewProps & { className?: string }>(
18
+ ({ className, children, style, ...props }, ref) => {
19
+ // On web, data attributes arrive as `dataSet: { checked: true }`.
20
+ // On native, they arrive as individual `data-checked: "true"` props.
21
+ const ds = (props as any).dataSet;
22
+ const isChecked = ds ? ds.checked === true : (props as any)['data-checked'] === 'true';
23
+ const isInvalid = ds ? ds.invalid === true : (props as any)['data-invalid'] === 'true';
24
+
25
+ return (
26
+ <View ref={ref} className={cn(radioIndicatorVariants(), className)} style={style} {...props}>
27
+ <View
28
+ className={cn(radioInnerDotVariants())}
29
+ {...dataAttributes({ checked: isChecked, invalid: isInvalid })}
30
+ />
31
+ {children}
32
+ </View>
33
+ );
34
+ },
35
+ );
36
+
37
+ RadioIndicatorBase.displayName = 'Radio.IndicatorBase';
38
+
39
+ // =============================================================================
40
+ // PRIMITIVE ASSEMBLY
41
+ // =============================================================================
42
+
43
+ const RadioPrimitive = createRadio({
44
+ Root: Pressable,
45
+ Indicator: RadioIndicatorBase,
46
+ Label: Text,
47
+ Group: View,
48
+ });
49
+
50
+ // =============================================================================
51
+ // RADIO ROOT
52
+ // =============================================================================
53
+
54
+ export interface RadioProps extends IRadioProps {
55
+ className?: string;
56
+ children?: ReactNode;
57
+ }
58
+
59
+ const RadioRoot = forwardRef<View, RadioProps>(({ className, children, style, ...props }, ref) => {
60
+ const computedClassName = cn(radioRootVariants(), className);
61
+
62
+ return (
63
+ <RadioPrimitive ref={ref as any} className={computedClassName} style={style} {...props}>
64
+ {children}
65
+ </RadioPrimitive>
66
+ );
67
+ });
68
+
69
+ RadioRoot.displayName = 'Radio';
70
+
71
+ // =============================================================================
72
+ // RADIO INDICATOR
73
+ // =============================================================================
74
+
75
+ export interface RadioIndicatorProps extends ViewProps {
76
+ className?: string;
77
+ children?: ReactNode;
78
+ }
79
+
80
+ const RadioIndicator = forwardRef<View, RadioIndicatorProps>(
81
+ ({ className, children, style, ...props }, ref) => {
82
+ return (
83
+ <RadioPrimitive.Indicator ref={ref as any} className={className} style={style} {...props}>
84
+ {children}
85
+ </RadioPrimitive.Indicator>
86
+ );
87
+ },
88
+ );
89
+
90
+ RadioIndicator.displayName = 'Radio.Indicator';
91
+
92
+ // =============================================================================
93
+ // RADIO LABEL
94
+ // =============================================================================
95
+
96
+ export interface RadioLabelProps extends TextProps {
97
+ className?: string;
98
+ children?: ReactNode;
99
+ }
100
+
101
+ const RadioLabel = forwardRef<Text, RadioLabelProps>(
102
+ ({ className, children, style, ...props }, ref) => {
103
+ const computedClassName = cn(radioLabelVariants(), className);
104
+
105
+ return (
106
+ <RadioPrimitive.Label ref={ref as any} className={computedClassName} style={style} {...props}>
107
+ {children}
108
+ </RadioPrimitive.Label>
109
+ );
110
+ },
111
+ );
112
+
113
+ RadioLabel.displayName = 'Radio.Label';
114
+
115
+ // =============================================================================
116
+ // RADIO GROUP
117
+ // =============================================================================
118
+
119
+ export interface RadioGroupProps extends ViewProps {
120
+ className?: string;
121
+ children?: ReactNode;
122
+ value?: string;
123
+ defaultValue?: string;
124
+ onChange?: (value: string) => void;
125
+ isDisabled?: boolean;
126
+ isInvalid?: boolean;
127
+ isRequired?: boolean;
128
+ isReadOnly?: boolean;
129
+ direction?: 'column' | 'row';
130
+ name?: string;
131
+ }
132
+
133
+ const RadioGroup = forwardRef<View, RadioGroupProps>(
134
+ (
135
+ {
136
+ className,
137
+ children,
138
+ style,
139
+ direction = 'column',
140
+ value,
141
+ defaultValue,
142
+ onChange,
143
+ isDisabled,
144
+ isInvalid,
145
+ isRequired,
146
+ isReadOnly,
147
+ name,
148
+ ...viewProps
149
+ },
150
+ ref,
151
+ ) => {
152
+ const computedClassName = cn(radioGroupVariants({ direction }), className);
153
+
154
+ return (
155
+ <RadioPrimitive.Group
156
+ ref={ref as any}
157
+ className={computedClassName}
158
+ style={style}
159
+ value={value}
160
+ defaultValue={defaultValue}
161
+ onChange={onChange}
162
+ isDisabled={isDisabled}
163
+ isInvalid={isInvalid}
164
+ isRequired={isRequired}
165
+ isReadOnly={isReadOnly}
166
+ name={name}
167
+ {...viewProps}
168
+ >
169
+ {children}
170
+ </RadioPrimitive.Group>
171
+ );
172
+ },
173
+ );
174
+
175
+ RadioGroup.displayName = 'Radio.Group';
176
+
177
+ // =============================================================================
178
+ // COMPOUND COMPONENT
179
+ // =============================================================================
180
+
181
+ type RadioCompoundComponent = typeof RadioRoot & {
182
+ Indicator: typeof RadioIndicator;
183
+ Label: typeof RadioLabel;
184
+ Group: typeof RadioGroup;
185
+ };
186
+
187
+ export const Radio = Object.assign(RadioRoot, {
188
+ Indicator: RadioIndicator,
189
+ Label: RadioLabel,
190
+ Group: RadioGroup,
191
+ }) as RadioCompoundComponent;
@@ -0,0 +1,59 @@
1
+ import { Platform } from 'react-native';
2
+ import { cva } from 'class-variance-authority';
3
+ import { DISABLED_CURSOR, TRANSITION_COLORS } from '../../styles/primitives';
4
+
5
+ // TODO: Add hover, active, and focus-visible styles based on Figma
6
+
7
+ export const radioRootVariants = cva([
8
+ 'flex-row items-center gap-2',
9
+ 'data-[disabled=true]:opacity-[var(--opacity-disabled)]',
10
+ DISABLED_CURSOR,
11
+ ]);
12
+
13
+ export const radioIndicatorVariants = cva([
14
+ 'items-center justify-center',
15
+ 'rounded-[var(--border-radius-round)]',
16
+ 'border-[length:var(--border-width-selected)]',
17
+ 'h-5 w-5',
18
+ 'border-stroke-primary',
19
+ 'data-[checked=false]:border-slate-300',
20
+ 'bg-surface-primary',
21
+ 'data-[checked=true]:border-stroke-action',
22
+ 'data-[invalid=true]:border-stroke-danger',
23
+ 'data-[checked=true]:data-[invalid=true]:border-stroke-danger',
24
+ Platform.select({
25
+ web: [
26
+ TRANSITION_COLORS,
27
+ 'data-[hover=true]:data-[checked=false]:border-slate-400',
28
+ 'data-[hover=true]:data-[checked=false]:bg-slate-50',
29
+ 'web:data-[focus-visible=true]:outline-none',
30
+ 'web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-offset-2',
31
+ 'web:data-[focus-visible=true]:data-[checked=false]:ring-slate-400/50',
32
+ 'web:data-[focus-visible=true]:data-[checked=true]:ring-stroke-focus',
33
+ 'data-[invalid=true]:data-[hover=true]:border-stroke-danger',
34
+ 'web:data-[invalid=true]:data-[focus-visible=true]:ring-stroke-danger',
35
+ ].join(' '),
36
+ default: '',
37
+ }),
38
+ ]);
39
+
40
+ export const radioInnerDotVariants = cva([
41
+ 'rounded-[var(--border-radius-round)]',
42
+ 'h-2.5 w-2.5',
43
+ 'scale-0',
44
+ 'data-[checked=true]:scale-100',
45
+ 'bg-surface-action-strong',
46
+ 'data-[invalid=true]:bg-surface-danger-strong',
47
+ ]);
48
+
49
+ export const radioLabelVariants = cva(['body-md', 'text-content-primary']);
50
+
51
+ export const radioGroupVariants = cva([], {
52
+ variants: {
53
+ direction: {
54
+ column: 'gap-2',
55
+ row: 'flex-row gap-4',
56
+ },
57
+ },
58
+ defaultVariants: { direction: 'column' },
59
+ });
@@ -16,6 +16,7 @@ export * from './Link';
16
16
  export * from './ListItem';
17
17
  export * from './ProgressBar';
18
18
  export * from './ProgressSegmented';
19
+ export * from './Radio';
19
20
  export * from './Select';
20
21
  export * from './VirtualizedList';
21
22
  export * from './Switch';