@coinbase/cds-mcp-server 8.27.4 → 8.28.1

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,14 @@ All notable changes to this project will be documented in this file.
8
8
 
9
9
  <!-- template-start -->
10
10
 
11
+ ## 8.28.1 ((12/10/2025, 04:33 PM PST))
12
+
13
+ This is an artificial version bump with no new change.
14
+
15
+ ## 8.28.0 ((12/10/2025, 03:41 PM PST))
16
+
17
+ This is an artificial version bump with no new change.
18
+
11
19
  ## 8.27.4 ((12/7/2025, 11:54 AM PST))
12
20
 
13
21
  This is an artificial version bump with no new change.
@@ -14,89 +14,143 @@ import { ContentCell } from '@coinbase/cds-mobile/cells/ContentCell'
14
14
 
15
15
  ```tsx
16
16
  <ContentCell
17
+ spacingVariant="condensed"
17
18
  title="Main Title"
18
19
  subtitle="Subtitle text"
19
- description="This is a detailed description of the content."
20
- accessibilityLabel="Main content cell"
20
+ description="This is a detailed description of the content that can span multiple lines and will automatically handle overflow."
21
21
  />
22
22
  ```
23
23
 
24
- ### With Meta Information
24
+ ### Spacing variants
25
+
26
+ ```tsx
27
+ <VStack>
28
+ {/* Preferred configuration */}
29
+ <ContentCell
30
+ accessory="arrow"
31
+ description="New design (condensed)"
32
+ meta="Updated 2m ago"
33
+ spacingVariant="condensed"
34
+ media={<Avatar size="m" src={assets.eth.imageUrl} />}
35
+ title="Condensed"
36
+ onPress={() => console.log('pressed')}
37
+ styles={{
38
+ media: {
39
+ paddingTop: theme.space[1],
40
+ },
41
+ }}
42
+ />
43
+
44
+ {/* Legacy spacing kept for backward compatibility */}
45
+ <ContentCell
46
+ accessory="arrow"
47
+ description="Legacy compact spacing"
48
+ meta="Updated 2m ago"
49
+ spacingVariant="compact"
50
+ media={<Avatar size="m" src={assets.eth.imageUrl} />}
51
+ title="Compact (legacy)"
52
+ onPress={() => console.log('pressed')}
53
+ styles={{
54
+ media: {
55
+ paddingTop: theme.space[1],
56
+ },
57
+ }}
58
+ />
59
+
60
+ <ContentCell
61
+ accessory="arrow"
62
+ description="Legacy normal spacing"
63
+ meta="Updated 2m ago"
64
+ spacingVariant="normal"
65
+ media={<Avatar size="m" src={assets.eth.imageUrl} />}
66
+ title="Normal (legacy)"
67
+ onPress={() => console.log('pressed')}
68
+ styles={{
69
+ media: {
70
+ paddingTop: theme.space[1],
71
+ },
72
+ }}
73
+ />
74
+ </VStack>
75
+ ```
76
+
77
+ When `spacingVariant="condensed"`, `meta` content is aligned with the accessory.
78
+
79
+ ### Meta and truncation
25
80
 
26
81
  ```tsx
27
82
  <ContentCell
28
- title="Document Title"
29
- subtitle="Last modified by John Doe"
83
+ spacingVariant="condensed"
84
+ title="This is a very long title that wraps to two lines in condensed spacing"
85
+ subtitle="This subtitle truncates to a single line"
30
86
  meta="2 days ago"
31
- description="This example shows how meta information appears aligned to the right."
32
- accessibilityHint="Double tap to view document details"
87
+ description="The title wraps to a second line because condensed spacing is enabled. The subtitle truncates to a single line and meta content is right aligned."
33
88
  />
34
89
  ```
35
90
 
36
- ### With Media and Accessory
91
+ ### With media and accessory
37
92
 
38
93
  ```tsx
39
94
  <ContentCell
95
+ spacingVariant="condensed"
40
96
  title="Profile Information"
41
97
  subtitle="Active Status"
42
98
  media={<Avatar alt="Sneezy" name="Sneezy" size="m" colorScheme="blue" />}
43
99
  accessory="disclosure"
44
- description="Profile details with avatar"
45
- accessibilityLabel="Jane Smith's profile"
100
+ description="This example demonstrates the use of media (avatar) and an accessory indicator."
101
+ styles={{
102
+ media: {
103
+ paddingTop: theme.space[1],
104
+ },
105
+ }}
46
106
  />
47
107
  ```
48
108
 
49
- ### Automatic Accessibility Label
50
-
51
- ```tsx
52
- <ContentCell
53
- title="Meeting with Team"
54
- subtitle="Tomorrow at 2 PM"
55
- description="Weekly sync meeting"
56
- // No accessibilityLabel provided - it will automatically use the title
57
- />
58
- ```
109
+ :::tip
110
+ Adjust the media `paddingTop` so the visual aligns with the text stack.
111
+ :::
59
112
 
60
- ### Compact Layout
113
+ ### Compact spacing (legacy)
61
114
 
62
115
  ```tsx
63
116
  <ContentCell
117
+ spacingVariant="compact"
64
118
  title="Compact Cell"
65
119
  subtitle="Reduced spacing"
66
120
  description="This cell uses compact spacing for denser layouts."
67
- compact
68
121
  />
69
122
  ```
70
123
 
