@cdx-ui/components 0.0.1-beta.1 → 0.0.1-beta.11

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 (92) hide show
  1. package/README.md +7 -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 -5
  7. package/lib/commonjs/components/Card/styles.js.map +1 -1
  8. package/lib/commonjs/components/Heading/styles.js.map +1 -1
  9. package/lib/commonjs/components/IconButton/styles.js +1 -1
  10. package/lib/commonjs/components/IconButton/styles.js.map +1 -1
  11. package/lib/commonjs/components/Input/styles.js +1 -1
  12. package/lib/commonjs/components/Input/styles.js.map +1 -1
  13. package/lib/commonjs/components/ListItem/index.js +283 -0
  14. package/lib/commonjs/components/ListItem/index.js.map +1 -0
  15. package/lib/commonjs/components/ListItem/styles.js +130 -0
  16. package/lib/commonjs/components/ListItem/styles.js.map +1 -0
  17. package/lib/commonjs/components/Radio/index.js +165 -0
  18. package/lib/commonjs/components/Radio/index.js.map +1 -0
  19. package/lib/commonjs/components/Radio/styles.js +30 -0
  20. package/lib/commonjs/components/Radio/styles.js.map +1 -0
  21. package/lib/commonjs/components/Text/styles.js.map +1 -1
  22. package/lib/commonjs/components/index.js +24 -0
  23. package/lib/commonjs/components/index.js.map +1 -1
  24. package/lib/commonjs/figma/Button.figma.js +69 -0
  25. package/lib/commonjs/figma/Button.figma.js.map +1 -0
  26. package/lib/commonjs/figma/Radio.figma.js +38 -0
  27. package/lib/commonjs/figma/Radio.figma.js.map +1 -0
  28. package/lib/commonjs/styles/primitives.js +0 -1
  29. package/lib/commonjs/styles/primitives.js.map +1 -1
  30. package/lib/module/components/Button/styles.js +1 -1
  31. package/lib/module/components/Button/styles.js.map +1 -1
  32. package/lib/module/components/Card/index.js +16 -3
  33. package/lib/module/components/Card/index.js.map +1 -1
  34. package/lib/module/components/Card/styles.js +17 -5
  35. package/lib/module/components/Card/styles.js.map +1 -1
  36. package/lib/module/components/Heading/styles.js.map +1 -1
  37. package/lib/module/components/IconButton/styles.js +1 -1
  38. package/lib/module/components/IconButton/styles.js.map +1 -1
  39. package/lib/module/components/Input/styles.js +1 -1
  40. package/lib/module/components/Input/styles.js.map +1 -1
  41. package/lib/module/components/ListItem/index.js +226 -0
  42. package/lib/module/components/ListItem/index.js.map +1 -0
  43. package/lib/module/components/ListItem/styles.js +127 -0
  44. package/lib/module/components/ListItem/styles.js.map +1 -0
  45. package/lib/module/components/Radio/index.js +162 -0
  46. package/lib/module/components/Radio/index.js.map +1 -0
  47. package/lib/module/components/Radio/styles.js +27 -0
  48. package/lib/module/components/Radio/styles.js.map +1 -0
  49. package/lib/module/components/Text/styles.js.map +1 -1
  50. package/lib/module/components/index.js +2 -0
  51. package/lib/module/components/index.js.map +1 -1
  52. package/lib/module/figma/Button.figma.js +63 -0
  53. package/lib/module/figma/Button.figma.js.map +1 -0
  54. package/lib/module/figma/Radio.figma.js +32 -0
  55. package/lib/module/figma/Radio.figma.js.map +1 -0
  56. package/lib/module/styles/primitives.js +0 -1
  57. package/lib/module/styles/primitives.js.map +1 -1
  58. package/lib/typescript/components/Card/index.d.ts +3 -2
  59. package/lib/typescript/components/Card/index.d.ts.map +1 -1
  60. package/lib/typescript/components/Card/styles.d.ts +9 -2
  61. package/lib/typescript/components/Card/styles.d.ts.map +1 -1
  62. package/lib/typescript/components/Heading/styles.d.ts.map +1 -1
  63. package/lib/typescript/components/ListItem/index.d.ts +49 -0
  64. package/lib/typescript/components/ListItem/index.d.ts.map +1 -0
  65. package/lib/typescript/components/ListItem/styles.d.ts +30 -0
  66. package/lib/typescript/components/ListItem/styles.d.ts.map +1 -0
  67. package/lib/typescript/components/Radio/index.d.ts +40 -0
  68. package/lib/typescript/components/Radio/index.d.ts.map +1 -0
  69. package/lib/typescript/components/Radio/styles.d.ts +8 -0
  70. package/lib/typescript/components/Radio/styles.d.ts.map +1 -0
  71. package/lib/typescript/components/Text/styles.d.ts.map +1 -1
  72. package/lib/typescript/components/index.d.ts +2 -0
  73. package/lib/typescript/components/index.d.ts.map +1 -1
  74. package/lib/typescript/figma/Button.figma.d.ts +8 -0
  75. package/lib/typescript/figma/Button.figma.d.ts.map +1 -0
  76. package/lib/typescript/figma/Radio.figma.d.ts +8 -0
  77. package/lib/typescript/figma/Radio.figma.d.ts.map +1 -0
  78. package/lib/typescript/styles/primitives.d.ts.map +1 -1
  79. package/package.json +6 -5
  80. package/src/components/Button/styles.ts +1 -1
  81. package/src/components/Card/index.tsx +33 -13
  82. package/src/components/Card/styles.ts +31 -23
  83. package/src/components/IconButton/styles.ts +1 -1
  84. package/src/components/Input/styles.ts +1 -1
  85. package/src/components/ListItem/index.tsx +285 -0
  86. package/src/components/ListItem/styles.ts +160 -0
  87. package/src/components/Radio/index.tsx +191 -0
  88. package/src/components/Radio/styles.ts +59 -0
  89. package/src/components/index.ts +2 -0
  90. package/src/styles/primitives.ts +0 -1
  91. /package/src/components/Heading/{styles.tsx → styles.ts} +0 -0
  92. /package/src/components/Text/{styles.tsx → styles.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Radio.figma.d.ts","sourceRoot":"","sources":["../../../src/figma/Radio.figma.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;;;;;;AAsB1B,wBAOE"}
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/styles/primitives.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAC7C,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAG/C,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AACtD,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AACrD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAGrD,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AACjD,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAC/C,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AACvD,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAGjD,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAGjD,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AACnD,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAItD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyClB,CAAC;AAGX,eAAO,MAAM,UAAU,2CAA2C,CAAC;AAGnE,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAG1C,eAAO,MAAM,SAAS,cAAc,CAAC;AACrC,eAAO,MAAM,SAAS,cAAc,CAAC;AAMrC,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAGb,CAAC;AAGX,eAAO,MAAM,iBAAiB,mCAAmC,CAAC;AAGlE,eAAO,MAAM,gBAAgB,oCAAoC,CAAC;AAClE,eAAO,MAAM,eAAe,qFACwD,CAAC"}
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/styles/primitives.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAC7C,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAG/C,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AACtD,eAAO,MAAM,kBAAkB,qBAAqB,CAAC;AACrD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAGrD,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AACnD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AACrD,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AACjD,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAC/C,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AACvD,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAGjD,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAGjD,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AACnD,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAItD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyClB,CAAC;AAGX,eAAO,MAAM,UAAU,2CAA2C,CAAC;AAGnE,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,WAAW,iBAAiB,CAAC;AAG1C,eAAO,MAAM,SAAS,cAAc,CAAC;AACrC,eAAO,MAAM,SAAS,cAAc,CAAC;AAMrC,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAGb,CAAC;AAGX,eAAO,MAAM,iBAAiB,mCAAmC,CAAC;AAGlE,eAAO,MAAM,gBAAgB,oCAAoC,CAAC;AAClE,eAAO,MAAM,eAAe,qFACwD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdx-ui/components",
3
- "version": "0.0.1-beta.1",
3
+ "version": "0.0.1-beta.11",
4
4
  "main": "lib/commonjs/index.js",
5
5
  "module": "lib/module/index.js",
6
6
  "react-native": "src/index.ts",
@@ -24,7 +24,8 @@
24
24
  },
