@stack-spot/citric-react 0.22.0 → 0.24.0

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 (258) hide show
  1. package/dist/citric.css +17 -4
  2. package/dist/components/Accordion.d.ts +34 -0
  3. package/dist/components/Accordion.d.ts.map +1 -1
  4. package/dist/components/Accordion.js +34 -0
  5. package/dist/components/Accordion.js.map +1 -1
  6. package/dist/components/Alert.d.ts +8 -0
  7. package/dist/components/Alert.d.ts.map +1 -1
  8. package/dist/components/Alert.js +8 -0
  9. package/dist/components/Alert.js.map +1 -1
  10. package/dist/components/AsyncContent.d.ts +18 -4
  11. package/dist/components/AsyncContent.d.ts.map +1 -1
  12. package/dist/components/AsyncContent.js +18 -4
  13. package/dist/components/AsyncContent.js.map +1 -1
  14. package/dist/components/Avatar.d.ts +9 -0
  15. package/dist/components/Avatar.d.ts.map +1 -1
  16. package/dist/components/Avatar.js +11 -1
  17. package/dist/components/Avatar.js.map +1 -1
  18. package/dist/components/AvatarGroup.d.ts +8 -0
  19. package/dist/components/AvatarGroup.d.ts.map +1 -1
  20. package/dist/components/AvatarGroup.js +8 -0
  21. package/dist/components/AvatarGroup.js.map +1 -1
  22. package/dist/components/Badge.d.ts +13 -2
  23. package/dist/components/Badge.d.ts.map +1 -1
  24. package/dist/components/Badge.js +14 -3
  25. package/dist/components/Badge.js.map +1 -1
  26. package/dist/components/Blockquote.d.ts +8 -0
  27. package/dist/components/Blockquote.d.ts.map +1 -1
  28. package/dist/components/Blockquote.js +8 -0
  29. package/dist/components/Blockquote.js.map +1 -1
  30. package/dist/components/Breadcrumb.d.ts +8 -0
  31. package/dist/components/Breadcrumb.d.ts.map +1 -1
  32. package/dist/components/Breadcrumb.js +10 -1
  33. package/dist/components/Breadcrumb.js.map +1 -1
  34. package/dist/components/Button.d.ts +11 -0
  35. package/dist/components/Button.d.ts.map +1 -1
  36. package/dist/components/Button.js +14 -2
  37. package/dist/components/Button.js.map +1 -1
  38. package/dist/components/Card.d.ts +15 -4
  39. package/dist/components/Card.d.ts.map +1 -1
  40. package/dist/components/Card.js +13 -1
  41. package/dist/components/Card.js.map +1 -1
  42. package/dist/components/Checkbox.d.ts +14 -0
  43. package/dist/components/Checkbox.d.ts.map +1 -1
  44. package/dist/components/Checkbox.js +14 -0
  45. package/dist/components/Checkbox.js.map +1 -1
  46. package/dist/components/CheckboxGroup.d.ts +22 -3
  47. package/dist/components/CheckboxGroup.d.ts.map +1 -1
  48. package/dist/components/CheckboxGroup.js +23 -3
  49. package/dist/components/CheckboxGroup.js.map +1 -1
  50. package/dist/components/Circle.d.ts +16 -0
  51. package/dist/components/Circle.d.ts.map +1 -1
  52. package/dist/components/Circle.js +8 -0
  53. package/dist/components/Circle.js.map +1 -1
  54. package/dist/components/CitricComponent.d.ts +14 -0
  55. package/dist/components/CitricComponent.d.ts.map +1 -1
  56. package/dist/components/CitricComponent.js +14 -0
  57. package/dist/components/CitricComponent.js.map +1 -1
  58. package/dist/components/Divider.d.ts +4 -1
  59. package/dist/components/Divider.d.ts.map +1 -1
  60. package/dist/components/Divider.js +4 -1
  61. package/dist/components/Divider.js.map +1 -1
  62. package/dist/components/ErrorBoundary.d.ts +13 -0
  63. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  64. package/dist/components/ErrorBoundary.js +13 -0
  65. package/dist/components/ErrorBoundary.js.map +1 -1
  66. package/dist/components/ErrorMessage.js +1 -1
  67. package/dist/components/ErrorMessage.js.map +1 -1
  68. package/dist/components/FallbackBoundary.d.ts +12 -1
  69. package/dist/components/FallbackBoundary.d.ts.map +1 -1
  70. package/dist/components/FallbackBoundary.js +12 -1
  71. package/dist/components/FallbackBoundary.js.map +1 -1
  72. package/dist/components/Favorite.d.ts +12 -0
  73. package/dist/components/Favorite.d.ts.map +1 -1
  74. package/dist/components/Favorite.js +12 -0
  75. package/dist/components/Favorite.js.map +1 -1
  76. package/dist/components/FieldGroup.d.ts +13 -0
  77. package/dist/components/FieldGroup.d.ts.map +1 -1
  78. package/dist/components/FieldGroup.js +13 -0
  79. package/dist/components/FieldGroup.js.map +1 -1
  80. package/dist/components/Form.d.ts +18 -0
  81. package/dist/components/Form.d.ts.map +1 -1
  82. package/dist/components/Form.js +18 -0
  83. package/dist/components/Form.js.map +1 -1
  84. package/dist/components/FormGroup.d.ts +12 -0
  85. package/dist/components/FormGroup.d.ts.map +1 -1
  86. package/dist/components/FormGroup.js +12 -0
  87. package/dist/components/FormGroup.js.map +1 -1
  88. package/dist/components/IconBox.d.ts +33 -8
  89. package/dist/components/IconBox.d.ts.map +1 -1
  90. package/dist/components/IconBox.js +37 -11
  91. package/dist/components/IconBox.js.map +1 -1
  92. package/dist/components/ImageBox.d.ts +32 -8
  93. package/dist/components/ImageBox.d.ts.map +1 -1
  94. package/dist/components/ImageBox.js +36 -11
  95. package/dist/components/ImageBox.js.map +1 -1
  96. package/dist/components/ImageWithFallback.d.ts +18 -0
  97. package/dist/components/ImageWithFallback.d.ts.map +1 -1
  98. package/dist/components/ImageWithFallback.js +11 -0
  99. package/dist/components/ImageWithFallback.js.map +1 -1
  100. package/dist/components/Input.d.ts +15 -3
  101. package/dist/components/Input.d.ts.map +1 -1
  102. package/dist/components/Input.js +16 -3
  103. package/dist/components/Input.js.map +1 -1
  104. package/dist/components/Link.d.ts +6 -0
  105. package/dist/components/Link.d.ts.map +1 -1
  106. package/dist/components/Link.js +6 -0
  107. package/dist/components/Link.js.map +1 -1
  108. package/dist/components/MenuOverlay/index.d.ts +20 -0
  109. package/dist/components/MenuOverlay/index.d.ts.map +1 -1
  110. package/dist/components/MenuOverlay/index.js +20 -0
  111. package/dist/components/MenuOverlay/index.js.map +1 -1
  112. package/dist/components/Overlay/index.d.ts +16 -0
  113. package/dist/components/Overlay/index.d.ts.map +1 -1
  114. package/dist/components/Overlay/index.js +16 -0
  115. package/dist/components/Overlay/index.js.map +1 -1
  116. package/dist/components/Pagination.d.ts +27 -8
  117. package/dist/components/Pagination.d.ts.map +1 -1
  118. package/dist/components/Pagination.js +18 -5
  119. package/dist/components/Pagination.js.map +1 -1
  120. package/dist/components/ProgressBar.d.ts +14 -0
  121. package/dist/components/ProgressBar.d.ts.map +1 -1
  122. package/dist/components/ProgressBar.js +14 -0
  123. package/dist/components/ProgressBar.js.map +1 -1
  124. package/dist/components/ProgressCircular.d.ts +14 -0
  125. package/dist/components/ProgressCircular.d.ts.map +1 -1
  126. package/dist/components/ProgressCircular.js +14 -0
  127. package/dist/components/ProgressCircular.js.map +1 -1
  128. package/dist/components/RadioGroup.d.ts +24 -3
  129. package/dist/components/RadioGroup.d.ts.map +1 -1
  130. package/dist/components/RadioGroup.js +25 -3
  131. package/dist/components/RadioGroup.js.map +1 -1
  132. package/dist/components/Rating.d.ts +10 -0
  133. package/dist/components/Rating.d.ts.map +1 -1
  134. package/dist/components/Rating.js +10 -0
  135. package/dist/components/Rating.js.map +1 -1
  136. package/dist/components/Select/RichSelect.d.ts +3 -5
  137. package/dist/components/Select/RichSelect.d.ts.map +1 -1
  138. package/dist/components/Select/RichSelect.js +4 -4
  139. package/dist/components/Select/RichSelect.js.map +1 -1
  140. package/dist/components/Select/SimpleSelect.d.ts +2 -3
  141. package/dist/components/Select/SimpleSelect.d.ts.map +1 -1
  142. package/dist/components/Select/SimpleSelect.js +2 -3
  143. package/dist/components/Select/SimpleSelect.js.map +1 -1
  144. package/dist/components/Select/index.d.ts +25 -2
  145. package/dist/components/Select/index.d.ts.map +1 -1
  146. package/dist/components/Select/index.js +26 -3
  147. package/dist/components/Select/index.js.map +1 -1
  148. package/dist/components/Select/types.d.ts +1 -2
  149. package/dist/components/Select/types.d.ts.map +1 -1
  150. package/dist/components/SelectBox.d.ts +31 -2
  151. package/dist/components/SelectBox.d.ts.map +1 -1
  152. package/dist/components/SelectBox.js +32 -3
  153. package/dist/components/SelectBox.js.map +1 -1
  154. package/dist/components/Skeleton.d.ts +11 -0
  155. package/dist/components/Skeleton.d.ts.map +1 -1
  156. package/dist/components/Skeleton.js +11 -0
  157. package/dist/components/Skeleton.js.map +1 -1
  158. package/dist/components/Slider.d.ts +12 -0
  159. package/dist/components/Slider.d.ts.map +1 -1
  160. package/dist/components/Slider.js +12 -0
  161. package/dist/components/Slider.js.map +1 -1
  162. package/dist/components/SmartTable.d.ts +36 -2
  163. package/dist/components/SmartTable.d.ts.map +1 -1
  164. package/dist/components/SmartTable.js +37 -3
  165. package/dist/components/SmartTable.js.map +1 -1
  166. package/dist/components/Stepper.d.ts +20 -3
  167. package/dist/components/Stepper.d.ts.map +1 -1
  168. package/dist/components/Stepper.js +21 -3
  169. package/dist/components/Stepper.js.map +1 -1
  170. package/dist/components/Table.d.ts +10 -0
  171. package/dist/components/Table.d.ts.map +1 -1
  172. package/dist/components/Table.js +10 -0
  173. package/dist/components/Table.js.map +1 -1
  174. package/dist/components/Tabs/TabController.d.ts +14 -0
  175. package/dist/components/Tabs/TabController.d.ts.map +1 -1
  176. package/dist/components/Tabs/TabController.js +14 -0
  177. package/dist/components/Tabs/TabController.js.map +1 -1
  178. package/dist/components/Tabs/index.d.ts +20 -3
  179. package/dist/components/Tabs/index.d.ts.map +1 -1
  180. package/dist/components/Tabs/index.js +21 -3
  181. package/dist/components/Tabs/index.js.map +1 -1
  182. package/dist/components/Text.d.ts +16 -2
  183. package/dist/components/Text.d.ts.map +1 -1
  184. package/dist/components/Text.js +17 -3
  185. package/dist/components/Text.js.map +1 -1
  186. package/dist/components/Textarea.d.ts +11 -1
  187. package/dist/components/Textarea.d.ts.map +1 -1
  188. package/dist/components/Textarea.js +12 -2
  189. package/dist/components/Textarea.js.map +1 -1
  190. package/dist/components/Tooltip.d.ts +14 -1
  191. package/dist/components/Tooltip.d.ts.map +1 -1
  192. package/dist/components/Tooltip.js +13 -0
  193. package/dist/components/Tooltip.js.map +1 -1
  194. package/dist/components/layout.d.ts +41 -7
  195. package/dist/components/layout.d.ts.map +1 -1
  196. package/dist/components/layout.js +44 -9
  197. package/dist/components/layout.js.map +1 -1
  198. package/dist/index.d.ts +0 -1
  199. package/dist/index.d.ts.map +1 -1
  200. package/dist/index.js +0 -1
  201. package/dist/index.js.map +1 -1
  202. package/package.json +2 -2
  203. package/src/components/Accordion.tsx +34 -0
  204. package/src/components/Alert.tsx +8 -0
  205. package/src/components/AsyncContent.tsx +18 -4
  206. package/src/components/Avatar.tsx +11 -1
  207. package/src/components/AvatarGroup.tsx +8 -0
  208. package/src/components/Badge.tsx +24 -8
  209. package/src/components/Blockquote.tsx +8 -0
  210. package/src/components/Breadcrumb.tsx +10 -1
  211. package/src/components/Button.tsx +17 -2
  212. package/src/components/Card.tsx +34 -14
  213. package/src/components/Checkbox.tsx +14 -0
  214. package/src/components/CheckboxGroup.tsx +61 -40
  215. package/src/components/Circle.tsx +16 -0
  216. package/src/components/CitricComponent.ts +14 -0
  217. package/src/components/Divider.tsx +6 -5
  218. package/src/components/ErrorBoundary.tsx +13 -0
  219. package/src/components/ErrorMessage.tsx +1 -1
  220. package/src/components/FallbackBoundary.tsx +12 -1
  221. package/src/components/Favorite.tsx +12 -0
  222. package/src/components/FieldGroup.tsx +13 -0
  223. package/src/components/Form.tsx +18 -0
  224. package/src/components/FormGroup.tsx +12 -0
  225. package/src/components/IconBox.tsx +61 -30
  226. package/src/components/ImageBox.tsx +60 -30
  227. package/src/components/ImageWithFallback.tsx +18 -0
  228. package/src/components/Input.tsx +28 -14
  229. package/src/components/Link.tsx +6 -0
  230. package/src/components/MenuOverlay/index.tsx +20 -0
  231. package/src/components/Overlay/index.tsx +17 -0
  232. package/src/components/Pagination.tsx +40 -17
  233. package/src/components/ProgressBar.tsx +14 -0
  234. package/src/components/ProgressCircular.tsx +14 -0
  235. package/src/components/RadioGroup.tsx +62 -39
  236. package/src/components/Rating.tsx +10 -0
  237. package/src/components/Select/RichSelect.tsx +183 -182
  238. package/src/components/Select/SimpleSelect.tsx +57 -57
  239. package/src/components/Select/index.tsx +29 -5
  240. package/src/components/Select/types.ts +1 -1
  241. package/src/components/SelectBox.tsx +92 -62
  242. package/src/components/Skeleton.tsx +11 -0
  243. package/src/components/Slider.tsx +12 -0
  244. package/src/components/SmartTable.tsx +91 -56
  245. package/src/components/Stepper.tsx +76 -57
  246. package/src/components/Table.tsx +10 -0
  247. package/src/components/Tabs/TabController.ts +14 -0
  248. package/src/components/Tabs/index.tsx +56 -37
  249. package/src/components/Text.ts +36 -21
  250. package/src/components/Textarea.tsx +14 -4
  251. package/src/components/Tooltip.tsx +14 -1
  252. package/src/components/layout.tsx +56 -13
  253. package/src/index.ts +0 -1
  254. package/dist/components/Switch.d.ts +0 -10
  255. package/dist/components/Switch.d.ts.map +0 -1
  256. package/dist/components/Switch.js +0 -8
  257. package/dist/components/Switch.js.map +0 -1
  258. package/src/components/Switch.tsx +0 -30