71
- ### Selected State
124
+ ### Selected state
72
125
 
73
126
  ```tsx
74
127
  <ContentCell
128
+ spacingVariant="condensed"
75
129
  title="Selected Item"
76
130
  subtitle="With checkmark"
77
- description="This cell shows the selected state."
131
+ description="This cell shows the selected state with a checkmark accessory."
78
132
  selected
79
- accessibilityLabel="Selected item"
80
133
  />
81
134
  ```
82
135
 
83
- ### Loading States
136
+ ### Loading states
84
137
 
85
- The ContentCellFallback component provides loading state representations of ContentCell. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. Each placeholder can have its width determined by a predefined set of values, which can be selected using the `rectWidthVariant` prop. The mobile version leverages the theme system for consistent line heights and reuses the ContentCell component structure for layout consistency.
138
+ The `ContentCellFallback` component provides loading state representations of `ContentCell`. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. Each placeholder can have its width determined by a predefined set of values, which can be selected using the `rectWidthVariant` prop. The mobile version leverages the theme system for consistent line heights and reuses the `ContentCell` component structure for layout consistency.
86
139
 
87
140
  ```tsx
88
141
  <VStack gap={3}>
89
142
  {/* Basic loading state */}
90
- <ContentCellFallback title subtitle description />
143
+ <ContentCellFallback spacingVariant="condensed" title subtitle description />
91
144
 
92
145
  {/* Loading state with media */}
93
- <ContentCellFallback title subtitle description media="avatar" />
146
+ <ContentCellFallback spacingVariant="condensed" title subtitle description media="avatar" />
94
147
 
95
148
  {/* Loading state with meta information */}
96
- <ContentCellFallback title subtitle description meta />
149
+ <ContentCellFallback spacingVariant="condensed" title subtitle description meta />
97
150
 
98
151
  {/* Loading state with custom width variant and disabled randomization */}
99
152
  <ContentCellFallback
153
+ spacingVariant="condensed"
100
154
  title
101
155
  subtitle
102
156
  description
@@ -107,8 +161,6 @@ The ContentCellFallback component provides loading state representations of Cont
107
161
  </VStack>
108
162
  ```
109
163
 
110
- Note: The mobile ContentCellFallback uses theme-based line heights and reuses the ContentCell component structure, resulting in a more consistent loading state appearance.
111
-
112
164
  ## Props
113
165
 
114
166
  | Prop | Type | Required | Default | Description |
@@ -144,8 +196,10 @@ Note: The mobile ContentCellFallback uses theme-based line heights and reuses th
144
196
  | `bottomContent` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | The content to display below the main cell content. |
145
197
  | `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - |
146
198
  | `columnGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
199
+ | `compact` | `boolean` | No | `-` | - |
147
200
  | `dangerouslySetBackground` | `string` | No | `-` | - |
148
201
  | `description` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Description of content. Content will wrap accordingly. |
202
+ | `descriptionNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render description. Takes precedence over description. When provided, styles.description is not applied. |
149
203
  | `detail` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | - |
150
204
  | `detailWidth` | `string \| number` | No | `-` | - |
151
205
  | `disabled` | `boolean` | No | `-` | Is the cell disabled? Will apply opacity and disable interaction. |
@@ -179,6 +233,7 @@ Note: The mobile ContentCellFallback uses theme-based line heights and reuses th
179
233
  | `maxWidth` | `string \| number` | No | `-` | - |
180
234
  | `media` | `ReactElement` | No | `-` | Media rendered at the start of the cell (icon, avatar, image, etc). Media (icon, asset, image, etc) to display at the start of the cell. |
181
235
  | `meta` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Meta information to display at the end of the title. |
236
+ | `metaNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render meta. Takes precedence over meta. When provided, styles.meta and styles.metaContainer are not applied. |
182
237
  | `minHeight` | `string \| number` | No | `-` | - |
183
238
  | `minWidth` | `string \| number` | No | `-` | - |
184
239
  | `onPointerCancel` | `((event: PointerEvent) => void)` | No | `-` | - |
@@ -210,15 +265,18 @@ Note: The mobile ContentCellFallback uses theme-based line heights and reuses th
210
265
  | `right` | `string \| number` | No | `-` | - |
