@cdx-ui/components 0.2.3 → 0.2.4

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 (248) hide show
  1. package/AGENTS.md +24 -0
  2. package/README.md +2 -0
  3. package/coverage.svg +1 -1
  4. package/docs/components/accordion/content.md +538 -0
  5. package/docs/components/alert/content.md +203 -0
  6. package/docs/components/alert-dialog/content.md +319 -0
  7. package/docs/components/avatar/content.md +368 -0
  8. package/docs/components/avatar/design.md +202 -0
  9. package/docs/components/badge/content.md +235 -0
  10. package/docs/components/bottom-sheet/content.md +351 -0
  11. package/docs/components/bottom-sheet/design.md +249 -0
  12. package/docs/components/breadcrumbs/content.md +169 -0
  13. package/docs/components/button/content.md +398 -0
  14. package/docs/components/button/design.md +258 -0
  15. package/docs/components/calendar/content.md +137 -0
  16. package/docs/components/card/content.md +283 -0
  17. package/docs/components/carousel/content.md +416 -0
  18. package/docs/components/checkbox/content.md +236 -0
  19. package/docs/components/checkbox/design.md +214 -0
  20. package/docs/components/chip/content.md +439 -0
  21. package/docs/components/chip/design.md +418 -0
  22. package/docs/components/color-area/content.md +86 -0
  23. package/docs/components/color-field/content.md +134 -0
  24. package/docs/components/color-picker/content.md +208 -0
  25. package/docs/components/color-slider/content.md +120 -0
  26. package/docs/components/color-swatch/content.md +64 -0
  27. package/docs/components/color-swatch-picker/content.md +126 -0
  28. package/docs/components/content.md +97 -0
  29. package/docs/components/currency-input/content.md +205 -0
  30. package/docs/components/data-grid/content.md +522 -0
  31. package/docs/components/date-field/content.md +147 -0
  32. package/docs/components/date-picker/content.md +360 -0
  33. package/docs/components/date-range-picker/content.md +301 -0
  34. package/docs/components/date-time-field/content.md +157 -0
  35. package/docs/components/date-time-list/content.md +105 -0
  36. package/docs/components/date-time-picker/content.md +272 -0
  37. package/docs/components/dialog/content.md +436 -0
  38. package/docs/components/dialog/design.md +192 -0
  39. package/docs/components/divider/content.md +112 -0
  40. package/docs/components/drawer/content.md +436 -0
  41. package/docs/components/field/content.md +277 -0
  42. package/docs/components/form/content.md +62 -0
  43. package/docs/components/full-screen-dialog/content.md +881 -0
  44. package/docs/components/heading/content.md +55 -0
  45. package/docs/components/icon/content.md +190 -0
  46. package/docs/components/icon-button/content.md +200 -0
  47. package/docs/components/icon-button/design.md +165 -0
  48. package/docs/components/image/content.md +104 -0
  49. package/docs/components/input/content.md +281 -0
  50. package/docs/components/input/design.md +389 -0
  51. package/docs/components/insurance-disclosure/content.md +103 -0
  52. package/docs/components/link/content.md +180 -0
  53. package/docs/components/link/design.md +160 -0
  54. package/docs/components/list-item/content.md +695 -0
  55. package/docs/components/menu/content.md +1247 -0
  56. package/docs/components/month-calendar/content.md +84 -0
  57. package/docs/components/month-picker/content.md +273 -0
  58. package/docs/components/otp-input/content.md +327 -0
  59. package/docs/components/progress-bar/content.md +87 -0
  60. package/docs/components/progress-circle/content.md +176 -0
  61. package/docs/components/progress-segmented/content.md +119 -0
  62. package/docs/components/quick-action-button/content.md +154 -0
  63. package/docs/components/quick-action-button/design.md +170 -0
  64. package/docs/components/radio/content.md +224 -0
  65. package/docs/components/range-calendar/content.md +123 -0
  66. package/docs/components/reorderable-list/content.md +309 -0
  67. package/docs/components/scoped-theme/content.md +47 -0
  68. package/docs/components/scroll-shadow/content.md +686 -0
  69. package/docs/components/select/content.md +400 -0
  70. package/docs/components/select/design.md +301 -0
  71. package/docs/components/skeleton/content.md +103 -0
  72. package/docs/components/slider/content.md +423 -0
  73. package/docs/components/stack/content.md +161 -0
  74. package/docs/components/switch/content.md +150 -0
  75. package/docs/components/switch/design.md +208 -0
  76. package/docs/components/table/content.md +548 -0
  77. package/docs/components/table-pagination/content.md +177 -0
  78. package/docs/components/tabs/content.md +292 -0
  79. package/docs/components/text/content.md +142 -0
  80. package/docs/components/textarea/content.md +222 -0
  81. package/docs/components/tile/content.md +703 -0
  82. package/docs/components/toast/content.md +456 -0
  83. package/docs/components/toggle-button/content.md +505 -0
  84. package/docs/components/tooltip/content.md +350 -0
  85. package/docs/components/virtualized-list/content.md +250 -0
  86. package/docs/foundations/content.md +9 -0
  87. package/docs/foundations/expressions/icons/content.md +19 -0
  88. package/docs/foundations/styles/tokens/all-tokens/content.md +192 -0
  89. package/docs/foundations/styles/tokens/what-are-tokens/content.md +33 -0
  90. package/docs/foundations/styles/tokens/what-are-tokens/design.md +33 -0
  91. package/docs/getting-started/content.md +4 -0
  92. package/docs/getting-started/designers/content.md +13 -0
  93. package/docs/getting-started/designers/design.md +13 -0
  94. package/docs/getting-started/developers/accessibility/content.md +31 -0
  95. package/docs/getting-started/developers/content.md +612 -0
  96. package/docs/getting-started/developers/styling/content.md +193 -0
  97. package/docs/llms.txt +193 -0
  98. package/docs/patterns/account-management/content.md +75 -0
  99. package/docs/patterns/authentication/content.md +52 -0
  100. package/docs/patterns/content.md +10 -0
  101. package/docs/patterns/dashboard/content.md +39 -0
  102. package/docs/patterns/empty-states/content.md +31 -0
  103. package/docs/patterns/forms/content.md +109 -0
  104. package/docs/patterns/onboarding/content.md +69 -0
  105. package/docs/patterns/payments/content.md +35 -0
  106. package/docs/patterns/settings/content.md +72 -0
  107. package/docs/resources/content.md +9 -0
  108. package/docs/resources/figma-libraries/content.md +42 -0
  109. package/docs/resources/release-notes/0.0.1-beta.118/content.md +27 -0
  110. package/docs/resources/release-notes/0.0.1-beta.122/content.md +21 -0
  111. package/docs/resources/release-notes/0.0.1-beta.124/content.md +16 -0
  112. package/docs/resources/release-notes/0.0.1-beta.126/content.md +10 -0
  113. package/docs/resources/release-notes/0.0.1-beta.127/content.md +14 -0
  114. package/docs/resources/release-notes/0.0.1-beta.128/content.md +9 -0
  115. package/docs/resources/release-notes/0.0.1-beta.129/content.md +18 -0
  116. package/docs/resources/release-notes/0.0.1-beta.130/content.md +18 -0
  117. package/docs/resources/release-notes/0.0.1-beta.133/content.md +7 -0
  118. package/docs/resources/release-notes/0.0.1-beta.134/content.md +17 -0
  119. package/docs/resources/release-notes/0.0.1-beta.136/content.md +7 -0
  120. package/docs/resources/release-notes/0.0.1-beta.137/content.md +10 -0
  121. package/docs/resources/release-notes/0.0.1-beta.138/content.md +7 -0
  122. package/docs/resources/release-notes/0.0.1-beta.139/content.md +13 -0
  123. package/docs/resources/release-notes/0.0.1-beta.140/content.md +26 -0
  124. package/docs/resources/release-notes/0.0.1-beta.141/content.md +63 -0
  125. package/docs/resources/release-notes/0.0.1-beta.142/content.md +7 -0
  126. package/docs/resources/release-notes/0.0.1-beta.143/content.md +12 -0
  127. package/docs/resources/release-notes/0.0.1-beta.144/content.md +7 -0
  128. package/docs/resources/release-notes/0.0.1-beta.145/content.md +7 -0
  129. package/docs/resources/release-notes/0.0.1-beta.147/content.md +10 -0
  130. package/docs/resources/release-notes/0.0.1-beta.149/content.md +10 -0
  131. package/docs/resources/release-notes/0.0.1-beta.150/content.md +13 -0
  132. package/docs/resources/release-notes/0.0.1-beta.152/content.md +7 -0
  133. package/docs/resources/release-notes/0.0.1-beta.154/content.md +15 -0
  134. package/docs/resources/release-notes/0.0.1-beta.156/content.md +7 -0
  135. package/docs/resources/release-notes/0.0.1-beta.158/content.md +9 -0
  136. package/docs/resources/release-notes/0.0.1-beta.159/content.md +11 -0
  137. package/docs/resources/release-notes/0.0.1-beta.160/content.md +7 -0
  138. package/docs/resources/release-notes/0.0.1-beta.161/content.md +7 -0
  139. package/docs/resources/release-notes/0.0.1-beta.163/content.md +7 -0
  140. package/docs/resources/release-notes/0.0.1-beta.164/content.md +9 -0
  141. package/docs/resources/release-notes/0.0.1-beta.166/content.md +17 -0
  142. package/docs/resources/release-notes/0.0.1-beta.167/content.md +7 -0
  143. package/docs/resources/release-notes/0.0.1-beta.168/content.md +7 -0
  144. package/docs/resources/release-notes/0.0.1-beta.169/content.md +7 -0
  145. package/docs/resources/release-notes/0.0.1-beta.171/content.md +16 -0
  146. package/docs/resources/release-notes/0.0.1-beta.172/content.md +24 -0
  147. package/docs/resources/release-notes/0.0.1-beta.173/content.md +15 -0
  148. package/docs/resources/release-notes/0.0.1-beta.174/content.md +7 -0
  149. package/docs/resources/release-notes/0.0.1-beta.176/content.md +32 -0
  150. package/docs/resources/release-notes/0.0.1-beta.179/content.md +11 -0
  151. package/docs/resources/release-notes/0.0.1-beta.182/content.md +13 -0
  152. package/docs/resources/release-notes/0.0.1-beta.185/content.md +7 -0
  153. package/docs/resources/release-notes/0.0.1-beta.187/content.md +27 -0
  154. package/docs/resources/release-notes/0.1.1/content.md +23 -0
  155. package/docs/resources/release-notes/0.1.2/content.md +7 -0
  156. package/docs/resources/release-notes/0.1.4/content.md +19 -0
  157. package/docs/resources/release-notes/0.1.5/content.md +7 -0
  158. package/docs/resources/release-notes/0.1.6/content.md +7 -0
  159. package/docs/resources/release-notes/0.2.0/content.md +31 -0
  160. package/docs/resources/release-notes/0.2.1/content.md +17 -0
  161. package/docs/resources/release-notes/0.2.2/content.md +11 -0
  162. package/docs/resources/release-notes/0.2.3/content.md +15 -0
  163. package/docs/resources/release-notes/content.md +64 -0
  164. package/lib/commonjs/components/DateTimeList/index.js +11 -26
  165. package/lib/commonjs/components/DateTimeList/index.js.map +1 -1
  166. package/lib/commonjs/components/DateTimeList/styles.js +2 -12
  167. package/lib/commonjs/components/DateTimeList/styles.js.map +1 -1
  168. package/lib/commonjs/components/ListItem/index.js.map +1 -1
  169. package/lib/commonjs/components/ListItem/styles.js +2 -1
  170. package/lib/commonjs/components/ListItem/styles.js.map +1 -1
  171. package/lib/commonjs/components/Menu/index.js +11 -5
  172. package/lib/commonjs/components/Menu/index.js.map +1 -1
  173. package/lib/commonjs/components/ScrollShadow/gradient.js +29 -0
  174. package/lib/commonjs/components/ScrollShadow/gradient.js.map +1 -0
  175. package/lib/commonjs/components/ScrollShadow/index.js +171 -44
  176. package/lib/commonjs/components/ScrollShadow/index.js.map +1 -1
  177. package/lib/commonjs/components/ScrollShadow/styles.js +58 -14
  178. package/lib/commonjs/components/ScrollShadow/styles.js.map +1 -1
  179. package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js +63 -0
  180. package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
  181. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +48 -8
  182. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
  183. package/lib/commonjs/components/Tabs/index.js +16 -23
  184. package/lib/commonjs/components/Tabs/index.js.map +1 -1
  185. package/lib/commonjs/components/Tabs/styles.js +1 -10
  186. package/lib/commonjs/components/Tabs/styles.js.map +1 -1
  187. package/lib/commonjs/figma/ListItem.SectionHeader.figma.js +20 -5
  188. package/lib/commonjs/figma/ListItem.SectionHeader.figma.js.map +1 -1
  189. package/lib/module/components/DateTimeList/index.js +12 -27
  190. package/lib/module/components/DateTimeList/index.js.map +1 -1
  191. package/lib/module/components/DateTimeList/styles.js +1 -11
  192. package/lib/module/components/DateTimeList/styles.js.map +1 -1
  193. package/lib/module/components/ListItem/index.js.map +1 -1
  194. package/lib/module/components/ListItem/styles.js +2 -1
  195. package/lib/module/components/ListItem/styles.js.map +1 -1
  196. package/lib/module/components/Menu/index.js +11 -5
  197. package/lib/module/components/Menu/index.js.map +1 -1
  198. package/lib/module/components/ScrollShadow/gradient.js +24 -0
  199. package/lib/module/components/ScrollShadow/gradient.js.map +1 -0
  200. package/lib/module/components/ScrollShadow/index.js +170 -48
  201. package/lib/module/components/ScrollShadow/index.js.map +1 -1
  202. package/lib/module/components/ScrollShadow/styles.js +57 -13
  203. package/lib/module/components/ScrollShadow/styles.js.map +1 -1
  204. package/lib/module/components/ScrollShadow/useComposedScrollHandler.js +57 -0
  205. package/lib/module/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
  206. package/lib/module/components/ScrollShadow/useScrollShadow.js +46 -8
  207. package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
  208. package/lib/module/components/Tabs/index.js +17 -24
  209. package/lib/module/components/Tabs/index.js.map +1 -1
  210. package/lib/module/components/Tabs/styles.js +0 -9
  211. package/lib/module/components/Tabs/styles.js.map +1 -1
  212. package/lib/module/figma/ListItem.SectionHeader.figma.js +20 -5
  213. package/lib/module/figma/ListItem.SectionHeader.figma.js.map +1 -1
  214. package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -1
  215. package/lib/typescript/components/DateTimeList/styles.d.ts +1 -4
  216. package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -1
  217. package/lib/typescript/components/ListItem/index.d.ts +5 -4
  218. package/lib/typescript/components/ListItem/index.d.ts.map +1 -1
  219. package/lib/typescript/components/ListItem/styles.d.ts +1 -1
  220. package/lib/typescript/components/ListItem/styles.d.ts.map +1 -1
  221. package/lib/typescript/components/Menu/index.d.ts.map +1 -1
  222. package/lib/typescript/components/ScrollShadow/gradient.d.ts +7 -0
  223. package/lib/typescript/components/ScrollShadow/gradient.d.ts.map +1 -0
  224. package/lib/typescript/components/ScrollShadow/index.d.ts +57 -15
  225. package/lib/typescript/components/ScrollShadow/index.d.ts.map +1 -1
  226. package/lib/typescript/components/ScrollShadow/styles.d.ts +8 -2
  227. package/lib/typescript/components/ScrollShadow/styles.d.ts.map +1 -1
  228. package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts +13 -0
  229. package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts.map +1 -0
  230. package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts +15 -2
  231. package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
  232. package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
  233. package/lib/typescript/components/Tabs/styles.d.ts +0 -7
  234. package/lib/typescript/components/Tabs/styles.d.ts.map +1 -1
  235. package/lib/typescript/figma/ListItem.SectionHeader.figma.d.ts.map +1 -1
  236. package/package.json +8 -6
  237. package/src/components/DateTimeList/index.tsx +13 -26
  238. package/src/components/DateTimeList/styles.ts +1 -10
  239. package/src/components/ListItem/index.tsx +5 -4
  240. package/src/components/ListItem/styles.ts +1 -0
  241. package/src/components/Menu/index.tsx +11 -8
  242. package/src/components/ScrollShadow/gradient.ts +48 -0
  243. package/src/components/ScrollShadow/index.tsx +300 -69
  244. package/src/components/ScrollShadow/styles.ts +45 -28
  245. package/src/components/ScrollShadow/useComposedScrollHandler.ts +58 -0
  246. package/src/components/ScrollShadow/useScrollShadow.ts +72 -10
  247. package/src/components/Tabs/index.tsx +25 -35
  248. package/src/components/Tabs/styles.ts +0 -9