25
25
  "files": [
26
26
  "lib",
27
- "src"
27
+ "src",
28
+ "!src/figma"
28
29
  ],
29
30
  "react-native-builder-bob": {
30
31
  "source": "src",
@@ -66,9 +67,9 @@
66
67
  "@gorhom/bottom-sheet": "^5.2.6",
67
68
  "class-variance-authority": "^0.7.1",
68
69
  "uniwind": "1.6.1",
69
- "@cdx-ui/primitives": "0.0.1-beta.1",
70
- "@cdx-ui/icons": "0.0.1-beta.1",
71
- "@cdx-ui/utils": "0.0.1-beta.1"
70
+ "@cdx-ui/primitives": "0.0.1-beta.11",
71
+ "@cdx-ui/utils": "0.0.1-beta.11",
72
+ "@cdx-ui/icons": "0.0.1-beta.11"
72
73
  },
73
74
  "devDependencies": {
74
75
  "@types/react": "*",
@@ -10,7 +10,7 @@ export const buttonRootVariants = cva(
10
10
  'rounded-[var(--border-radius-button)]',
11
11
  'web:outline-none web:focus:outline-none web:focus-visible:outline-none',
12
12
  TRANSITION_COLORS,
13
- 'data-[disabled=true]:opacity-[--opacity-disabled]',
13
+ 'data-[disabled=true]:opacity-[var(--opacity-disabled)]',
14
14
  DISABLED_CURSOR,
15
15
  'web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-[--color-stroke-focus] web:data-[focus-visible=true]:ring-offset-2',
16
16
  ],
@@ -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,27 +1,30 @@
1
- import { cva } from 'class-variance-authority';
2
- import {
3
- COLOR_BG_PRIMARY,
4
- COLOR_BORDER_DEFAULT,
5
- COLOR_TEXT_PRIMARY,
6
- RADIUS_SM,
7
- SHADOW_SM,
8
- } from '../../styles/primitives';
1
+ import { cva, VariantProps } from 'class-variance-authority';
9
2
 
10
3
  // ── Root ────────────────────────────────────────────────────
11
4
 
12
- export const cardRootVariants = cva([
13
- COLOR_BG_PRIMARY,
14
- `border ${COLOR_BORDER_DEFAULT}`,
15
- RADIUS_SM,
16
- SHADOW_SM,
17
- 'overflow-hidden',
18
- ]);
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
+ );
19
21
 