211
266
  | `rowGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
212
267
  | `selected` | `boolean` | No | `-` | Is the cell selected? Will apply a background and selected accessory. |
268
+ | `spacingVariant` | `compact \| normal \| condensed` | No | `'normal'` | Spacing variant configuration. Deprecated value: compact. Prefer condensed. When spacingVariant=normal: 1. min-height is 80px 2. padding is var(--space-2) var(--space-3) 3. border-radius is var(--borderRadius-200) When spacingVariant=compact: 1. same as spacingVariant=normal, except min-height is 40px When spacingVariant=condensed: 1. min-height is undefined 2. padding is var(--space-1) var(--space-2) 3. border-radius is var(--borderRadius-0) 4. subtitle uses label1 5. title wraps to 2 lines regardless of description content |
213
269
  | `style` | `false \| RegisteredStyle<ViewStyle> \| Value \| AnimatedInterpolation<string \| number> \| WithAnimatedObject<ViewStyle> \| WithAnimatedArray<Falsy \| ViewStyle \| RegisteredStyle<ViewStyle> \| RecursiveArray<Falsy \| ViewStyle \| RegisteredStyle<ViewStyle>> \| readonly (Falsy \| ViewStyle \| RegisteredStyle<ViewStyle>)[]> \| null` | No | `-` | - |
214
- | `styles` | `{ root?: StyleProp<ViewStyle>; contentContainer?: StyleProp<ViewStyle>; topContent?: StyleProp<ViewStyle>; bottomContent?: StyleProp<ViewStyle>; pressable?: StyleProp<ViewStyle>; media?: StyleProp<ViewStyle>; intermediary?: StyleProp<ViewStyle>; end?: StyleProp<ViewStyle>; accessory?: StyleProp<ViewStyle>; }` | No | `-` | Styles for the components |
270
+ | `styles` | `{ root?: StyleProp<ViewStyle>; media?: StyleProp<ViewStyle>; accessory?: StyleProp<ViewStyle>; contentContainer?: StyleProp<ViewStyle>; pressable?: StyleProp<ViewStyle>; mainContent?: StyleProp<ViewStyle>; title?: StyleProp<TextStyle>; subtitle?: StyleProp<TextStyle>; metaContainer?: StyleProp<ViewStyle>; meta?: StyleProp<TextStyle>; description?: StyleProp<TextStyle>; }` | No | `-` | Styles for the default subcomponents. Ignored when the corresponding xxNode prop is used. |
215
271
  | `subtitle` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Subtitle of content. Max 1 line, otherwise will truncate. |
272
+ | `subtitleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subtitle. Takes precedence over subtitle. When provided, styles.subtitle is not applied. |
216
273
  | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Used to locate this view in end-to-end tests. Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID |
217
274
  | `textAlign` | `left \| right \| auto \| center \| justify` | No | `-` | - |
218
275
  | `textDecorationLine` | `none \| underline \| line-through \| underline line-through` | No | `-` | - |
219
276
  | `textDecorationStyle` | `solid \| dotted \| dashed \| double` | No | `-` | - |
220
277
  | `textTransform` | `none \| capitalize \| uppercase \| lowercase` | No | `-` | - |
221
- | `title` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Title of content. Max 1 line, otherwise will truncate. |
278
+ | `title` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Title of content. Up to 2 lines depending on spacing variant. |
279
+ | `titleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render title. Takes precedence over title. When provided, styles.title is not applied. |
222
280
  | `top` | `string \| number` | No | `-` | - |
223
281
  | `transform` | `string \| (({ scaleX: AnimatableNumericValue; } & { scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ scaleY: AnimatableNumericValue; } & { scaleX?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ translateX: AnimatableNumericValue \| ${number}%; } & { scaleX?: undefined; scaleY?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ translateY: AnimatableNumericValue \| ${number}%; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ perspective: AnimatableNumericValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotate: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotateX: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotateY: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotateZ: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ scale: AnimatableNumericValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ skewX: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ skewY: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; matrix?: undefined; }) \| ({ matrix: AnimatableNumericValue[]; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; }))[]` | No | `-` | - |
224
282
  | `userSelect` | `none \| auto \| contain \| text \| all` | No | `-` | - |
@@ -410,6 +410,45 @@ The accessibility props are only applied when the `<ListCell>` has a value for t
410
410
  </VStack>
411
411
  ```
412
412
 
413
+ ### ContentCell
414
+
415
+ ```tsx
416
+ <ListCell
417
+ multiline
418
+ description={
419
+ <Text color="fgMuted" font="body">
420
+ Long description with multiple lines. This section can be arbitrarily long and occupy many
421
+ many lines.
422
+ </Text>
423
+ }
424
+ end={
425
+ <HStack alignItems="center" gap={1}>
426
+ <Text color="fgMuted" font="label2">
427
+ Meta
428
+ </Text>
429
+ <Icon color="fg" name="caretRight" size="s" />
430
+ </HStack>
431
+ }
432
+ media={<Avatar shape="circle" size="l" src={assets.eth.imageUrl} />}
433
+ onPress={() => console.log('pressed')}
434
+ priority="end"
435
+ spacingVariant="condensed"
436
+ styles={{
437
+ media: {
438
+ marginTop: theme.space[1],
439
+ alignSelf: 'flex-start',
440
+ },
441
+ end: {
442
+ marginTop: theme.space[1],
443
+ alignSelf: 'flex-start',
444
+ },
445
+ }}
446
+ subdetail="Subdetail"
447
+ subtitle="Subtitle"
448
+ title="Content-style layout"
449
+ />
450
+ ```
451
+
413
452
  ### Loading States
414
453
 
415
454
  The ListCellFallback component provides loading state representations of ListCell. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. The web version uses percentage-based widths and custom layouts to match the ListCell's four-column structure.
@@ -630,7 +669,7 @@ Mapping to `styles` / `classNames` keys:
630
669
  | `compact` | `boolean` | No | `-` | - |
631
670
  | `dangerouslySetBackground` | `string` | No | `-` | - |
632
671
  | `description` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Description of content. Max 1 line (with title) or 2 lines (without), otherwise will truncate. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use descriptionNode. |
633
- | `descriptionNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render description. Takes precedence over description. |
672
+ | `descriptionNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render description. Takes precedence over description. When provided, styles.description is not applied. |
634
673
  | `detail` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Label and/or extra detail. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use detailNode. |
