@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,170 @@
1
+ # Quick Action Button — Design (https://design.candescent.com/docs/components/quick-action-button)
2
+
3
+ ## Usage
4
+
5
+ **Common alternative names**: Tile, Shortcut, Quick link, Navigation tile
6
+
7
+ ---
8
+
9
+ ## Anatomy
10
+
11
+ Quick action button is a vertical stack inside a single interactive container. The whole tile is one tap target—not separate targets for icon and label.
12
+
13
+ **Anatomy\_quick-action-button**
14
+
15
+ 1. **Stroke:** The outline that surrounds the icon. Used to provide visual emphasis and define the icon's shape.
16
+ 2. **Icon:** A single icon centered in the upper area of the container. Conveys the action at a glance. One icon per Quick action button.
17
+ 3. **Label:** Short text centered below the icon.
18
+
19
+ ---
20
+
21
+ Usage
22
+
23
+ ### When to use
24
+
25
+ **✅ Provide quick access to common tasks**
26
+
27
+ - ex: Pay, Transfer, Deposit, Statements on an account home
28
+ - ex: Send, Request, Scan on a payments hub
29
+
30
+ > [!TIP]
31
+ >
32
+ > **Actions users recognize by icon but still need a short name**
33
+ >
34
+ > - ex: Mobile banking where icons speed scanning but labels remove ambiguity (**Zelle** vs generic send icon)
35
+
36
+ > [!TIP]
37
+ >
38
+ > **Display a small group of related actions**
39
+ >
40
+ > - ex: Use quick actions to present a small set of related actions together. When displaying multiple quick actions, use the Quick action bar to create a consistent and easy-to-scan layout.
41
+
42
+ > [!TIP]
43
+ >
44
+ > **Entry points to flows and destinations**
45
+ >
46
+ > - ex: Open account, Order checks, Find ATM as optional next steps below main content
47
+
48
+ ### When not to use
49
+
50
+ > [!CAUTION]
51
+ >
52
+ > **One primary call to action for the screen**
53
+ >
54
+ > - ex: Continue, Submit application, Sign in
55
+
56
+ > [!CAUTION]
57
+ >
58
+ > **Icon-only control with no visible label**
59
+ >
60
+ > - ex: Use an [Icon Button](https://design.candescent.com/docs/components/icon-button/content.md) when a visible text label is not needed.
61
+
62
+ > [!CAUTION]
63
+ >
64
+ > **Primary or persistent navigation**
65
+ >
66
+ > - ex: Use dedicated Navigation components for moving between major sections of an application.
67
+
68
+ > [!CAUTION]
69
+ >
70
+ > **Selecting between options**
71
+ >
72
+ > - ex: Use a Radio group, Segmented control, or other selection component when users need to choose and maintain a selected state.
73
+
74
+ > [!CAUTION]
75
+ >
76
+ > **Actions that require lengthy labels or supporting content**
77
+ >
78
+ > - ex: Use a List row, or Card when additional text, descriptions, or supporting information is needed.
79
+
80
+ ### Quick action button vs Button and Icon button
81
+
82
+ Quick action buttons share space as equals; Buttons express hierarchy (primary vs secondary). Icon buttons save space when the label is elsewhere or obvious.
83
+
84
+ | Need | Use |
85
+ | ----------------------------------------------------- | ----------------------- |
86
+ | 3–8 peer shortcuts with icon + short label | **Quick action button** |
87
+ | Primary or secondary CTA, form footer, dialog actions | **Button** |
88
+ | Single icon, label in tooltip or adjacent heading | **Icon button** |
89
+
90
+ ### Layout patterns
91
+
92
+ Quick action buttons are most effective when displayed as a group of related actions. Use a maximum of four quick actions per row. When more than four actions are needed, wrap the remaining items to a new row while maintaining consistent sizing, spacing, and alignment.
93
+
94
+ #### Horizontal row
95
+
96
+ Use a single row when up to four quick actions can fit comfortably within the available space. When displaying multiple quick actions, use the **Quick Action Bar** to maintain consistent sizing, spacing, and alignment across the group. For groups with fewer than four quick actions, center the actions within the row.
97
+
98
+ **Usage\_layout\_01-ex\_**
99
+
100
+ ### Icon and label
101
+
102
+ Every quick action button requires both an icon and a label. Icons help users identify actions quickly, while labels provide clarity and reduce ambiguity. Together, they create a recognizable and easy-to-scan experience.
103
+
104
+ - **Do:** Pair each icon with a short, descriptive label that clearly communicates the action.
105
+ - **Don't:** Don't rely on icons alone. If a visible label is not needed, use an Icon button instead.
106
+
107
+ ### Action count and prioritization
108
+
109
+ Quick action buttons should highlight the most important and frequently used tasks. Avoid displaying too many actions at once, as this can make it harder for users to find the action they need.
110
+
111
+ - **Do:** Prioritize the most frequently used or valuable actions and display them first within the group.
112
+ - **Don't:** Don't display more than four quick actions in a single row. When additional actions are needed, move them to a new row or a secondary destination.
113
+
114
+ ---
115
+
116
+ ## Behavior
117
+
118
+ ### States
119
+
120
+ - **Resting (default)**
121
+
122
+ Default state. User is not interacting with the button.
123
+ - **isHovered: true**
124
+
125
+ When the user’s cursor is hovering over the button.
126
+ - **isFocused: true**
127
+
128
+ Visible focus ring on the **container** (keyboard and assistive tech).
129
+
130
+ ### Disabled
131
+
132
+ Quick action buttons can be disabled, which prevents users from selecting or interacting with the action.
133
+
134
+ Using disabled quick action buttons can create accessibility and usability challenges because users may not understand why an action is unavailable. Keep quick action buttons enabled whenever possible and provide clear guidance or validation to help users complete the required task. Use disabled quick action buttons only when an action is temporarily unavailable and no alternative approach can be provided.
135
+
136
+ - **isDisabled: true**
137
+
138
+ The user cannot interact with the button in this state.
139
+
140
+ ## Content
141
+
142
+ ## Labels
143
+
144
+ Labels identify the action associated with a quick action button. Keep labels concise, descriptive, and easy to scan.
145
+
146
+ - Prefer one to two words.
147
+ - Use action-oriented language whenever possible.
148
+ - Describe the outcome of the action, not the component or destination.
149
+ - Use consistent grammar across a group of quick actions.
150
+
151
+ ### Capitalization
152
+
153
+ Use sentence case for all labels and maintain consistency across the experience.
154
+
155
+ - **Do:** Use sentence casing.
156
+ - **Don't:** Don't use all caps or title casing.
157
+
158
+ ### Text truncation
159
+
160
+ Quick action labels should be concise and easy to scan. Labels wrap to a second line when needed. When the label exceeds two lines, the text is truncated with an ellipsis to preserve a consistent layout.
161
+
162
+ - **Do:** Allow labels to wrap to a second line before truncating.
163
+ - **Caution:** Avoid labels exceeding two lines or overflow the available space.
164
+
165
+ ### Label length
166
+
167
+ Quick action labels should be concise and easy to scan. Use the shortest label that clearly communicates the action while maintaining consistency across the group.
168
+
169
+ - **Do:** Use short, descriptive labels that quickly communicate the action.
170
+ - **Don't:** Don't use long or overly descriptive labels that reduce scannability.
@@ -0,0 +1,224 @@
1
+ # Radio (https://design.candescent.com/docs/components/radio)
2
+
3
+ Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-Forge-DS--React-Native-Components?node-id=2603-62), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/inputs-radio--default)
4
+
5
+ A compound component with sub-components for the indicator, label, and grouping. A `Radio` must always be rendered inside a `Radio.Group`.
6
+
7
+ ```tsx
8
+ import { Radio } from '@cdx-ui/components';
9
+ ```
10
+
11
+ ## Basic
12
+
13
+ ```tsx
14
+ import { useState } from 'react';
15
+ import { Radio } from '@cdx-ui/components';
16
+
17
+ export default function RadioBasicDemo() {
18
+ const [accountType, setAccountType] = useState('checking');
19
+
20
+ return (
21
+ <Radio.Group value={accountType} onChange={setAccountType} aria-label="Account type">
22
+ <Radio value="checking">
23
+ <Radio.Label>Checking</Radio.Label>
24
+ </Radio>
25
+ <Radio value="savings">
26
+ <Radio.Label>Savings</Radio.Label>
27
+ </Radio>
28
+ <Radio value="money-market">
29
+ <Radio.Label>Money Market</Radio.Label>
30
+ </Radio>
31
+ </Radio.Group>
32
+ );
33
+ }
34
+ ```
35
+
36
+ ## Horizontal
37
+
38
+ ```tsx
39
+ import { Radio } from '@cdx-ui/components';
40
+
41
+ export default function RadioHorizontalDemo() {
42
+ return (
43
+ <Radio.Group defaultValue="monthly" direction="row" aria-label="Billing cycle">
44
+ <Radio value="monthly">
45
+ <Radio.Label>Monthly</Radio.Label>
46
+ </Radio>
47
+ <Radio value="quarterly">
48
+ <Radio.Label>Quarterly</Radio.Label>
49
+ </Radio>
50
+ <Radio value="annual">
51
+ <Radio.Label>Annual</Radio.Label>
52
+ </Radio>
53
+ </Radio.Group>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ## States
59
+
60
+ The group controls disabled, read-only, and invalid state for every radio.
61
+
62
+ ```tsx
63
+ import { Box, Radio, Text } from '@cdx-ui/components';
64
+
65
+ export default function RadioStatesDemo() {
66
+ return (
67
+ <Box className="w-full gap-4">
68
+ <Box className="gap-2">
69
+ <Text size="sm" color="secondary">
70
+ Disabled
71
+ </Text>
72
+ <Radio.Group defaultValue="email" isDisabled aria-label="Disabled notification preference">
73
+ <Radio value="email">
74
+ <Radio.Label>Email</Radio.Label>
75
+ </Radio>
76
+ <Radio value="sms">
77
+ <Radio.Label>Text message</Radio.Label>
78
+ </Radio>
79
+ </Radio.Group>
80
+ </Box>
81
+ <Box className="gap-2">
82
+ <Text size="sm" color="secondary">
83
+ Read-only
84
+ </Text>
85
+ <Radio.Group defaultValue="email" isReadOnly aria-label="Read-only notification preference">
86
+ <Radio value="email">
87
+ <Radio.Label>Email</Radio.Label>
88
+ </Radio>
89
+ <Radio value="sms">
90
+ <Radio.Label>Text message</Radio.Label>
91
+ </Radio>
92
+ </Radio.Group>
93
+ </Box>
94
+ <Box className="gap-2">
95
+ <Text size="sm" color="secondary">
96
+ Invalid
97
+ </Text>
98
+ <Radio.Group isInvalid aria-label="Invalid payment method">
99
+ <Radio value="card">
100
+ <Radio.Label>Credit / debit card</Radio.Label>
101
+ </Radio>
102
+ <Radio value="ach">
103
+ <Radio.Label>Bank transfer (ACH)</Radio.Label>
104
+ </Radio>
105
+ </Radio.Group>
106
+ </Box>
107
+ </Box>
108
+ );
109
+ }
110
+ ```
111
+
112
+ ## With field
113
+
114
+ ```tsx
115
+ import { useState } from 'react';
116
+ import { Field, Radio } from '@cdx-ui/components';
117
+
118
+ export default function RadioWithFieldDemo() {
119
+ const [value, setValue] = useState('');
120
+
121
+ return (
122
+ <Field isRequired isInvalid={!value}>
123
+ <Field.Label>Payment method</Field.Label>
124
+ <Radio.Group value={value} onChange={setValue}>
125
+ <Radio value="card">
126
+ <Radio.Label>Credit / debit card</Radio.Label>
127
+ </Radio>
128
+ <Radio value="ach">
129
+ <Radio.Label>Bank transfer (ACH)</Radio.Label>
130
+ </Radio>
131
+ <Radio value="wire">
132
+ <Radio.Label>Wire transfer</Radio.Label>
133
+ </Radio>
134
+ </Radio.Group>
135
+ <Field.Error>Please select a payment method.</Field.Error>
136
+ </Field>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ## API
142
+
143
+ ### Radio
144
+
145
+ An individual radio item. Auto-renders its indicator internally — compose only `Radio.Label` (and other children) inside it. Must be rendered inside a `Radio.Group`.
146
+
147
+ | Prop | Type | Default | Description |
148
+ | --- | --- | --- | --- |
149
+ | `className?` | `string` | — | — |
150
+ | `children?` | `ReactNode` | — | Either children or a render prop that receives a boolean reflecting whether the component is currently pressed. |
151
+ | `value` | `string` | — | Required — identifies this item's value within a Radio.Group. |
152
+ | `isDisabled?` | `boolean` | — | Disables this item without disabling the rest of the group. |
153
+ | `isInvalid?` | `boolean` | — | — |
154
+ | `isReadOnly?` | `boolean` | — | Focusable, but the selection cannot be changed. |
155
+ | `isHovered?` | `boolean` | — | — |
156
+ | `isFocused?` | `boolean` | — | — |
157
+ | `isPressed?` | `boolean` | — | — |
158
+ | `isFocusVisible?` | `boolean` | — | — |
159
+
160
+ Inherits all [`PressableProps`](https://reactnative.dev/docs/pressable#props).
161
+
162
+ ## Sub-components
163
+
164
+ ### Radio.Label
165
+
166
+ Text label rendered alongside the radio indicator. Automatically receives disabled and checked state from context.
167
+
168
+ | Prop | Type | Default | Description |
169
+ | --- | --- | --- | --- |
170
+ | `className?` | `string` | — | — |
171
+ | `children?` | `ReactNode` | — | — |
172
+ | `asChild?` | `boolean` | — | — |
173
+
174
+ Inherits all [`TextProps`](https://reactnative.dev/docs/text#props).
175
+
176
+ ### Radio.Indicator
177
+
178
+ The visual circle that displays the checked/unchecked state — an outer ring with an inner filled dot when selected. Auto-rendered by the root; exposed for deep customization but not composed in standard usage.
179
+
180
+ | Prop | Type | Default | Description |
181
+ | --- | --- | --- | --- |
182
+ | `className?` | `string` | — | — |
183
+ | `children?` | `ReactNode` | — | — |
184
+ | `asChild?` | `boolean` | — | — |
185
+
186
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
187
+
188
+ ### Radio.Group
189
+
190
+ Manages single-selection state for a set of radio items with consistent spacing. Enforces single-select — there is no `type` or `max` prop.
191
+
192
+ | Prop | Type | Default | Description |
193
+ | --- | --- | --- | --- |
194
+ | `className?` | `string` | — | — |
195
+ | `children?` | `ReactNode` | — | — |
196
+ | `value?` | `string` | — | — |
197
+ | `defaultValue?` | `string` | — | — |
198
+ | `onChange?` | `((value: string) => void)` | — | — |
199
+ | `isDisabled?` | `boolean` | — | — |
200
+ | `isInvalid?` | `boolean` | — | — |
201
+ | `isRequired?` | `boolean` | — | — |
202
+ | `isReadOnly?` | `boolean` | — | Makes every radio in the group read-only. Items stay focusable, but the selection cannot be changed. |
203
+ | `direction?` | `'column' \| 'row'` | — | — |
204
+ | `name?` | `string` | — | — |
205
+
206
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
207
+
208
+ | Prop | Type | Default | Description |
209
+ | -------------- | ------------------------- | ---------- | ----------------------------------------------- |
210
+ | `value` | `string` | — | Currently selected radio value (controlled) |
211
+ | `defaultValue` | `string` | — | Initially selected value (uncontrolled) |
212
+ | `onChange` | `(value: string) => void` | — | Called when the selection changes |
213
+ | `isDisabled` | `boolean` | `false` | Disables all radios in the group |
214
+ | `isInvalid` | `boolean` | `false` | Marks all radios as invalid |
215
+ | `isRequired` | `boolean` | `false` | Marks the group as required for form validation |
216
+ | `isReadOnly` | `boolean` | `false` | Makes all radios read-only |
217
+ | `direction` | `'column' \| 'row'` | `'column'` | Layout direction of the group |
218
+ | `name` | `string` | — | Form field name for web form integration |
219
+
220
+ ## Accessibility
221
+
222
+ The group exposes `radiogroup` and each item exposes `radio`. The selected item has `aria-checked` set to `true`; the others are `false`. `isDisabled` marks the affected items disabled (`aria-disabled` on web), whether it is set on the group or on a single item.
223
+
224
+ On web, Tab moves focus into the group. Arrow keys change the selection, and Space selects the focused item. The focus ring is drawn on the indicator. The group name — from `aria-label`, `aria-labelledby`, or a `Field.Label` — is announced when focus enters. Each item announces its label, checked state, and position in the set.
@@ -0,0 +1,123 @@
1
+ # Range Calendar (https://design.candescent.com/docs/components/range-calendar)
2
+
3
+ Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-Forge-DS--Components?node-id=12118-58084), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/date-time-rangecalendar--default)
4
+
5
+ `RangeCalendar` renders a day grid for selecting a start and end date. The start and end values are `DateId` strings in `YYYY-MM-DD` format.
6
+
7
+ ```tsx
8
+ import { RangeCalendar } from '@cdx-ui/components';
9
+ ```
10
+
11
+ ## Basic
12
+
13
+ Control the range with `startValue`, `endValue`, and `onRangeChange`. Tap once to set the start and again to set the end; taps in reverse order are normalized automatically.
14
+
15
+ ```tsx
16
+ import { useState } from 'react';
17
+ import { RangeCalendar } from '@cdx-ui/components';
18
+ import { dateId, type DateId } from '@cdx-ui/formatters';
19
+
20
+ export default function RangeCalendarBasicDemo() {
21
+ const [start, setStart] = useState<DateId | undefined>(dateId('2026-07-15'));
22
+ const [end, setEnd] = useState<DateId | undefined>(dateId('2026-07-20'));
23
+
24
+ return (
25
+ <RangeCalendar
26
+ startValue={start}
27
+ endValue={end}
28
+ onRangeChange={({ startId, endId }) => {
29
+ setStart(startId);
30
+ setEnd(endId);
31
+ }}
32
+ aria-label="Trip dates"
33
+ className="w-full max-w-sm"
34
+ />
35
+ );
36
+ }
37
+ ```
38
+
39
+ ## Date limits
40
+
41
+ Set `minValue` and `maxValue` to restrict which days can be selected.
42
+
43
+ ```tsx
44
+ import { useState } from 'react';
45
+ import { RangeCalendar } from '@cdx-ui/components';
46
+ import { dateId, monthId, type DateId } from '@cdx-ui/formatters';
47
+
48
+ export default function RangeCalendarMinMaxDemo() {
49
+ const [start, setStart] = useState<DateId | undefined>(dateId('2026-08-12'));
50
+ const [end, setEnd] = useState<DateId | undefined>(dateId('2026-08-18'));
51
+
52
+ return (
53
+ <RangeCalendar
54
+ startValue={start}
55
+ endValue={end}
56
+ onRangeChange={({ startId, endId }) => {
57
+ setStart(startId);
58
+ setEnd(endId);
59
+ }}
60
+ defaultMonthId={monthId('2026-08-01')}
61
+ minValue={dateId('2026-08-10')}
62
+ maxValue={dateId('2026-08-20')}
63
+ aria-label="Appointment dates"
64
+ className="w-full max-w-sm"
65
+ />
66
+ );
67
+ }
68
+ ```
69
+
70
+ ## Disabled
71
+
72
+ Set `disabled` to render a read-only grid that ignores day presses.
73
+
74
+ ```tsx
75
+ import { RangeCalendar } from '@cdx-ui/components';
76
+ import { dateId } from '@cdx-ui/formatters';
77
+
78
+ export default function RangeCalendarDisabledDemo() {
79
+ return (
80
+ <RangeCalendar
81
+ startValue={dateId('2026-07-15')}
82
+ endValue={dateId('2026-07-20')}
83
+ disabled
84
+ aria-label="Trip dates"
85
+ className="w-full max-w-sm"
86
+ />
87
+ );
88
+ }
89
+ ```
90
+
91
+ ## API
92
+
93
+ ### RangeCalendar
94
+
95
+ By default, `RangeCalendar` renders a month header with previous/next navigation and a year drill-down, followed by the day grid. Selecting a day while a range is empty or complete starts a new range; the second tap completes it, and an inverted selection is normalized so the earlier day becomes the start. `locale` defaults to `en-US` and controls weekday and month formatting.
96
+
97
+ | Prop | Type | Default | Description |
98
+ | --- | --- | --- | --- |
99
+ | `className?` | `string` | — | Additional Uniwind/Tailwind classes, merged after the calendar's own styles. |
100
+ | `children?` | `ReactNode` | — | Custom calendar body. Omit to render the default header and month grid. |
101
+ | `asChild?` | `boolean` | — | Render the consumer's child element in place of the default `View` host. |
102
+ | `startValue?` | `DateId` | — | Controlled range start. Setting `startValue` or `endValue` makes the range controlled. |
103
+ | `endValue?` | `DateId` | — | Controlled range end. Setting `startValue` or `endValue` makes the range controlled. |
104
+ | `defaultStartValue?` | `DateId` | — | Initial range start when uncontrolled. |
105
+ | `defaultEndValue?` | `DateId` | — | Initial range end when uncontrolled. |
106
+ | `onRangeChange?` | `((range: { startId?: DateId; endId?: DateId; }) => void)` | — | Called when the user picks a day. The first pick starts a new range with no `endId`; the second completes it, with the two days in date order. |
107
+ | `monthId?` | `MonthId` | — | Controlled visible month. When set, `defaultMonthId` has no effect. |
108
+ | `defaultMonthId?` | `MonthId` | — | Initial visible month when uncontrolled. Defaults to the month of the range, or today. |
109
+ | `onMonthIdChange?` | `((monthId: MonthId) => void)` | — | Called with the new visible month when the user navigates months. |
110
+ | `focusedField?` | `'start' \| 'end'` | — | Controlled active field. The calendar moves it to `'end'` after the first day pick and back to `'start'` after the second. |
111
+ | `defaultFocusedField?` | `'start' \| 'end'` | `'start'` | Initial active field when uncontrolled. |
112
+ | `onFocusedFieldChange?` | `((field: RangeCalendarFocus) => void)` | — | Called with the new active field after each day pick. |
113
+ | `minValue?` | `DateId` | — | Earliest selectable date. Build with `dateId(...)` from `@cdx-ui/formatters`. |
114
+ | `maxValue?` | `DateId` | — | Latest selectable date. Build with `dateId(...)` from `@cdx-ui/formatters`. |
115
+ | `disabled?` | `boolean` | `false` | Prevents day selection and month navigation. |
116
+ | `locale?` | `string` | `'en-US'` | BCP 47 locale for month and weekday names. |
117
+ | `labels?` | `Partial<DateComponentLabels>` | — | Overrides for the built-in UI copy, such as the previous- and next-month button labels. |
118
+
119
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
120
+
121
+ ## Accessibility
122
+
123
+ Pass `accessibilityLabel` to name the calendar for assistive technology; the root carries no landmark role of its own. Days outside the `minValue`–`maxValue` range, and every day while `disabled`, are not selectable.