@@ -0,0 +1,368 @@
1
+ # Avatar (https://design.candescent.com/docs/components/avatar)
2
+
3
+ Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-Forge-DS--Components?node-id=449-377), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/content-avatar--default)
4
+
5
+ A compound component that displays an image, initials, or an icon fallback.
6
+
7
+ ```tsx
8
+ import { Avatar } from '@cdx-ui/components';
9
+ ```
10
+
11
+ ## Basic
12
+
13
+ Include `Avatar.Text` alongside `Avatar.Image` to provide a fallback while the image loads or if it fails.
14
+
15
+ ```tsx
16
+ import { Avatar } from '@cdx-ui/components';
17
+
18
+ export default function AvatarBasicDemo() {
19
+ return (
20
+ <Avatar size="xl" accessibilityLabel="Alex Morgan">
21
+ <Avatar.Image src="https://www.loremfaces.net/128/id/1.jpg" />
22
+ <Avatar.Text>Alex Morgan</Avatar.Text>
23
+ </Avatar>
24
+ );
25
+ }
26
+ ```
27
+
28
+ ## Variants
29
+
30
+ ```tsx
31
+ import { Avatar, Box, Text, type AvatarProps } from '@cdx-ui/components';
32
+ import { Person } from '@cdx-ui/icons';
33
+
34
+ const shapes = ['circle', 'rounded'] as const satisfies readonly NonNullable<
35
+ AvatarProps['shape']
36
+ >[];
37
+
38
+ export default function AvatarVariantsDemo() {
39
+ return (
40
+ <Box className="gap-4">
41
+ {shapes.map((shape) => (
42
+ <Box key={shape} className="gap-2">
43
+ <Text size="sm" color="secondary">
44
+ {shape}
45
+ </Text>
46
+ <Box className="flex-row items-center gap-4">
47
+ <Avatar variant="subtle" shape={shape} accessibilityLabel={`Subtle ${shape} avatar`}>
48
+ <Avatar.Text>Alex Morgan</Avatar.Text>
49
+ </Avatar>
50
+ <Avatar variant="solid" shape={shape} accessibilityLabel={`Solid ${shape} avatar`}>
51
+ <Avatar.Text>Alex Morgan</Avatar.Text>
52
+ </Avatar>
53
+ <Avatar
54
+ variant="subtle"
55
+ shape={shape}
56
+ accessibilityLabel={`Subtle ${shape} icon avatar`}
57
+ >
58
+ <Avatar.Icon as={Person} />
59
+ </Avatar>
60
+ <Avatar variant="solid" shape={shape} accessibilityLabel={`Solid ${shape} icon avatar`}>
61
+ <Avatar.Icon as={Person} />
62
+ </Avatar>
63
+ </Box>
64
+ </Box>
65
+ ))}
66
+ </Box>
67
+ );
68
+ }
69
+ ```
70
+
71
+ ## Colors
72
+
73
+ ```tsx
74
+ import { Avatar, Box, Text, type AvatarProps } from '@cdx-ui/components';
75
+ import { Person } from '@cdx-ui/icons';
76
+
77
+ const colors = [
78
+ 'brand',
79
+ 'neutral',
80
+ 'danger',
81
+ 'warning',
82
+ 'success',
83
+ 'info',
84
+ ] as const satisfies readonly NonNullable<AvatarProps['color']>[];
85
+
86
+ const variants = ['subtle', 'solid'] as const satisfies readonly NonNullable<
87
+ AvatarProps['variant']
88
+ >[];
89
+
90
+ const shapes = ['circle', 'rounded'] as const satisfies readonly NonNullable<
91
+ AvatarProps['shape']
92
+ >[];
93
+
94
+ export default function AvatarColorsDemo() {
95
+ return (
96
+ <Box className="gap-4">
97
+ {variants.map((variant) => (
98
+ <Box key={variant} className="gap-3">
99
+ <Text size="sm" color="secondary">
100
+ {variant}
101
+ </Text>
102
+ {shapes.map((shape) => (
103
+ <Box key={shape} className="gap-2">
104
+ <Text size="sm" color="secondary">
105
+ {shape}
106
+ </Text>
107
+ <Box className="flex-row flex-wrap items-center gap-3">
108
+ {colors.map((color) => (
109
+ <Box
110
+ key={`${variant}-${shape}-${color}`}
111
+ className="flex-row items-center gap-1.5"
112
+ >
113
+ <Avatar
114
+ variant={variant}
115
+ color={color}
116
+ shape={shape}
117
+ accessibilityLabel={`${variant} ${shape} ${color} initials`}
118
+ >
119
+ <Avatar.Text>Alex Morgan</Avatar.Text>
120
+ </Avatar>
121
+ <Avatar
122
+ variant={variant}
123
+ color={color}
124
+ shape={shape}
125
+ accessibilityLabel={`${variant} ${shape} ${color} icon`}
126
+ >
127
+ <Avatar.Icon as={Person} />
128
+ </Avatar>
129
+ </Box>
130
+ ))}
131
+ </Box>
132
+ </Box>
133
+ ))}
134
+ </Box>
135
+ ))}
136
+ </Box>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ## Shapes
142
+
143
+ Use `shape` to render a circle or a rounded square. `Avatar.Image` clips to the same geometry.
144
+
145
+ ```tsx
146
+ import { Avatar, Box, Text, type AvatarProps } from '@cdx-ui/components';
147
+ import { Person } from '@cdx-ui/icons';
148
+
149
+ const shapes = ['circle', 'rounded'] as const satisfies readonly NonNullable<
150
+ AvatarProps['shape']
151
+ >[];
152
+
153
+ export default function AvatarShapesDemo() {
154
+ return (
155
+ <Box className="flex-row flex-wrap items-end gap-6">
156
+ {shapes.map((shape) => (
157
+ <Box key={shape} className="items-center gap-2">
158
+ <Box className="flex-row items-center gap-3">
159
+ <Avatar shape={shape} accessibilityLabel={`${shape} initials`}>
160
+ <Avatar.Text>Alex Morgan</Avatar.Text>
161
+ </Avatar>
162
+ <Avatar shape={shape} accessibilityLabel={`${shape} icon`}>
163
+ <Avatar.Icon as={Person} />
164
+ </Avatar>
165
+ <Avatar shape={shape} accessibilityLabel={`${shape} image`}>
166
+ <Avatar.Image src="https://www.loremfaces.net/128/id/1.jpg" />
167
+ <Avatar.Text>Alex Morgan</Avatar.Text>
168
+ </Avatar>
169
+ </Box>
170
+ <Text size="sm" color="secondary">
171
+ {shape}
172
+ </Text>
173
+ </Box>
174
+ ))}
175
+ </Box>
176
+ );
177
+ }
178
+ ```
179
+
180
+ ## Sizes
181
+
182
+ ```tsx
183
+ import { Avatar, Box, Text, type AvatarProps } from '@cdx-ui/components';
184
+
185
+ const sizes = ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'] as const satisfies readonly NonNullable<
186
+ AvatarProps['size']
187
+ >[];
188
+
189
+ const shapes = ['circle', 'rounded'] as const satisfies readonly NonNullable<
190
+ AvatarProps['shape']
191
+ >[];
192
+
193
+ export default function AvatarSizesDemo() {
194
+ return (
195
+ <Box className="gap-4">
196
+ {shapes.map((shape) => (
197
+ <Box key={shape} className="gap-2">
198
+ <Text size="sm" color="secondary">
199
+ {shape}
200
+ </Text>
201
+ <Box className="flex-row flex-wrap items-end gap-4">
202
+ {sizes.map((size) => (
203
+ <Box key={size} className="items-center gap-2">
204
+ <Avatar
205
+ size={size}
206
+ shape={shape}
207
+ accessibilityLabel={`${shape} avatar size ${size}`}
208
+ >
209
+ <Avatar.Text>Alex Morgan</Avatar.Text>
210
+ </Avatar>
211
+ <Text size="sm" color="secondary">
212
+ {size}
213
+ </Text>
214
+ </Box>
215
+ ))}
216
+ </Box>
217
+ </Box>
218
+ ))}
219
+ </Box>
220
+ );
221
+ }
222
+ ```
223
+
224
+ ## Fallbacks
225
+
226
+ `Avatar.Text` derives up to two initials from a name. Use `Avatar.Icon` for a generic fallback.
227
+
228
+ ```tsx
229
+ import { Avatar, Box, Text, type AvatarProps } from '@cdx-ui/components';
230
+ import { Person } from '@cdx-ui/icons';
231
+
232
+ const shapes = ['circle', 'rounded'] as const satisfies readonly NonNullable<
233
+ AvatarProps['shape']
234
+ >[];
235
+
236
+ export default function AvatarFallbacksDemo() {
237
+ return (
238
+ <Box className="gap-4">
239
+ {shapes.map((shape) => (
240
+ <Box key={shape} className="gap-2">
241
+ <Text size="sm" color="secondary">
242
+ {shape}
243
+ </Text>
244
+ <Box className="flex-row items-center gap-4">
245
+ <Avatar size="lg" shape={shape} accessibilityLabel={`${shape} initials fallback`}>
246
+ <Avatar.Text>Alex Morgan</Avatar.Text>
247
+ </Avatar>
248
+ <Avatar size="lg" shape={shape} accessibilityLabel={`${shape} icon fallback`}>
249
+ <Avatar.Icon as={Person} />
250
+ </Avatar>
251
+ </Box>
252
+ </Box>
253
+ ))}
254
+ </Box>
255
+ );
256
+ }
257
+ ```
258
+
259
+ ## With badge
260
+
261
+ Wrap an avatar with `Badge` to display a status indicator or notification count.
262
+
263
+ ```tsx
264
+ import { Avatar, Badge, Box, Text, type AvatarProps } from '@cdx-ui/components';
265
+
266
+ const shapes = ['circle', 'rounded'] as const satisfies readonly NonNullable<
267
+ AvatarProps['shape']
268
+ >[];
269
+
270
+ export default function AvatarStatusDemo() {
271
+ return (
272
+ <Box className="gap-4">
273
+ {shapes.map((shape) => {
274
+ const overlap = shape === 'circle' ? 'circular' : 'rectangular';
275
+
276
+ return (
277
+ <Box key={shape} className="gap-2">
278
+ <Text size="sm" color="secondary">
279
+ {shape}
280
+ </Text>
281
+ <Box className="flex-row items-center gap-6">
282
+ <Badge variant="dot" color="success" placement="bottom-end" overlap={overlap}>
283
+ <Avatar
284
+ size="xl"
285
+ shape={shape}
286
+ accessibilityLabel={`Alex Morgan, online, ${shape}`}
287
+ >
288
+ <Avatar.Image src="https://www.loremfaces.net/128/id/2.jpg" />
289
+ <Avatar.Text>Alex Morgan</Avatar.Text>
290
+ </Avatar>
291
+ </Badge>
292
+ <Badge
293
+ label={3}
294
+ color="danger"
295
+ placement="top-end"
296
+ overlap={overlap}
297
+ accessibilityLabel="3 notifications"
298
+ >
299
+ <Avatar size="xl" shape={shape} accessibilityLabel={`Sofia Rivera, ${shape}`}>
300
+ <Avatar.Image src="https://www.loremfaces.net/128/id/4.jpg" />
301
+ <Avatar.Text>Sofia Rivera</Avatar.Text>
302
+ </Avatar>
303
+ </Badge>
304
+ </Box>
305
+ </Box>
306
+ );
307
+ })}
308
+ </Box>
309
+ );
310
+ }
311
+ ```
312
+
313
+ ## API
314
+
315
+ ### Avatar
316
+
317
+ | Prop | Type | Default | Description |
318
+ | --- | --- | --- | --- |
319
+ | `className?` | `string` | — | — |
320
+ | `children?` | `ReactNode` | — | — |
321
+ | `size?` | `'2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| null` | — | — |
322
+ | `variant?` | `'subtle' \| 'solid'` | `'subtle'` | Visual style variant. |
323
+ | `color?` | `'neutral' \| 'brand' \| 'danger' \| 'warning' \| 'success' \| 'info'` | `'brand'` | Color theme applied to the avatar surface and fallback content. |
324
+ | `shape?` | `'circle' \| 'rounded'` | `'circle'` | Geometry of the avatar root and loaded image. |
325
+
326
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props). Defaults to an image accessibility role; provide an `accessibilityLabel` that identifies the person or entity.
327
+
328
+ ## Sub-components
329
+
330
+ ### Avatar.Image
331
+
332
+ Displays an image when it loads successfully. If the image is unavailable or fails to load, the fallback content remains visible.
333
+
334
+ | Prop | Type | Default | Description |
335
+ | --- | --- | --- | --- |
336
+ | `className?` | `string` | — | — |
337
+ | `src?` | `string` | — | A string representing the resource identifier for the image. Similar to src from HTML. See https://reactnative.dev/docs/image#src |
338
+ | `source?` | `ImageSourcePropType` | — | — |
339
+ | `asChild?` | `boolean` | — | — |
340
+
341
+ Inherits all [`ImageProps`](https://reactnative.dev/docs/image#props). Pass either a URI string to `src` or an `ImageSourcePropType` to `source`.
342
+
343
+ ### Avatar.Text
344
+
345
+ Text fallback shown until an image loads successfully or when no image is available. A one- or two-character string is uppercased as-is; longer names become the first letter of each word, up to two characters.
346
+
347
+ | Prop | Type | Default | Description |
348
+ | --- | --- | --- | --- |
349
+ | `className?` | `string` | — | — |
350
+ | `children?` | `ReactNode` | — | Name or initials. One or two characters are uppercased as-is. Longer text uses the first letter of each word, up to two characters. |
351
+ | `asChild?` | `boolean` | — | — |
352
+
353
+ Inherits all [`TextProps`](https://reactnative.dev/docs/text#props).
354
+
355
+ ### Avatar.Icon
356
+
357
+ Icon fallback shown until an image loads successfully or when no image is available.
358
+
359
+ | Prop | Type | Default | Description |
360
+ | --- | --- | --- | --- |
361
+ | `className?` | `string` | — | Utility classes for size (`size-*`) and placement, merged after the defaults. |
362
+ | `filled?` | `boolean` | — | When `true`, renders the filled variant of the icon (if available). Defaults to `false` (outlined). |
363
+ | `size?` | `string \| number` | — | Width and height of the icon, in pixels or any SVG length. The bare icon renders at 24 when omitted. |
364
+ | `data-testid?` | `string` | — | Test identifier forwarded to the rendered SVG. |
365
+ | `as` | `ForgeIcon` | — | The `@cdx-ui/icons` component to render. |
366
+ | `asChild?` | `boolean` | — | — |
367
+
368
+ Inherits all `ForgeIconProps` (react-native-svg `SvgProps` plus `filled` and `size`).
@@ -0,0 +1,202 @@
1
+ # Avatar — Design (https://design.candescent.com/docs/components/avatar)
2
+
3
+ ## Usage
4
+
5
+ **Common alternative names**: Profile photo
6
+
7
+ ---
8
+
9
+ ## Anatomy
10
+
11
+ An avatar is a shaped container with content inside – an image, letters, or an icon.
12
+
13
+ **Anatomy\_avatar**
14
+
15
+ 1. **Container**: The avatar’s container can be a circle or a square with rounded corners.
16
+ 2. **Image**: The user’s profile picture or other image. When an image is provided, it fills the container.
17
+ 3. **Background fill**: When an image is not provided, the avatar should have a solid background color.
18
+ 4. **Text**: Text can be provided instead of an image, or as a fallback for when no image is available for the user. Commonly the user’s initials.
19
+ 5. **Icon**: An icon can be provided instead of an image. Useful for categorizing or emphasizing an icon.
20
+
21
+ ### Variant
22
+
23
+ The **variant** property controls the shape of the avatar’s container. The avatar comes in 2 variants: **Circular**, and **Rounded**.
24
+
25
+ - **Circular**
26
+
27
+ The avatar’s container is a perfect circle. This is our recommended variant for most use cases.
28
+ - **Rounded**
29
+
30
+ The avatar’s container is a square with rounded corners.
31
+
32
+ ### Type
33
+
34
+ An avatar supports 3 types of content: an **Image**, **Text**, or an **Icon**. The **Type** property does not exist in code, but is included in Figma as a shortcut for swapping out the content types.
35
+
36
+ - **Type: Image**
37
+
38
+ The user’s profile picture or other image. When an image is provided, it fills the container.
39
+ - **Type: Text**
40
+
41
+ Text content centered inside the container, typically one or two characters. Must have a solid background color.
42
+ - **Type: Icon**
43
+
44
+ A single icon centered inside the container. Must have a solid background color.
45
+
46
+ ### **Size**
47
+
48
+ Avatars are available in 7 sizes: 2XS, XS, Small, Medium, Large, XL, and 2XL. Size should be considered for visual balance and layout needs; larger avatars will draw more attention while smaller sizes support denser views. The default avatar size is Medium (32 × 32 px).
49
+
50
+ - **Size: 2xs**
51
+
52
+ 2XS avatars are 12 × 12 px. This size is typically used in compact components such as chips.
53
+ - **Size: Xs**
54
+
55
+ XS avatars are 18 × 18 px. This size is commonly used in components like chips and other compact patterns.
56
+ - **Size: Small**
57
+
58
+ Small avatars are 24 × 24 px. This size works well in dense layouts where a slightly larger presence than XS is needed without drawing too much attention.
59
+ - **Size: Medium**
60
+
61
+ Medium avatars are 32 × 32 px. This is the default size and works well for most layouts.
62
+ - **Size: Large**
63
+
64
+ Large avatars are 40 × 40 px. This size increases visibility and draws more attention.
65
+ - **Size: Xlarge**
66
+
67
+ XL avatars are 48 × 48 px. This size is useful in layouts where the avatar plays a more prominent role.
68
+ - **Size: 2xl**
69
+
70
+ 2XL avatars are 56 × 56 px. This size is used in high-emphasis contexts such as profile headers.
71
+
72
+ ### Color
73
+
74
+ When an image is not provided, a solid background color is required to display the fallback content (text or icon) on top of. By default, the avatar will use a light background with dark text. However, any colors can be utilized as long as the content meets a **≥ 4.5:1** color contrast ratio with the background.
75
+
76
+ - **Default**
77
+
78
+ Light background (`color.surface.tertiary`) with dark content (`color.content.primary`).
79
+
80
+ #### **Preferred color combinations**
81
+
82
+ Below are our preferred color combinations for avatars.
83
+
84
+ - **Strong**
85
+
86
+ Strong background color with contrasting content.
87
+
88
+ Example: `color.content.danger-on-strong` on `color.surface.danger.strong`
89
+ - **Subtle**
90
+
91
+ Subtle background color with contrasting content.
92
+
93
+ Example: `color.content.danger-on-subtle` on `color.surface.danger.subtle`
94
+
95
+ **⭐ Tip:** Each of these suggestions will work with the following palettes: `neutral`, `action`, `danger`, `warning`, `success`, and `info`.
96
+
97
+ ---
98
+
99
+ Usage
100
+
101
+ ### When to use
102
+
103
+ > [!TIP]
104
+ >
105
+ > **Represent the active user or business**
106
+ >
107
+ > - ex: In the top bar of an app, an avatar can indicate what account is currently logged in to the app
108
+ > - ex: In an organization selector, an avatar can indicate which organization is selected
109
+
110
+ > [!TIP]
111
+ >
112
+ > **Anchor content to a specific user, account, business, or entity**
113
+ >
114
+ > - ex: In a social media app, an avatar helps identify the user who posted the content
115
+ > - ex: In a chat or messaging setting, an avatar helps identify who is speaking in the conversation
116
+
117
+ > [!TIP]
118
+ >
119
+ > **Associate an item with a category, classification, or status**
120
+ >
121
+ > - ex: In a banking app, avatars can be used to identify the merchant associated with each transaction
122
+ > - ex: In a budgeting app, icon avatars can be used to show what category each transaction belongs to
123
+
124
+ ### When not to use
125
+
126
+ > [!CAUTION]
127
+ >
128
+ > **Decorations or illustrations**
129
+ >
130
+ > - ex: Wrapping a decorative icon inside an avatar just to add extra visual emphasis
131
+
132
+ ### Examples
133
+
134
+ #### **Account entry points**
135
+
136
+ Avatars can serve as entry points to an account menus, account pages, or user profiles.
137
+
138
+ _usage\_examples\_account\_01-ex_
139
+
140
+ #### **Conversations**
141
+
142
+ In realtime conversations such as a chat, phone call, or video chat, an avatar helps identify the user or business who is currently speaking.
143
+
144
+ _usage\_examples\_conversations\_01-ex_
145
+
146
+ In asynchronous conversations such as an email or forum post, an avatar helps identify the sender or author of the message.
147
+
148
+ _usage\_examples\_conversations\_02-ex_
149
+
150
+ #### **Lists and tables**
151
+
152
+ Avatars are also commonly found in lists and tables. They can help distinguish between users, businesses, or categories.
153
+
154
+ _usage\_examples\_lists\_01-ex_
155
+
156
+ ### **Choosing colors**
157
+
158
+ #### **Use a consistent color combo**
159
+
160
+ Choose a color palette for your avatars and use it consistently across your experience. We recommend choosing one of our [preferred color combinations](https://design.candescent.com/docs/components/avatar/content.md). If using multiple colors, keep them within the same palette, such as all strong or all subtle options. Mixing palettes may create visual inconsistency or make some avatars feel more prominent than others.
161
+
162
+ - **Do:** Use the same color combination throughout your app, and especially within the same section.
163
+ - **Don't:** Don’t mix color combinations within the same section. In this example, the email from Malachi ends up looking more important than the others.
164
+
165
+ ---
166
+
167
+ ## **Behavior**
168
+
169
+ ### **Fallback rendering**
170
+
171
+ When using image avatars, there may be instances where an image is not available for every avatar. This could be because a user has not uploaded a profile picture, or because there was an error retrieving the image from the server. As a fallback, **text** or an **icon** should be provided.
172
+
173
+ - **Text fallback**
174
+
175
+ `<Avatar.Text>John Smith</Avatar.Text>`
176
+ - **Icon fallback**
177
+
178
+ `<Avatar.Icon as={Person} />`
179
+ - **No fallback specified**
180
+
181
+ When no fallback is specified, the avatar will be empty. Avoid this scenario.
182
+
183
+ A [study from Yale University](https://cyberpsychology.eu/article/view/6281) found that users are more likely to interpret the typical “person” icon as a man than a woman. As such, we recommend always defining fallback text instead of using an icon when representing people.
184
+
185
+ ### Text rendering
186
+
187
+ Avatar text will show **initials** that are derived from the string of text. For example:
188
+
189
+ - "John Smith" ➡️ **JS**
190
+ - "John" ➡️ **J**
191
+ - "John Smith Jr." ➡️ **JS**
192
+ - "John Michael Smith" ➡️ **JM**
193
+
194
+ ## Content
195
+
196
+ ## **Initials**
197
+
198
+ When an image is not available for the user, use a text avatar. The text should either be the beginning letter of their first name, or the beginning letter of their first and last name. For example, “John Smith” would either be “J” or “JS”.
199
+
200
+ - **Do:** Use a single initial or double initials. Be consistent, unless the user only has a first name.
201
+ - **Don't:** Don’t include a third letter, even if the user has a middle name.
202
+ - **Don't:** Don’t spell out names inside the avatar, even if some fit within the space.