635
674
  | `detailNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render label and/or extra detail. Takes precedence over detail. |
636
675
  | `detailWidth` | `string \| number` | No | `-` | - |
@@ -702,19 +741,19 @@ Mapping to `styles` / `classNames` keys:
702
741
  | `selected` | `boolean` | No | `-` | Is the cell selected? Will apply a background and selected accessory. |
703
742
  | `spacingVariant` | `compact \| normal \| condensed` | No | `'normal'` | Spacing variant configuration. Deprecated value: compact. Prefer condensed. When spacingVariant=normal: 1. min-height is 80px 2. padding is var(--space-2) var(--space-3) 3. border-radius is var(--borderRadius-200) 4. when there is a description, titles numberOfLines={1} otherwise titles numberOfLines={2} 5. description and subdetail have font body When spacingVariant=compact: 1. same as spacingVariant=normal, except min-height is 40px When spacingVariant=condensed: 1. min-height is undefined 2. padding is var(--space-1) var(--space-2) 3. border-radius is --borderRadius-0 4. titles numberOfLines={2} 5. description and subdetail have font label2 |
704
743
  | `style` | `false \| RegisteredStyle<ViewStyle> \| Value \| AnimatedInterpolation<string \| number> \| WithAnimatedObject<ViewStyle> \| WithAnimatedArray<Falsy \| ViewStyle \| RegisteredStyle<ViewStyle> \| RecursiveArray<Falsy \| ViewStyle \| RegisteredStyle<ViewStyle>> \| readonly (Falsy \| ViewStyle \| RegisteredStyle<ViewStyle>)[]> \| null` | No | `-` | - |
705
- | `styles` | `({ root?: StyleProp<ViewStyle>; contentContainer?: StyleProp<ViewStyle>; topContent?: StyleProp<ViewStyle>; bottomContent?: StyleProp<ViewStyle>; pressable?: StyleProp<ViewStyle>; media?: StyleProp<ViewStyle>; intermediary?: StyleProp<ViewStyle>; end?: StyleProp<ViewStyle>; accessory?: StyleProp<ViewStyle>; } & { root?: StyleProp<ViewStyle>; media?: StyleProp<ViewStyle>; intermediary?: StyleProp<ViewStyle>; end?: StyleProp<ViewStyle>; accessory?: StyleProp<ViewStyle>; contentContainer?: StyleProp<ViewStyle>; pressable?: StyleProp<ViewStyle>; mainContent?: StyleProp<ViewStyle>; helperText?: StyleProp<ViewStyle>; title?: StyleProp<TextStyle>; subtitle?: StyleProp<TextStyle>; description?: StyleProp<TextStyle>; })` | No | `-` | Styles for the components |
744
+ | `styles` | `({ root?: StyleProp<ViewStyle>; contentContainer?: StyleProp<ViewStyle>; topContent?: StyleProp<ViewStyle>; bottomContent?: StyleProp<ViewStyle>; pressable?: StyleProp<ViewStyle>; media?: StyleProp<ViewStyle>; intermediary?: StyleProp<ViewStyle>; end?: StyleProp<ViewStyle>; accessory?: StyleProp<ViewStyle>; } & { root?: StyleProp<ViewStyle>; media?: StyleProp<ViewStyle>; intermediary?: StyleProp<ViewStyle>; end?: StyleProp<ViewStyle>; accessory?: StyleProp<ViewStyle>; contentContainer?: StyleProp<ViewStyle>; pressable?: StyleProp<ViewStyle>; mainContent?: StyleProp<ViewStyle>; helperText?: StyleProp<ViewStyle>; title?: StyleProp<TextStyle>; subtitle?: StyleProp<TextStyle>; description?: StyleProp<TextStyle>; })` | No | `-` | Styles for the components Styles for default subcomponents. Ignored when the corresponding xxNode prop is used. |
706
745
  | `subdetail` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Subdetail providing more information. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use subdetailNode. |
707
746
  | `subdetailFont` | `inherit \| FontFamily` | No | `-` | Font to apply to the subdetail text. |
708
747
  | `subdetailNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subdetail. Takes precedence over subdetail. |
709
748
  | `subtitle` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Subtitle to display below the title and above the description. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use subtitleNode. |
710
- | `subtitleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subtitle. Takes precedence over subtitle. |
749
+ | `subtitleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subtitle. Takes precedence over subtitle. When provided, styles.subtitle is not applied. |
711
750
  | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID Used to locate this element in unit and end-to-end tests. Used to locate this view in end-to-end tests. |
712
751
  | `textAlign` | `left \| right \| auto \| center \| justify` | No | `-` | - |
713
752
  | `textDecorationLine` | `none \| underline \| line-through \| underline line-through` | No | `-` | - |
714
753
  | `textDecorationStyle` | `solid \| dotted \| dashed \| double` | No | `-` | - |
715
754
  | `textTransform` | `none \| capitalize \| uppercase \| lowercase` | No | `-` | - |
716
755
  | `title` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Title of content. Max 1 line (with description) or 2 lines (without), otherwise will truncate. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use titleNode. |
717
- | `titleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render title. Takes precedence over title. |
756
+ | `titleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render title. Takes precedence over title. When provided, styles.title is not applied. |
718
757
  | `top` | `string \| number` | No | `-` | - |