20
22
  // ── Header ──────────────────────────────────────────────────
21
23
 
22
24
  export const cardHeaderVariants = cva([
23
- 'flex-row items-center justify-between p-4 border-b border-t-8',
24
- COLOR_BORDER_DEFAULT,
25
+ 'flex-row items-center justify-between px-5 py-3',
26
+ 'border-t-8 border-t-surface-brand-strong',
27
+ 'border-b border-b-solid border-b-stroke-secondary',
25
28
  ]);
26
29
 
27
30
  // ── Title ───────────────────────────────────────────────────
@@ -30,12 +33,17 @@ export const cardTitleVariants = cva(['flex-1']);
30
33
 
31
34
  // ── Content ─────────────────────────────────────────────────
32
35
 
33
- export const cardContentVariants = cva([COLOR_TEXT_PRIMARY, 'p-4']);
36
+ export const cardContentVariants = cva(['text-content-primary', 'p-5'], {
37
+ variants: {
38
+ fullBleed: {
39
+ true: 'p-0',
40
+ },
41
+ },
42
+ });
34
43
 
35
44
  // ── Footer ──────────────────────────────────────────────────
36
45
 
37
- export const cardFooterVariants = cva([
38
- 'p-4 border-t',
39
- COLOR_BORDER_DEFAULT,
40
- 'flex-row items-center gap-2',
41
- ]);
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,285 @@
1
+ import { forwardRef, type ReactNode } from 'react';
2
+ import { Pressable, Text, View, type TextProps, type ViewProps } from 'react-native';
3
+ import {
4
+ createListItem,
5
+ type IListItemLeadingSlotProps,
6
+ type IListItemProps,
7
+ type IListItemSectionHeaderProps,
8
+ type ListItemCrossAlign,
9
+ } from '@cdx-ui/primitives';
10
+ import { cn, useStyleContext, withStyleContext, type WithStyleContextProps } from '@cdx-ui/utils';
11
+ import {
12
+ listItemContentVariants,
13
+ listItemDescriptionVariants,
14
+ listItemLeadingSlotVariants,
15
+ listItemMetaVariants,
16
+ listItemRootVariants,
17
+ listItemSectionHeaderLabelVariants,
18
+ listItemSectionHeaderVariants,
19
+ listItemTitleVariants,
20
+ listItemTrailingSlotVariants,
21
+ type ListItemVariantProps,
22
+ } from './styles';
23
+
24
+ const SCOPE = 'LIST_ITEM';
25
+
26
+ const RootView = withStyleContext(View, SCOPE);
27
+ const RootPressable = withStyleContext(Pressable, SCOPE);
28
+
29
+ const ListItemPrimitive = createListItem({
30
+ View: RootView,
31
+ Pressable: RootPressable,
32
+ LeadingSlot: View,
33
+ Content: View,
34
+ Title: Text,
35
+ Description: Text,
36
+ Meta: Text,
37
+ TrailingSlot: View,
38
+ SectionHeader: View,
39
+ });
40
+
41
+ const useListItemStyleContext = (): Pick<ListItemVariantProps, 'size' | 'crossAlign'> => {
42
+ const ctx = useStyleContext(SCOPE) as ListItemVariantProps | undefined;
43
+ return { size: ctx?.size ?? 'default', crossAlign: ctx?.crossAlign ?? 'center' };
44
+ };
45
+
46
+ // =============================================================================
47
+ // ROOT
48
+ // =============================================================================
49
+
50
+ export interface ListItemProps extends IListItemProps, WithStyleContextProps {
51
+ className?: string;
52
+ }
53
+
54
+ const ListItemRoot = forwardRef<View, ListItemProps>(
55
+ (
56
+ {
57
+ size = 'default',
58
+ surface = 'default',
59
+ showSeparator = true,
60
+ crossAlign = 'center',
61
+ className,
62
+ style,
63
+ ...props
64
+ },
65
+ ref,
66
+ ) => {
67
+ const computedClassName = cn(
68
+ listItemRootVariants({ size, surface, showSeparator, crossAlign }),
69
+ className,
70
+ );
71
+
72
+ return (
73
+ <ListItemPrimitive
74
+ ref={ref as never}
75
+ className={computedClassName}
76
+ context={{ size, surface, showSeparator, crossAlign }}
77
+ crossAlign={crossAlign}
78
+ showSeparator={showSeparator}
79
+ size={size}
80
+ style={style}
81
+ surface={surface}
82
+ {...props}
83
+ />
84
+ );
85
+ },
86
+ );
87
+
88
+ ListItemRoot.displayName = 'ListItem';
89
+
90
+ // =============================================================================
91
+ // SLOTS & TEXT
92
+ // =============================================================================
93
+
94
+ export interface ListItemLeadingSlotProps extends IListItemLeadingSlotProps {
95
+ className?: string;
96
+ }
97
+
98
+ const ListItemLeadingSlot = forwardRef<View, ListItemLeadingSlotProps>(
99
+ ({ className, style, ...props }, ref) => (
100
+ <ListItemPrimitive.LeadingSlot
101
+ ref={ref as never}
102
+ className={cn(listItemLeadingSlotVariants(), className)}
103
+ style={style}
104
+ {...props}
105
+ />
106
+ ),
107
+ );
108
+
109
+ ListItemLeadingSlot.displayName = 'ListItem.LeadingSlot';
110
+
111
+ export interface ListItemContentProps extends ViewProps {
112
+ className?: string;
113
+ }
114
+
115
+ const ListItemContent = forwardRef<View, ListItemContentProps>(
116
+ ({ className, style, ...props }, ref) => {
117
+ const { crossAlign } = useListItemStyleContext();
118
+
119
+ return (
120
+ <ListItemPrimitive.Content
121
+ ref={ref as never}
122
+ className={cn(listItemContentVariants({ crossAlign }), className)}
123
+ style={style}
124
+ {...props}
125
+ />
126
+ );
127
+ },
128
+ );
129
+
130
+ ListItemContent.displayName = 'ListItem.Content';
131
+
132
+ export interface ListItemTitleProps extends TextProps {
133
+ className?: string;
134
+ }
135
+
136
+ const ListItemTitle = forwardRef<Text, ListItemTitleProps>(
137
+ ({ className, numberOfLines = 1, style, ...props }, ref) => {
138
+ const { size } = useListItemStyleContext();
139
+
140
+ return (
141
+ <ListItemPrimitive.Title
142
+ ref={ref as never}
143
+ className={cn(listItemTitleVariants({ size }), className)}
144
+ numberOfLines={numberOfLines}
145
+ style={style}
146
+ {...props}
147
+ />
148
+ );
149
+ },
150
+ );
151
+
152
+ ListItemTitle.displayName = 'ListItem.Title';
153
+
154
+ export interface ListItemDescriptionProps extends TextProps {
155
+ className?: string;
156
+ }
157
+
158
+ const ListItemDescription = forwardRef<Text, ListItemDescriptionProps>(
159
+ ({ className, style, ...props }, ref) => {
160
+ const { size } = useListItemStyleContext();
161
+
162
+ return (
163
+ <ListItemPrimitive.Description
164
+ ref={ref as never}
165
+ className={cn(listItemDescriptionVariants({ size }), className)}
166
+ style={style}
167
+ {...props}
168
+ />
169
+ );
170
+ },
171
+ );
172
+
173
+ ListItemDescription.displayName = 'ListItem.Description';
174
+
175
+ export interface ListItemMetaProps extends TextProps {
176
+ className?: string;
177
+ }
178
+
179
+ const ListItemMeta = forwardRef<Text, ListItemMetaProps>(
180
+ ({ className, numberOfLines = 1, style, ...props }, ref) => {
181
+ const { size } = useListItemStyleContext();
182
+
183
+ return (
184
+ <ListItemPrimitive.Meta
185
+ ref={ref as never}
186
+ className={cn(listItemMetaVariants({ size }), className)}
187
+ numberOfLines={numberOfLines}
188
+ style={style}
189
+ {...props}
190
+ />
191
+ );
192
+ },
193
+ );
194
+
195
+ ListItemMeta.displayName = 'ListItem.Meta';
196
+
197
+ export interface ListItemTrailingSlotProps extends ViewProps {
198
+ className?: string;
199
+ }
200
+
201
+ const ListItemTrailingSlot = forwardRef<View, ListItemTrailingSlotProps>(
202
+ ({ className, style, ...props }, ref) => {
203
+ const { crossAlign } = useListItemStyleContext();
204
+
205
+ return (
206
+ <ListItemPrimitive.TrailingSlot
207
+ ref={ref as never}
208
+ className={cn(listItemTrailingSlotVariants({ crossAlign }), className)}
209
+ style={style}
210
+ {...props}
211
+ />
212
+ );
213
+ },
214
+ );
215
+
216
+ ListItemTrailingSlot.displayName = 'ListItem.TrailingSlot';
217
+
218
+ const wrapSectionHeaderLabel = (children: ReactNode): ReactNode => {
219
+ if (typeof children === 'string' || typeof children === 'number') {
220
+ return <Text className={cn(listItemSectionHeaderLabelVariants())}>{children}</Text>;
221
+ }
222
+ return children;
223
+ };
224
+
225
+ // =============================================================================
226
+ // SECTION HEADER
227
+ // =============================================================================
228
+
229
+ export interface ListItemSectionHeaderComponentProps extends IListItemSectionHeaderProps {
230
+ className?: string;
231
+ }
232
+
233
+ const ListItemSectionHeader = forwardRef<View, ListItemSectionHeaderComponentProps>(
234
+ ({ children, className, showDivider = true, style, trailing, ...props }, ref) => (
235
+ <ListItemPrimitive.SectionHeader
236
+ ref={ref as never}
237
+ className={cn(listItemSectionHeaderVariants({ showDivider }), className)}
238
+ showDivider={showDivider}
239
+ style={style}
240
+ trailing={trailing}
241
+ {...props}
242
+ >
243
+ {wrapSectionHeaderLabel(children)}
244
+ </ListItemPrimitive.SectionHeader>
245
+ ),
246
+ );
247
+
248
+ ListItemSectionHeader.displayName = 'ListItem.SectionHeader';
249
+
250
+ // =============================================================================
251
+ // COMPOUND EXPORT
252
+ // =============================================================================
253
+
254
+ type ListItemCompound = typeof ListItemRoot & {
255
+ LeadingSlot: typeof ListItemLeadingSlot;
256
+ Content: typeof ListItemContent;
257
+ Title: typeof ListItemTitle;
258
+ Description: typeof ListItemDescription;
259
+ Meta: typeof ListItemMeta;
260
+ TrailingSlot: typeof ListItemTrailingSlot;
261
+ SectionHeader: typeof ListItemSectionHeader;
262
+ };
263
+
264
+ export const ListItem = Object.assign(ListItemRoot, {
265
+ LeadingSlot: ListItemLeadingSlot,
266
+ Content: ListItemContent,
267
+ Title: ListItemTitle,
268
+ Description: ListItemDescription,
269
+ Meta: ListItemMeta,
270
+ TrailingSlot: ListItemTrailingSlot,
271
+ SectionHeader: ListItemSectionHeader,
272
+ }) as ListItemCompound;
273
+
274
+ export type { ListItemCrossAlign, ListItemVariantProps };
275
+ export {
276
+ listItemContentVariants,
277
+ listItemDescriptionVariants,
278
+ listItemLeadingSlotVariants,
279
+ listItemMetaVariants,
280
+ listItemRootVariants,
281
+ listItemSectionHeaderLabelVariants,
282
+ listItemSectionHeaderVariants,
283
+ listItemTitleVariants,
284
+ listItemTrailingSlotVariants,
285
+ } from './styles';
@@ -0,0 +1,160 @@
1
+ import { Platform } from 'react-native';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+ import {
4
+ COLOR_BORDER_DEFAULT,
5
+ COLOR_TEXT_MUTED,
6
+ COLOR_TEXT_PRIMARY,
7
+ COLOR_TEXT_SECONDARY,
8
+ TRANSITION_COLORS,
9
+ } from '../../styles/primitives';
10
+
11
+ // ── Root (row): density, surface, separator, interactive feedback ──────────
12
+
13
+ export const listItemRootVariants = cva(
14
+ [
15
+ 'flex-row self-stretch w-full px-4',
16
+ 'data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none',
17
+ 'data-[active=true]:opacity-70',
18
+ TRANSITION_COLORS,
19
+ Platform.select({
20
+ web: [
21
+ 'outline-none',
22
+ 'web:data-[hovered=true]:bg-slate-50',
23
+ 'web:focus-visible:data-[disabled=false]:bg-slate-50',
24
+ 'web:focus-visible:data-[disabled=false]:ring-2 web:focus-visible:data-[disabled=false]:ring-slate-400/40 web:focus-visible:data-[disabled=false]:ring-offset-2',
25
+ ].join(' '),
26
+ default: '',
27
+ }),
28
+ ],
29
+ {
30
+ variants: {
31
+ size: {
32
+ default: 'gap-3 py-4',
33
+ compact: 'gap-2 py-3',
34
+ },
35
+ surface: {
36
+ default: 'bg-white',
37
+ negative: 'bg-red-50',
38
+ },
39
+ showSeparator: {
40
+ true: ['border-b border-solid', COLOR_BORDER_DEFAULT],
41
+ false: 'border-b-0',
42
+ },
43
+ crossAlign: {
44
+ center: 'items-center',
45
+ start: 'items-start',
46
+ },
47
+ },
48
+ compoundVariants: [
49
+ {
50
+ surface: 'negative',
51
+ className: Platform.select({
52
+ web: 'web:data-[hovered=true]:bg-red-100/90',
53
+ default: '',
54
+ }),
55
+ },
56
+ ],
57
+ defaultVariants: {
58
+ size: 'default',
59
+ surface: 'default',
60
+ showSeparator: true,
61
+ crossAlign: 'center',
62
+ },
63
+ },
64
+ );
65
+
66
+ // ── Leading / trailing slots ─────────────────────────────────────────────────
67
+
68
+ export const listItemLeadingSlotVariants = cva(['flex shrink-0 items-center justify-center']);
69
+
70
+ export const listItemTrailingSlotVariants = cva(['flex shrink-0 flex-row justify-end gap-2'], {
71
+ variants: {
72
+ crossAlign: {
73
+ center: 'items-center',
74
+ start: 'items-start self-start',
75
+ },
76
+ },
77
+ defaultVariants: {
78
+ crossAlign: 'center',
79
+ },
80
+ });
81
+
82
+ // ── Content stack (title / description / meta) ───────────────────────────────
83
+
84
+ export const listItemContentVariants = cva(['flex min-w-0 flex-1 flex-col gap-1'], {
85
+ variants: {
86
+ crossAlign: {
87
+ center: 'justify-center',
88
+ start: 'justify-start',
89
+ },
90
+ },
91
+ defaultVariants: {
92
+ crossAlign: 'center',
93
+ },
94
+ });
95
+
96
+ // ── Typography ───────────────────────────────────────────────────────────────
97
+
98
+ export const listItemTitleVariants = cva([COLOR_TEXT_PRIMARY, 'font-medium'], {
99
+ variants: {
100
+ size: {
101
+ default: 'text-base leading-snug',
102
+ compact: 'text-sm leading-snug',
103
+ },
104
+ },
105
+ defaultVariants: {
106
+ size: 'default',
107
+ },
108
+ });
109
+
110
+ export const listItemDescriptionVariants = cva([COLOR_TEXT_SECONDARY], {
111
+ variants: {
112
+ size: {
113
+ default: 'text-sm leading-normal',
114
+ compact: 'text-xs leading-normal',
115
+ },
116
+ },
117
+ defaultVariants: {
118
+ size: 'default',
119
+ },
120
+ });
121
+
122
+ export const listItemMetaVariants = cva([COLOR_TEXT_MUTED], {
123
+ variants: {
124
+ size: {
125
+ default: 'text-xs leading-normal',
126
+ compact: 'text-[11px] leading-normal',
127
+ },
128
+ },
129
+ defaultVariants: {
130
+ size: 'default',
131
+ },
132
+ });
133
+
134
+ // ── Section header (group label row inside lists / cards) ───────────────────
135
+
136
+ export const listItemSectionHeaderVariants = cva(
137
+ [
138
+ 'flex-row items-center justify-between gap-2 border-b border-solid px-4 py-3',
139
+ COLOR_BORDER_DEFAULT,
140
+ ],
141
+ {
142
+ variants: {
143
+ showDivider: {
144
+ true: ['border-t-4 border-solid border-t-surface-brand-strong/40', 'border-x-0'],
145
+ false: 'border-t-0',
146
+ },
147
+ },
148
+ defaultVariants: {
149
+ showDivider: true,
150
+ },
151
+ },
152
+ );
153
+
154
+ /** Default section-title typography; applied by `ListItem.SectionHeader` for string/number children. Exported for rare custom composition. */
155
+ export const listItemSectionHeaderLabelVariants = cva([
156
+ 'text-xs font-semibold uppercase tracking-wide',
157
+ COLOR_TEXT_SECONDARY,
158
+ ]);
159
+
160
+ export type ListItemVariantProps = VariantProps<typeof listItemRootVariants>;