@@ -26,6 +26,18 @@ export interface BaseFormGroupProps {
26
26
 
27
27
  export type FormGroupProps = React.JSX.IntrinsicElements['div'] & BaseFormGroupProps
28
28
 
29
+ /**
30
+ * A form group renders everything a field in a form needs: the input, its label, a tooltip (help), an error and a remark (warning).
31
+ *
32
+ * Labels, errors, tooltips and warnings are only rendered when they're strings with at least one character.
33
+ *
34
+ * @example
35
+ * ```
36
+ * <FormGroup label="Birth Date" help="The date when you were born" error="The date you typed is invalid!">
37
+ * <Input type="date" />
38
+ * </FormGroup>
39
+ * ```
40
+ */
29
41
  export const FormGroup = withRef(({ error, help, label, warning, className, children, ...props }: FormGroupProps) => (
30
42
  <CitricComponent tag="div" component="form-group" className={listToClass([className, error && 'error'])} {...props}>
31
43
  <label>
@@ -59,41 +59,72 @@ export interface BaseIconBoxProps<T extends IconBoxTag, G extends IconGroup> ext
59
59
 
60
60
  export type IconBoxProps<T extends IconBoxTag, G extends IconGroup> = Omit<HTMLTag[T], 'children'> & BaseIconBoxProps<T, G>
61
61
 
62
- function _IconBox<T extends IconBoxTag = 'i', G extends IconGroup = 'outline'>(
63
- { group, icon, tag, appearance, size, className, analytics, onClick, feedback, ...props }: IconBoxProps<T, G>,
64
- ) {
65
- const citric = useCitricController()
62
+ /**
63
+ * Renders a wrapper for an icon. The icon must specified by the properties "icon" and "group", this component accepts no children.
64
+ *
65
+ * If you don't need the icon to be rendered within a box, consider using the component "Icon" directly.
66
+ *
67
+ * Hover and focus effects are applied if the IconBox is focusable.
68
+ *
69
+ * @example
70
+ * ```
71
+ * <IconBox icon="Search" colorScheme="primary" />
72
+ * ```
73
+ */
74
+ export const IconBox = withRef(
75
+ function IconBox<T extends IconBoxTag = 'i', G extends IconGroup = 'outline'>(
76
+ { group, icon, tag, appearance, size, className, analytics, onClick, feedback, ...props }: IconBoxProps<T, G>,
77
+ ) {
78
+ props['aria-label'] ||= props.title // accessibility
79
+ const citric = useCitricController()
66
80
 
67
- function handleClick(e: React.MouseEvent<any>) {
68
- onClick?.(e)
69
- if (tag === 'button') citric?.onClickButton?.(e, analytics ?? false)
70
- else if (tag === 'a') citric?.onClickLink?.(e, analytics ?? false)
71
- }
81
+ function handleClick(e: React.MouseEvent<any>) {
82
+ onClick?.(e)
83
+ if (tag === 'button') citric?.onClickButton?.(e, analytics ?? false)
84
+ else if (tag === 'a') citric?.onClickLink?.(e, analytics ?? false)
85
+ }
72
86
 
73
- return <CitricComponent
74
- tag={(tag || 'i') as any}
75
- component="icon-box"
76
- className={listToClass(['citric-icon', group || 'outline', icon, appearance, size, className])}
77
- data-feedback={feedback || undefined}
78
- onClick={['button', 'a'].includes(tag ?? '') ? handleClick : onClick}
79
- {...props}
80
- />
81
- }
87
+ return <CitricComponent
88
+ tag={(tag || 'i') as any}
89
+ component="icon-box"
90
+ className={listToClass(['citric-icon', group || 'outline', icon, appearance, size, className])}
91
+ data-feedback={feedback || undefined}
92
+ onClick={['button', 'a'].includes(tag ?? '') ? handleClick : onClick}
93
+ {...props}
94
+ />
95
+ },
96
+ )
82
97
 
83
98
  /**
84
- * Shortcut to `<IconBox tag="button" />`
99
+ * A shortcut for `<IconBox tag="button">`.
100
+ *
101
+ * Whenever a button is clicked, the function `onClickButton` of the nearest CitricController is called with the event and the value of the
102
+ * prop `analytics`.
103
+ *
104
+ * @example
105
+ * ```
106
+ * <IconButton icon="Search" />
107
+ * ```
85
108
  */
86
- function _IconButton<G extends IconGroup = 'outline'>({ type, ...props }: Omit<IconBoxProps<'button', G>, 'tag'>) {
87
- return <IconBox {...props} tag="button" type={type || 'button' } />
88
- }
109
+ export const IconButton = withRef(
110
+ function IconButton<G extends IconGroup = 'outline'>({ type, ...props }: Omit<IconBoxProps<'button', G>, 'tag'>) {
111
+ return <IconBox {...props} tag="button" type={type || 'button' } />
112
+ },
113
+ )
89
114
 
90
115
  /**
91
- * Shortcut to `<IconBox tag="a" />`
116
+ * A shortcut for `<IconBox tag="a">`.
117
+ *
118
+ * Whenever a link is clicked, the function `onClickLink` of the nearest CitricController is called with the event and the value of the
119
+ * prop `analytics`.
120
+ *
121
+ * @example
122
+ * ```
123
+ * <IconLink icon="Search" href="#" />
124
+ * ```
92
125
  */
93
- function _IconLink<G extends IconGroup = 'outline'>(props: Omit<IconBoxProps<'a', G>, 'tag'>) {
94
- return <IconBox {...props} tag="a" />
95
- }
96
-
97
- export const IconBox = withRef(_IconBox)
98
- export const IconButton = withRef(_IconButton)
99
- export const IconLink = withRef(_IconLink)
126
+ export const IconLink = withRef(
127
+ function IconLink<G extends IconGroup = 'outline'>(props: Omit<IconBoxProps<'a', G>, 'tag'>) {
128
+ return <IconBox {...props} tag="a" />
129
+ },
130
+ )
@@ -49,41 +49,71 @@ export interface BaseImageBoxProps<T extends ImageBoxTag> extends WithColorPalet
49
49
 
50
50
  export type ImageBoxProps<T extends ImageBoxTag> = HTMLTag[T] & BaseImageBoxProps<T>
51
51
 
52
- function _ImageBox<T extends ImageBoxTag = 'div'>(
53
- { tag, appearance, size, className, analytics, onClick, feedback, ...props }: ImageBoxProps<T>,
54
- ) {
55
- const citric = useCitricController()
52
+ /**
53
+ * Renders a wrapper for its child (normally an image). The image will be resized and cropped to fit the container. The image is not cropped
54
+ * if the property "feedback" is set.
55
+ *
56
+ * Hover and focus effects are applied if the ImageBox is focusable.
57
+ *
58
+ * @example
59
+ * ```
60
+ * <ImageBox><img src="https://images.com/myimage.png" /></ImageBox>
61
+ * ```
62
+ */
63
+ export const ImageBox = withRef(
64
+ function ImageBox<T extends ImageBoxTag = 'div'>(
65
+ { tag, appearance, size, className, analytics, onClick, feedback, ...props }: ImageBoxProps<T>,
66
+ ) {
67
+ props['aria-label'] ||= props.title // accessibility
68
+ const citric = useCitricController()
56
69
 
57
- function handleClick(e: React.MouseEvent<any>) {
58
- onClick?.(e)
59
- if (tag === 'button') citric?.onClickButton?.(e, analytics ?? false)
60
- else if (tag === 'a') citric?.onClickLink?.(e, analytics ?? false)
61
- }
70
+ function handleClick(e: React.MouseEvent<any>) {
71
+ onClick?.(e)
72
+ if (tag === 'button') citric?.onClickButton?.(e, analytics ?? false)
73
+ else if (tag === 'a') citric?.onClickLink?.(e, analytics ?? false)
74
+ }
62
75
 
63
- return <CitricComponent
64
- tag={(tag || 'i') as any}
65
- component="icon-box"
66
- className={listToClass([appearance, size, className])}
67
- data-feedback={feedback || undefined}
68
- onClick={['button', 'a'].includes(tag ?? '') ? handleClick : onClick}
69
- {...props}
70
- />
71
- }
76
+ return <CitricComponent
77
+ tag={(tag || 'i') as any}
78
+ component="icon-box"
79
+ className={listToClass([appearance, size, className])}
80
+ data-feedback={feedback || undefined}
81
+ onClick={['button', 'a'].includes(tag ?? '') ? handleClick : onClick}
82
+ {...props}
83
+ />
84
+ },
85
+ )
72
86
 
73
87
  /**
74
- * Shortcut to `<ImageBox tag="button" />`
88
+ * A shortcut for `<ImageBox tag="button">`.
89
+ *
90
+ * Whenever a button is clicked, the function `onClickButton` of the nearest CitricController is called with the event and the value of the
91
+ * prop `analytics`.
92
+ *
93
+ * @example
94
+ * ```
95
+ * <ImageButton><img src="https://images.com/myimage.png" /></ImageButton>
96
+ * ```
75
97
  */
76
- function _ImageButton(props: Omit<ImageBoxProps<'button'>, 'tag'>) {
77
- return <ImageBox {...props} tag="button" type={props.type || 'button'} />
78
- }
98
+ export const ImageButton = withRef(
99
+ function ImageButton(props: Omit<ImageBoxProps<'button'>, 'tag'>) {
100
+ return <ImageBox {...props} tag="button" type={props.type || 'button'} />
101
+ },
102
+ )
79
103
 
80
104
  /**
81
- * Shortcut to `<ImageBox tag="a" />`
105
+ * A shortcut for `<ImageBox tag="a">`.
106
+ *
107
+ * Whenever a link is clicked, the function `onClickLink` of the nearest CitricController is called with the event and the value of the
108
+ * prop `analytics`.
109
+ *
110
+ * @example
111
+ * ```
112
+ * <ImageLink href="#"><img src="https://images.com/myimage.png" /></ImageButton>
113
+ * ```
82
114
  */
83
- function _ImageLink(props: Omit<ImageBoxProps<'a'>, 'tag'>) {
84
- return <ImageBox {...props} tag="a" />
85
- }
86
-
87
- export const ImageBox = withRef(_ImageBox)
88
- export const ImageButton = withRef(_ImageButton)
89
- export const ImageLink = withRef(_ImageLink)
115
+ export const ImageLink = withRef(
116
+ function ImageLink(props: Omit<ImageBoxProps<'a'>, 'tag'>) {
117
+ return <ImageBox {...props} tag="a" />
118
+ },
119
+ )
@@ -5,12 +5,30 @@ import { getStyleFromProps } from '../utils/css'
5
5
  import { Skeleton } from './Skeleton'
6
6
 
7
7
  export interface BaseImageWithFallbackProps extends Pick<WithStyleShortcuts, 'w' | 'h' | 'radius' | 'bg'> {
8
+ /**
9
+ * The react element to fallback to if the image can't be rendered.
10
+ */
8
11
  fallback: React.ReactNode,
12
+ /**
13
+ * Whether or not to show a skeleton when the image is still loading.
14
+ * @default false
15
+ */
9
16
  showLoading?: boolean,
10
17
  }
11
18
 
12
19
  export type ImageWithFallbackProps = JSX.IntrinsicElements['img'] & BaseImageWithFallbackProps
13
20
 
21
+ /**
22
+ * Attempts to render an image. If it succeeds, the image is displayed, otherwise, a fallback is rendered.
23
+ *
24
+ * This is very useful if the value of "src" may be empty or if it may be broken. Instead of rendering nothing or the default browser error,
25
+ * it renders the fallback passed as parameter.
26
+ *
27
+ * @example
28
+ * ```
29
+ * <ImageWithFallback src={item.image} fallback={<Icon icon="Agent" />} />
30
+ * ```
31
+ */
14
32
  export const ImageWithFallback = (
15
33
  { onLoad, onError, className, style: ogStyle, fallback, showLoading, w, h, radius, bg, ...props }: ImageWithFallbackProps,
16
34
  ) => {
@@ -17,19 +17,33 @@ export interface BaseInputProps<T extends SupportedInputType> extends WithColorS
17
17
  export type InputProps<T extends SupportedInputType = 'text'> =
18
18
  ControlledInput & BaseInputProps<T> & { type?: T }
19
19
 
20
- function _Input<T extends SupportedInputType = 'text'>({ type, value, onChange, ...props }: InputProps<T>) {
21
- function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
22
- if (!onChange) return
23
- const newValue = e.target.value
24
- if (type === 'number') {
25
- const parsed = newValue ? parseFloat(newValue) : undefined
26
- onChange(parsed as any)
27
- } else {
28
- onChange(newValue as any)
20
+ /**
21
+ * Renders a input.
22
+ *
23
+ * Attention: "onChange" doesn't receive an event, instead, it receives the new value of the input: a string, unless "type" is "number",
24
+ * in this case, it receives a number.
25
+ *
26
+ * @example
27
+ *
28
+ * ```
29
+ * const [value, setValue] = useState('')
30
+ *
31
+ * return <Input value={value} onChange={setValue} />
32
+ * ```
33
+ */
34
+ export const Input = withRef(
35
+ function Input<T extends SupportedInputType = 'text'>({ type, value, onChange, ...props }: InputProps<T>) {
36
+ function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
37
+ if (!onChange) return
38
+ const newValue = e.target.value
39
+ if (type === 'number') {
40
+ const parsed = newValue ? parseFloat(newValue) : undefined
41
+ onChange(parsed as any)
42
+ } else {
43
+ onChange(newValue as any)
44
+ }
29
45
  }
30
- }
31
46
 
32
- return <CitricComponent tag="input" component="input" type={type} value={value} onChange={handleChange} {...props} />
33
- }
34
-
35
- export const Input = withRef(_Input)
47
+ return <CitricComponent tag="input" component="input" type={type} value={value} onChange={handleChange} {...props} />
48
+ },
49
+ )
@@ -23,6 +23,12 @@ export interface BaseLinkProps extends WithColor {
23
23
 
24
24
  export type LinkProps = React.JSX.IntrinsicElements['a'] & BaseLinkProps
25
25
 
26
+ /**
27
+ * Renders an html anchor by default, the actual component to render may be set on a CitricController, through the function `renderLink`.
28
+ *
29
+ * Whenever a link is clicked, the function `onClickLink` of the nearest CitricController is called with the event and the value of the
30
+ * prop `analytics`.
31
+ */
26
32
  export const Link = withRef(({ appearance, color, style, className, children, onClick, analytics, ...props }: LinkProps) => {
27
33
  const citric = useCitricController()
28
34
  const linkProps = {
@@ -5,6 +5,26 @@ import { Overlay } from '../Overlay'
5
5
  import { Menu } from './Menu'
6
6
  import { MenuOverlayProps } from './types'
7
7
 
8
+ /**
9
+ * Creates a menu overlay for its child element. Whenever the child element is clicked, the menu appears. Closing the menu is also handled
10
+ * by this component.
11
+ *
12
+ * The menu is defined by the property "items" and can contain sections and sub menus.
13
+ *
14
+ * If no child is provided, a button with the vertical ellipsis icon is rendered.
15
+ *
16
+ * @example
17
+ *
18
+ * ```
19
+ * const items: MenuItem[] = useMemo([
20
+ * { label: 'View', href: `/resource/${id}` },
21
+ * { label: 'Edit', onClick: () => editResource(id) },
22
+ * { label: 'Remove', onClick: () => removeResource(id), style: { color: theme.color.danger[500] } },
23
+ * ], [id])
24
+ *
25
+ * return <MenuOverlay items={items}><IconButton icon="Plus" /></MenuOverlay>
26
+ * ```
27
+ */
8
28
  export const MenuOverlay = ({
9
29
  id, items, appearance, bgLevel, header, roundedItems, showBorders, showShadows, spaced, menuClass, menuStyle, children, ...props
10
30
  }: MenuOverlayProps) => {
@@ -21,6 +21,23 @@ const arbitraryRenderTime = 20
21
21
  * hidden by the scroll.
22
22
  * TODO: use React Portal to implement overlays. The current implementation will lose every React context in the tree.
23
23
  */
24
+
25
+ /**
26
+ * Creates an overlay for the child component. The overlay can be any React element. The overlay can be triggered by "click" or "hover"
27
+ * (default).
28
+ *
29
+ * @example
30
+ *
31
+ * ```
32
+ * const overlay = <Card>Hey, this is my overlay!</Card>
33
+ *
34
+ * return (
35
+ * <Overlay content={overlay} attributes={{ style: { margin: '20px' } }}>
36
+ * <Button>Hover to see the overlay</Button>
37
+ * </Overlay>
38
+ * )
39
+ * ```
40
+ */
24
41
  export function Overlay<T extends keyof HTMLTag>({
25
42
  tag,
26
43
  children,
@@ -4,6 +4,17 @@ import { withRef } from '../utils/react'
4
4
  import { CitricComponent } from './CitricComponent'
5
5
  import { IconButton } from './IconBox'
6
6
 
7
+ export interface PaginationValue {
8
+ /**
9
+ * The first page is 1. If "0" is provided, it will be treated as if it was "1".
10
+ */
11
+ page: number,
12
+ /**
13
+ * The current number of items in a page.
14
+ */
15
+ size: number,
16
+ }
17
+
7
18
  export interface BasePaginationProps {
8
19
  /**
9
20
  * The options for the page size.
@@ -16,60 +27,72 @@ export interface BasePaginationProps {
16
27
  */
17
28
  totalPages: number,
18
29
  /**
19
- * The first page is 1. If "0" is provided, it will be treated as if it was "1".
30
+ * The current page and page size.
20
31
  */
21
- page: number,
22
- /**
23
- * The current number of items in a page.
24
- */
25
- pageSize: number,
32
+ value: PaginationValue,
26
33
  /**
27
34
  * Function to run whenever the page size or current page changes.
28
35
  */
29
- onChange: (page: number, size: number) => void,
36
+ onChange: (value: PaginationValue) => void,
30
37
  }
31
38
 
32
39
  export type PaginationProps = Omit<React.JSX.IntrinsicElements['div'], 'onChange'> & BasePaginationProps
33
40
 
41
+ /**
42
+ * Renders a pagination UI, letting the user chose one among multiple pages. This is generally rendered at the bottom of a table.
43
+ *
44
+ * @example
45
+ * ```
46
+ * const [pageData, setPageData] = useState({ page: 1, size: 10 })
47
+ * return <Pagination
48
+ * value={pageData}
49
+ * totalPages={50}
50
+ * onChange={setPageData}
51
+ * />
52
+ * ```
53
+ */
34
54
  export const Pagination = withRef((
35
- { pageSizeOptions = [10, 20, 30], pageSize, totalPages, page, onChange, ...props }: PaginationProps,
55
+ { pageSizeOptions = [10, 20, 30], totalPages, value, onChange, ...props }: PaginationProps,
36
56
  ) => {
37
57
  const t = useTranslate(dictionary)
38
- const sizeOptions = useMemo(() => pageSizeOptions.map(o => <option key={o} selected={pageSize === o}>{o}</option>), [pageSizeOptions])
58
+ const sizeOptions = useMemo(
59
+ () => pageSizeOptions.map(o => <option key={o} selected={value.size === o}>{o}</option>),
60
+ [pageSizeOptions],
61
+ )
39
62
  const pageOptions = useMemo(() => {
40
63
  const options: React.ReactElement[] = []
41
64
  for (let i = 1; i <= totalPages; i++) {
42
- options.push(<option key={i} value={i} selected={page === i}>{i}</option>)
65
+ options.push(<option key={i} value={i} selected={value.page === i}>{i}</option>)
43
66
  }
44
67
  return options
45
- }, [page, totalPages])
68
+ }, [value.page, totalPages])
46
69
 
47
70
  return (
48
71
  <CitricComponent tag="div" component="pagination" {...props}>
49
72
  <div className="page-size">
50
73
  <label>
51
74
  {t.itemsPerPage}:
52
- <select name="itemsPerPage" onChange={e => onChange(page, parseInt(e.target.value))}>{sizeOptions}</select>
75
+ <select name="itemsPerPage" onChange={e => onChange({ page: value.page, size: parseInt(e.target.value) })}>{sizeOptions}</select>
53
76
  </label>
54
77
  </div>
55
78
  <div className="page-number">
56
79
  <label>
57
- <select name="page" onChange={e => onChange(parseInt(e.target.value), pageSize)}>{pageOptions}</select>
80
+ <select name="page" onChange={e => onChange({ page: parseInt(e.target.value), size: value.size })}>{pageOptions}</select>
58
81
  </label>
59
82
  {totalPages > 1 ? interpolate(t.ofTotalPlural, totalPages) : t.ofTotalSingular}
60
83
  <IconButton
61
84
  icon="ChevronLeft"
62
85
  aria-label="previous"
63
86
  title="previous"
64
- disabled={page === 1}
65
- onClick={() => onChange(page - 1, pageSize)}
87
+ disabled={value.page === 1}
88
+ onClick={() => onChange({ page: value.page - 1, size: value.size })}
66
89
  />
67
90
  <IconButton
68
91
  icon="ChevronRight"
69
92
  aria-label="next"
70
93
  title="next"
71
- disabled={page === totalPages}
72
- onClick={() => onChange(page + 1, pageSize)}
94
+ disabled={value.page === totalPages}
95
+ onClick={() => onChange({ page: value.page + 1, size: value.size })}
73
96
  />
74
97
  </div>
75
98
  </CitricComponent>
@@ -20,6 +20,20 @@ export interface BaseProgressBarProps extends WithColorScheme, WithColorPalette
20
20
 
21
21
  export type ProgressBarProps = React.JSX.IntrinsicElements['div'] & BaseProgressBarProps
22
22
 
23
+ /**
24
+ * Shows a progress bar. This can indicate a loading state or the progress of a task. When "progress" is not set, the bar is animated,
25
+ * indicating a busy state.
26
+ *
27
+ * @example
28
+ * A simple loading with a Progress Bar.
29
+ * ```
30
+ * <ProgressBar />
31
+ * ```
32
+ * A Progress Bar that is 50% complete.
33
+ * ```
34
+ * <ProgressBar progress={50} />
35
+ * ```
36
+ */
23
37
  export const ProgressBar = withRef(({ progress, speed, style, className, ...props }: ProgressBarProps) =>
24
38
  <CitricComponent
25
39
  tag="div"
@@ -20,6 +20,20 @@ export interface BaseProgressCircularProps extends WithColorScheme, WithColorPal
20
20
 
21
21
  export type ProgressCircularProps = React.JSX.IntrinsicElements['div'] & BaseProgressCircularProps
22
22
 
23
+ /**
24
+ * Shows a circular progress. This can indicate a loading state (spinner) or the progress of a task. When "progress" is not set, the
25
+ * spinner is animated, indicating a busy state.
26
+ *
27
+ * @example
28
+ * A simple loading with a Progress Circular.
29
+ * ```
30
+ * <ProgressCircular />
31
+ * ```
32
+ * A Progress Circular that is 50% complete.
33
+ * ```
34
+ * <ProgressCircular progress={50} />
35
+ * ```
36
+ */
23
37
  export const ProgressCircular = withRef(({ progress, size, style, className, ...props }: ProgressCircularProps) =>
24
38
  <CitricComponent
25
39
  tag="div"
@@ -67,42 +67,65 @@ export interface BaseRadioGroupProps<T> extends WithColorScheme {
67
67
 
68
68
  export type RadioGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseRadioGroupProps<T>
69
69
 
70
- function _RadioGroup<T>({
71
- name,
72
- value,
73
- options,
74
- onChange,
75
- renderLabel = defaultRenderLabel,
76
- renderKey = defaultRenderKey,
77
- renderItem,
78
- isDisabled,
79
- colorScheme,
80
- style,
81
- ...props
82
- }: RadioGroupProps<T>) {
83
- const items = useMemo(() => {
84
- const valueKey = value ? renderKey(value) : undefined
85
- return options.map((o) => {
86
- const key = renderKey(o)
87
- const radio = <CitricComponent
88
- tag="input"
89
- component="radio"
90
- type="radio"
91
- name={name}
92
- value={key}
93
- checked={value === o || (!isNil(key) && valueKey === key)}
94
- onChange={() => onChange?.(o)}
95
- disabled={isDisabled?.(o)}
96
- />
97
- return renderItem ? renderItem(radio, o) : (
98
- <CitricComponent tag="label" component="radio-row" key={key} colorScheme={colorScheme}>
99
- {radio}
100
- {renderLabel(o)}
101
- </CitricComponent>
102
- )
103
- })
104
- }, [options, value, name, colorScheme])
105
- return <Column {...props} style={{ gap: '8px', ...style }}>{items}</Column>
106
- }
107
-
108
- export const RadioGroup = withRef(_RadioGroup)
70
+ /**
71
+ * Renders a list of radio button for single-selection. One radio button is rendered for each option.
72
+ *
73
+ * Attention: single radio buttons don't make sense, this is why they're not provided by this library.
74
+ *
75
+ * This component can be heavily customized via its properties. Check the storybook for complex examples.
76
+ *
77
+ * Tip: if you need to implement features like "search", use the hook `useRadioGroupControls`.
78
+ *
79
+ * @example
80
+ *
81
+ * ```
82
+ * const options = useMemo(() => [
83
+ * { id: 1, name: 'Option 1' },
84
+ * { id: 2, name: 'Option 2' },
85
+ * { id: 3, name: 'Option 3' },
86
+ * ], [])
87
+ *
88
+ * const [value, setValue] = useState<(typeof options)[number] | undefined>()
89
+ *
90
+ * return <RadioGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
91
+ * ```
92
+ */
93
+ export const RadioGroup = withRef(
94
+ function RadioGroup<T>({
95
+ name,
96
+ value,
97
+ options,
98
+ onChange,
99
+ renderLabel = defaultRenderLabel,
100
+ renderKey = defaultRenderKey,
101
+ renderItem,
102
+ isDisabled,
103
+ colorScheme,
104
+ style,
105
+ ...props
106
+ }: RadioGroupProps<T>) {
107
+ const items = useMemo(() => {
108
+ const valueKey = value ? renderKey(value) : undefined
109
+ return options.map((o) => {
110
+ const key = renderKey(o)
111
+ const radio = <CitricComponent
112
+ tag="input"
113
+ component="radio"
114
+ type="radio"
115
+ name={name}
116
+ value={key}
117
+ checked={value === o || (!isNil(key) && valueKey === key)}
118
+ onChange={() => onChange?.(o)}
119
+ disabled={isDisabled?.(o)}
120
+ />
121
+ return renderItem ? renderItem(radio, o) : (
122
+ <CitricComponent tag="label" component="radio-row" key={key} colorScheme={colorScheme}>
123
+ {radio}
124
+ {renderLabel(o)}
125
+ </CitricComponent>
126
+ )
127
+ })
128
+ }, [options, value, name, colorScheme])
129
+ return <Column {...props} style={{ gap: '8px', ...style }}>{items}</Column>
130
+ },
131
+ )
@@ -14,6 +14,16 @@ export interface BaseRatingProps {
14
14
 
15
15
  export type RatingProps = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseRatingProps
16
16
 
17
+ /**
18
+ * Renders a 5 star rating UI. The user can select 1 to 5 stars.
19
+ *
20
+ * @example
21
+ * ```
22
+ * const [value, setValue] = useState<RatingValue | undefined>()
23
+ * return <Rating value={value} setValue={setValue} />
24
+ * ```
25
+ * In the example above, `RatingValue` is any integer from 1 to 5.
26
+ */
17
27
  export const Rating = withRef(({ value, onChange, name, ...props }: RatingProps) => (
18
28
  <CitricComponent tag="div" component="rating" {...props}>
19
29
  <input type="radio" value="1" name={name} checked={value === 5} onChange={() => onChange(5)} />