719
758
  | `transform` | `string \| (({ scaleX: AnimatableNumericValue; } & { scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ scaleY: AnimatableNumericValue; } & { scaleX?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ translateX: AnimatableNumericValue \| ${number}%; } & { scaleX?: undefined; scaleY?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ translateY: AnimatableNumericValue \| ${number}%; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ perspective: AnimatableNumericValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotate: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotateX: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotateY: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ rotateZ: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ scale: AnimatableNumericValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; skewX?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ skewX: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewY?: undefined; matrix?: undefined; }) \| ({ skewY: AnimatableStringValue; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; matrix?: undefined; }) \| ({ matrix: AnimatableNumericValue[]; } & { scaleX?: undefined; scaleY?: undefined; translateX?: undefined; translateY?: undefined; perspective?: undefined; rotate?: undefined; rotateX?: undefined; rotateY?: undefined; rotateZ?: undefined; scale?: undefined; skewX?: undefined; skewY?: undefined; }))[]` | No | `-` | - |
720
759
  | `userSelect` | `none \| auto \| contain \| text \| all` | No | `-` | - |
@@ -14,50 +14,118 @@ import { ContentCell } from '@coinbase/cds-web/cells/ContentCell'
14
14
 
15
15
  ```tsx live
16
16
  <ContentCell
17
+ spacingVariant="condensed"
17
18
  title="Main Title"
18
19
  subtitle="Subtitle text"
19
20
  description="This is a detailed description of the content that can span multiple lines and will automatically handle overflow."
20
21
  />
21
22
  ```
22
23
 
23
- ### With Meta Information and Truncation
24
+ ### Spacing variants
25
+
26
+ ```tsx live
27
+ <VStack>
28
+ {/* Preferred configuration */}
29
+ <ContentCell
30
+ accessory="arrow"
31
+ description="New design (condensed)"
32
+ meta="Updated 2m ago"
33
+ spacingVariant="condensed"
34
+ media={<Avatar size="m" src={assets.eth.imageUrl} />}
35
+ title="Condensed"
36
+ onClick={() => console.log('clicked')}
37
+ styles={{
38
+ media: {
39
+ paddingTop: 'var(--space-0_5)',
40
+ },
41
+ }}
42
+ />
43
+
44
+ {/* Legacy spacing kept for backward compatibility */}
45
+ <ContentCell
46
+ accessory="arrow"
47
+ description="Legacy compact spacing"
48
+ meta="Updated 2m ago"
49
+ spacingVariant="compact"
50
+ media={<Avatar size="m" src={assets.eth.imageUrl} />}
51
+ title="Compact (legacy)"
52
+ onClick={() => console.log('clicked')}
53
+ styles={{
54
+ media: {
55
+ paddingTop: 'var(--space-0_5)',
56
+ },
57
+ }}
58
+ />
59
+
60
+ <ContentCell
61
+ accessory="arrow"
62
+ description="Legacy normal spacing"
63
+ meta="Updated 2m ago"
64
+ spacingVariant="normal"
65
+ media={<Avatar size="m" src={assets.eth.imageUrl} />}
66
+ title="Normal (legacy)"
67
+ onClick={() => console.log('clicked')}
68
+ styles={{
69
+ media: {
70
+ paddingTop: 'var(--space-0_5)',
71
+ },
72
+ }}
73
+ />
74
+ </VStack>
75
+ ```
76
+
77
+ When `spacingVariant="condensed"`, `meta` content is aligend with the accessory.
78
+
79
+ ### Meta and truncation
24
80
 
25
81
  ```tsx live
26
82
  <ContentCell
27
- title="This is a very long title that will be truncated when it exceeds the available space in the container"
28
- subtitle="This subtitle will also be truncated if it becomes too long for the container to display"
83
+ spacingVariant="condensed"
84
+ title="This is a very long title that wraps to two lines in condensed spacing"
85
+ subtitle="This subtitle truncates to a single line"
29
86
  meta="2 days ago"
30
- description="The title and subtitle above will be truncated with ellipsis, while this description text will wrap to multiple lines and show scrollbars if needed."
87
+ description="The title wraps to a second line because condensed spacing is enabled. The subtitle truncates to a single line and meta content is right aligned."
31
88
  />
32
89
  ```
33
90
 
34
- ### With Media and Accessory
91
+ ### With media and accessory
35
92
 
36
93
  ```tsx live
37
94
  <ContentCell
95
+ spacingVariant="condensed"
38
96
  title="Profile Information"
39
97
  subtitle="Active Status"
40
98
  media={<Avatar alt="Sneezy" name="Sneezy" size="m" colorScheme="blue" />}
41
99
  accessory="disclosure"
42
100
  description="This example demonstrates the use of media (avatar) and an accessory indicator."
101
+ styles={{
102
+ media: {
103
+ paddingTop: 'var(--space-0_5)',
104
+ },
105
+ }}
43
106
  />
44
107
  ```
45
108
 
46
- ### Compact Layout
109
+ :::tip
110
+ Adjust the media `paddingTop` so the visual aligns with the text stack.
111
+ :::
112
+
113
+ ### Compact spacing (legacy)
47
114
 
48
115
  ```tsx live
49
116
  <ContentCell
117
+ spacingVariant="compact"
50
118
  title="Compact Cell"
51
119
  subtitle="Reduced spacing"
52
120
  description="This cell uses compact spacing for denser layouts."
53
- compact
54
121
  />
55
122
  ```
56
123
 
57
- ### Selected State
124
+ ### Selected state
58
125
 
59
126
  ```tsx live
60
127
  <ContentCell
128
+ spacingVariant="condensed"
61
129
  title="Selected Item"
62
130
  subtitle="With checkmark"
63
131
  description="This cell shows the selected state with a checkmark accessory."
@@ -65,23 +133,24 @@ import { ContentCell } from '@coinbase/cds-web/cells/ContentCell'
65
133
  />
66
134
  ```
67
135
 
68
- ### Loading States
136
+ ### Loading states
69
137
 
70
- The ContentCellFallback component provides loading state representations of ContentCell. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. Each placeholder can have its width determined by a predefined set of values, which can be selected using the `rectWidthVariant` prop. The web version uses percentage-based widths and custom layouts to match the ContentCell structure.
138
+ The `ContentCellFallback` component provides loading state representations of `ContentCell`. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. Each placeholder can have its width determined by a predefined set of values, which can be selected using the `rectWidthVariant` prop. The web version uses percentage-based widths and custom layouts to match the `ContentCell` structure.
71
139
 
72
140
  ```tsx live
73
141
  <VStack gap={3}>
74
142
  {/* Basic loading state */}
75
- <ContentCellFallback title subtitle description />
143
+ <ContentCellFallback spacingVariant="condensed" title subtitle description />
76
144
 
77
145
  {/* Loading state with media */}
78
- <ContentCellFallback title subtitle description media="avatar" />
146
+ <ContentCellFallback spacingVariant="condensed" title subtitle description media="avatar" />
79
147
 
80
148
  {/* Loading state with meta information */}
81
- <ContentCellFallback title subtitle description meta />
149
+ <ContentCellFallback spacingVariant="condensed" title subtitle description meta />
82
150
 
83
151
  {/* Loading state with custom width variant and disabled randomization */}
84
152
  <ContentCellFallback
153
+ spacingVariant="condensed"
85
154
  title
86
155
  subtitle
87
156
  description
@@ -124,12 +193,14 @@ The ContentCellFallback component provides loading state representations of Cont
124
193
  | `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. |
125
194
  | `bottom` | `ResponsiveProp<Bottom<string \| number>>` | No | `-` | - |
126
195
  | `bottomContent` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | The content to display below the main cell content |
127
- | `classNames` | `{ root?: string; contentContainer?: string \| undefined; topContent?: string \| undefined; bottomContent?: string \| undefined; pressable?: string \| undefined; media?: string \| undefined; intermediary?: string \| undefined; end?: string \| undefined; accessory?: string \| undefined; } \| undefined` | No | `-` | Class names for the components |
196
+ | `classNames` | `{ root?: string; media?: string \| undefined; accessory?: string \| undefined; contentContainer?: string \| undefined; pressable?: string \| undefined; mainContent?: string \| undefined; title?: string \| undefined; subtitle?: string \| undefined; end?: string \| undefined; metaContainer?: string \| undefined; meta?: string \| undefined; description?: string \| undefined; } \| undefined` | No | `-` | Class names for default subcomponents. Ignored when the corresponding xxNode prop is used. |
128
197
  | `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - |
129
198
  | `columnGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
199
+ | `compact` | `boolean` | No | `-` | - |
130
200
  | `contentClassName` | `string` | No | `-` | - |
131
201
  | `dangerouslySetBackground` | `string` | No | `-` | - |
132
202
  | `description` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Description of content. Content will wrap accordingly. |
203
+ | `descriptionNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render description. Takes precedence over description. When provided, classNames.description and styles.description are not applied. |
133
204
  | `detail` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | - |
134
205
  | `detailWidth` | `string \| number` | No | `-` | - |
135
206
  | `disabled` | `boolean` | No | `-` | Is the cell disabled? Will apply opacity and disable interaction. |
@@ -178,6 +249,7 @@ The ContentCellFallback component provides loading state representations of Cont
178
249
  | `maxWidth` | `ResponsiveProp<MaxWidth<string \| number>>` | No | `-` | - |
179
250
  | `media` | `ReactElement` | No | `-` | Media (icon, asset, image, etc) to display at the start of the cell. |
180
251
  | `meta` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Meta information to display at the end of the title. |
252
+ | `metaNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render meta. Takes precedence over meta. When provided, classNames.meta and styles.meta are not applied. |
181
253
  | `minHeight` | `ResponsiveProp<MinHeight<string \| number>>` | No | `-` | - |
182
254
  | `minWidth` | `ResponsiveProp<MinWidth<string \| number>>` | No | `-` | - |
183
255
  | `onClick` | `MouseEventHandler<Element>` | No | `-` | Click handler. |
@@ -202,14 +274,17 @@ The ContentCellFallback component provides loading state representations of Cont
202
274
  | `selected` | `boolean` | No | `-` | Is the cell selected? Will apply a background and selected accessory. |
203
275
  | `shouldOverflow` | `boolean` | No | `-` | - |
204
276
  | `shouldTruncate` | `boolean` | No | `true` | Controls whether the main content should truncate with an ellipsis. Defaults to true (truncates) when not provided. |
277
+ | `spacingVariant` | `normal \| compact \| condensed` | No | `'normal'` | Spacing variant configuration. Deprecated value: compact. Prefer condensed. When spacingVariant=normal: 1. min-height is 80px 2. padding is var(--space-2) var(--space-3) 3. border-radius is var(--borderRadius-200) When spacingVariant=compact: 1. same as spacingVariant=normal, except min-height is 40px When spacingVariant=condensed: 1. min-height is undefined 2. padding is var(--space-1) var(--space-2) 3. border-radius is var(--borderRadius-0) 4. subtitle uses label1 5. title wraps to 2 lines regardless of description content 6. meta is placed alongside the accessory |
205
278
  | `style` | `CSSProperties` | No | `-` | - |
206
- | `styles` | `{ root?: CSSProperties; contentContainer?: CSSProperties \| undefined; topContent?: CSSProperties \| undefined; bottomContent?: CSSProperties \| undefined; pressable?: CSSProperties \| undefined; media?: CSSProperties \| undefined; intermediary?: CSSProperties \| undefined; end?: CSSProperties \| undefined; accessory?: CSSProperties \| undefined; } \| undefined` | No | `-` | Styles for the components |
279
+ | `styles` | `{ root?: CSSProperties; media?: CSSProperties \| undefined; accessory?: CSSProperties \| undefined; contentContainer?: CSSProperties \| undefined; pressable?: CSSProperties \| undefined; mainContent?: CSSProperties \| undefined; title?: CSSProperties \| undefined; subtitle?: CSSProperties \| undefined; end?: CSSProperties \| undefined; metaContainer?: CSSProperties \| undefined; meta?: CSSProperties \| undefined; description?: CSSProperties \| undefined; } \| undefined` | No | `-` | Styles for default subcomponents. Ignored when the corresponding xxNode prop is used. |
207
280
  | `subtitle` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Subtitle of content. Max 1 line, otherwise will truncate. |
281
+ | `subtitleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subtitle. Takes precedence over subtitle. When provided, classNames.subtitle and styles.subtitle are not applied. |
208
282
  | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID |
209
283
  | `textAlign` | `ResponsiveProp<center \| start \| end \| justify>` | No | `-` | - |
210
284
  | `textDecoration` | `ResponsiveProp<none \| underline \| overline \| line-through \| underline overline \| underline double>` | No | `-` | - |
211
285
  | `textTransform` | `ResponsiveProp<capitalize \| lowercase \| none \| uppercase>` | No | `-` | - |
212
- | `title` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Title of content. Max 1 line, otherwise will truncate. |
286
+ | `title` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Title of content. Up to 2 lines depending on spacing variant. |
287
+ | `titleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render title. Takes precedence over title. When provided, classNames.title and styles.title are not applied. |
213
288
  | `top` | `ResponsiveProp<Top<string \| number>>` | No | `-` | - |
214
289
  | `transform` | `inherit \| none \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
215
290
  | `userSelect` | `ResponsiveProp<text \| none \| auto \| all>` | No | `-` | - |
@@ -410,6 +410,45 @@ The accessibility props are only applied when the `<ListCell>` has a value for t
410
410
  </VStack>
411
411
  ```
412
412
 
413
+ ### ContentCell
414
+
415
+ ```tsx live
416
+ <ListCell
417
+ multiline
418
+ description={
419
+ <Text as="div" color="fgMuted" font="body">
420
+ Long description with multiple lines. This section can be arbitrarily long and occupy many
421
+ many lines.
422
+ </Text>
423
+ }
424
+ end={
425
+ <HStack alignItems="center" gap={2}>
426
+ <Text color="fgMuted" font="label2">
427
+ Meta
428
+ </Text>
429
+ <Icon color="fg" name="caretRight" size="s" />
430
+ </HStack>
431
+ }
432
+ media={<Avatar shape="circle" size="l" src={assets.eth.imageUrl} />}
433
+ onClick={() => console.log('clicked')}
434
+ priority="end"
435
+ spacingVariant="condensed"
436
+ styles={{
437
+ media: {
438
+ marginTop: 'var(--space-0_5)',
439
+ alignSelf: 'flex-start',
440
+ },
441
+ end: {
442
+ marginTop: 'var(--space-0_5)',
443
+ alignSelf: 'flex-start',
444
+ },
445
+ }}
446
+ subdetail="Subdetail"
447
+ subtitle="Subtitle"
448
+ title="Content-style layout"
449
+ />
450
+ ```
451
+
413
452
  ### Loading States
414
453
 
415
454
  The ListCellFallback component provides loading state representations of ListCell. It uses placeholder rectangles to indicate where content will appear, creating a smooth loading experience. The web version uses percentage-based widths and custom layouts to match the ListCell's four-column structure.
@@ -623,14 +662,14 @@ Mapping to `styles` / `classNames` keys:
623
662
  | `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. |
624
663
  | `bottom` | `ResponsiveProp<Bottom<string \| number>>` | No | `-` | - |
625
664
  | `bottomContent` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | The content to display below the main cell content |
626
- | `classNames` | `{ root?: string; media?: string \| undefined; intermediary?: string \| undefined; end?: string \| undefined; accessory?: string \| undefined; contentContainer?: string \| undefined; pressable?: string \| undefined; mainContent?: string \| undefined; helperText?: string \| undefined; title?: string \| undefined; subtitle?: string \| undefined; description?: string \| undefined; } \| undefined` | No | `-` | Class names for the components |
665
+ | `classNames` | `{ root?: string; media?: string \| undefined; intermediary?: string \| undefined; end?: string \| undefined; accessory?: string \| undefined; contentContainer?: string \| undefined; pressable?: string \| undefined; mainContent?: string \| undefined; helperText?: string \| undefined; title?: string \| undefined; subtitle?: string \| undefined; description?: string \| undefined; } \| undefined` | No | `-` | Class names for default subcomponents. Ignored when the corresponding xxNode prop is used. |
627
666
  | `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - |
628
667
  | `columnGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
629
668
  | `compact` | `boolean` | No | `-` | - |
630
669
  | `contentClassName` | `string` | No | `-` | - |
631
670
  | `dangerouslySetBackground` | `string` | No | `-` | - |
632
671
  | `description` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Description of content. Max 1 line (with title) or 2 lines (without), otherwise will truncate. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use descriptionNode. |
633
- | `descriptionNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render description. Takes precedence over description. |
672
+ | `descriptionNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render description. Takes precedence over description. When provided, classNames.description and styles.description are not applied. |
634
673
  | `detail` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Label and/or extra detail. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use detailNode. |
635
674
  | `detailNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render label and/or extra detail. Takes precedence over detail. |
636
675
  | `detailWidth` | `string \| number` | No | `-` | - |
@@ -709,18 +748,18 @@ Mapping to `styles` / `classNames` keys:
709
748
  | `shouldTruncate` | `boolean` | No | `true` | Controls whether the main content should truncate with an ellipsis. Defaults to true (truncates) when not provided. |
710
749
  | `spacingVariant` | `normal \| compact \| condensed` | No | `'normal'` | Spacing variant configuration. Deprecated value: compact. Prefer condensed. When spacingVariant=normal: 1. min-height is 80px 2. padding is var(--space-2) var(--space-3) 3. border-radius is var(--borderRadius-200) 4. when there is a description, titles numberOfLines={1} otherwise titles numberOfLines={2} 5. description and subdetail have font body When spacingVariant=compact: 1. same as spacingVariant=normal, except min-height is 40px When spacingVariant=condensed: 1. min-height is undefined 2. padding is var(--space-1) var(--space-2) 3. border-radius is --borderRadius-0 4. titles numberOfLines={2} 5. description and subdetail have font label2 |
711
750
  | `style` | `CSSProperties` | No | `-` | - |
712
- | `styles` | `{ root?: CSSProperties; media?: CSSProperties \| undefined; intermediary?: CSSProperties \| undefined; end?: CSSProperties \| undefined; accessory?: CSSProperties \| undefined; contentContainer?: CSSProperties \| undefined; pressable?: CSSProperties \| undefined; mainContent?: CSSProperties \| undefined; helperText?: CSSProperties \| undefined; title?: CSSProperties \| undefined; subtitle?: CSSProperties \| undefined; description?: CSSProperties \| undefined; } \| undefined` | No | `-` | Styles for the components |
751
+ | `styles` | `{ root?: CSSProperties; media?: CSSProperties \| undefined; intermediary?: CSSProperties \| undefined; end?: CSSProperties \| undefined; accessory?: CSSProperties \| undefined; contentContainer?: CSSProperties \| undefined; pressable?: CSSProperties \| undefined; mainContent?: CSSProperties \| undefined; helperText?: CSSProperties \| undefined; title?: CSSProperties \| undefined; subtitle?: CSSProperties \| undefined; description?: CSSProperties \| undefined; } \| undefined` | No | `-` | Styles for default subcomponents. Ignored when the corresponding xxNode prop is used. |
713
752
  | `subdetail` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Subdetail providing more information. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use subdetailNode. |
714
753
  | `subdetailFont` | `ResponsiveProp<FontFamily \| inherit>` | No | `-` | Font to apply to the subdetail text. |
715
754
  | `subdetailNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subdetail. Takes precedence over subdetail. |
716
755
  | `subtitle` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Subtitle to display below the title and above the description. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use subtitleNode. |
717
- | `subtitleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subtitle. Takes precedence over subtitle. |
756
+ | `subtitleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render subtitle. Takes precedence over subtitle. When provided, classNames.subtitle and styles.subtitle are not applied. |
718
757
  | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID |
719
758
  | `textAlign` | `ResponsiveProp<center \| start \| end \| justify>` | No | `-` | - |
720
759
  | `textDecoration` | `ResponsiveProp<none \| underline \| overline \| line-through \| underline overline \| underline double>` | No | `-` | - |
721
760
  | `textTransform` | `ResponsiveProp<capitalize \| lowercase \| none \| uppercase>` | No | `-` | - |
722
761
  | `title` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Title of content. Max 1 line (with description) or 2 lines (without), otherwise will truncate. This prop is only intended to accept a string or Text component; other use cases, while allowed, are not supported and may result in unexpected behavior. For arbitrary content, use titleNode. |
723
- | `titleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render title. Takes precedence over title. |
762
+ | `titleNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | React node to render title. Takes precedence over title. When provided, classNames.title and styles.title are not applied. |
724
763
  | `top` | `ResponsiveProp<Top<string \| number>>` | No | `-` | - |
725
764
  | `transform` | `inherit \| none \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
726
765
  | `userSelect` | `ResponsiveProp<text \| none \| auto \| all>` | No | `-` | - |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cds-mcp-server",
3
- "version": "8.27.4",
3
+ "version": "8.28.1",
4
4
  "description": "Coinbase Design System - MCP Server",
5
5
  "repository": {
6
6
  "type": "git",