@stack-spot/citric-react 0.21.0 → 0.23.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 (261) hide show
  1. package/dist/citric.css +30 -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 +34 -9
  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 +19 -1
  121. package/dist/components/ProgressBar.d.ts.map +1 -1
  122. package/dist/components/ProgressBar.js +15 -1
  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 +23 -4
  181. package/dist/components/Tabs/index.js.map +1 -1
  182. package/dist/components/Tabs/types.d.ts +6 -0
  183. package/dist/components/Tabs/types.d.ts.map +1 -1
  184. package/dist/components/Text.d.ts +16 -2
  185. package/dist/components/Text.d.ts.map +1 -1
  186. package/dist/components/Text.js +17 -3
  187. package/dist/components/Text.js.map +1 -1
  188. package/dist/components/Textarea.d.ts +11 -1
  189. package/dist/components/Textarea.d.ts.map +1 -1
  190. package/dist/components/Textarea.js +12 -2
  191. package/dist/components/Textarea.js.map +1 -1
  192. package/dist/components/Tooltip.d.ts +14 -1
  193. package/dist/components/Tooltip.d.ts.map +1 -1
  194. package/dist/components/Tooltip.js +13 -0
  195. package/dist/components/Tooltip.js.map +1 -1
  196. package/dist/components/layout.d.ts +41 -7
  197. package/dist/components/layout.d.ts.map +1 -1
  198. package/dist/components/layout.js +44 -9
  199. package/dist/components/layout.js.map +1 -1
  200. package/dist/index.d.ts +0 -1
  201. package/dist/index.d.ts.map +1 -1
  202. package/dist/index.js +0 -1
  203. package/dist/index.js.map +1 -1
  204. package/package.json +2 -2
  205. package/src/components/Accordion.tsx +34 -0
  206. package/src/components/Alert.tsx +8 -0
  207. package/src/components/AsyncContent.tsx +18 -4
  208. package/src/components/Avatar.tsx +11 -1
  209. package/src/components/AvatarGroup.tsx +8 -0
  210. package/src/components/Badge.tsx +24 -8
  211. package/src/components/Blockquote.tsx +8 -0
  212. package/src/components/Breadcrumb.tsx +10 -1
  213. package/src/components/Button.tsx +17 -2
  214. package/src/components/Card.tsx +34 -14
  215. package/src/components/Checkbox.tsx +14 -0
  216. package/src/components/CheckboxGroup.tsx +61 -40
  217. package/src/components/Circle.tsx +16 -0
  218. package/src/components/CitricComponent.ts +14 -0
  219. package/src/components/Divider.tsx +6 -5
  220. package/src/components/ErrorBoundary.tsx +13 -0
  221. package/src/components/ErrorMessage.tsx +1 -1
  222. package/src/components/FallbackBoundary.tsx +12 -1
  223. package/src/components/Favorite.tsx +12 -0
  224. package/src/components/FieldGroup.tsx +13 -0
  225. package/src/components/Form.tsx +18 -0
  226. package/src/components/FormGroup.tsx +12 -0
  227. package/src/components/IconBox.tsx +62 -31
  228. package/src/components/ImageBox.tsx +60 -30
  229. package/src/components/ImageWithFallback.tsx +18 -0
  230. package/src/components/Input.tsx +28 -14
  231. package/src/components/Link.tsx +6 -0
  232. package/src/components/MenuOverlay/index.tsx +20 -0
  233. package/src/components/Overlay/index.tsx +17 -0
  234. package/src/components/Pagination.tsx +40 -17
  235. package/src/components/ProgressBar.tsx +20 -2
  236. package/src/components/ProgressCircular.tsx +14 -0
  237. package/src/components/RadioGroup.tsx +62 -39
  238. package/src/components/Rating.tsx +10 -0
  239. package/src/components/Select/RichSelect.tsx +183 -182
  240. package/src/components/Select/SimpleSelect.tsx +57 -57
  241. package/src/components/Select/index.tsx +29 -5
  242. package/src/components/Select/types.ts +1 -1
  243. package/src/components/SelectBox.tsx +92 -62
  244. package/src/components/Skeleton.tsx +11 -0
  245. package/src/components/Slider.tsx +12 -0
  246. package/src/components/SmartTable.tsx +91 -56
  247. package/src/components/Stepper.tsx +76 -57
  248. package/src/components/Table.tsx +10 -0
  249. package/src/components/Tabs/TabController.ts +14 -0
  250. package/src/components/Tabs/index.tsx +57 -37
  251. package/src/components/Tabs/types.ts +6 -0
  252. package/src/components/Text.ts +36 -21
  253. package/src/components/Textarea.tsx +14 -4
  254. package/src/components/Tooltip.tsx +14 -1
  255. package/src/components/layout.tsx +56 -13
  256. package/src/index.ts +0 -1
  257. package/dist/components/Switch.d.ts +0 -10
  258. package/dist/components/Switch.d.ts.map +0 -1
  259. package/dist/components/Switch.js +0 -8
  260. package/dist/components/Switch.js.map +0 -1
  261. package/src/components/Switch.tsx +0 -30
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/citric-react",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "author": "StackSpot",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -15,7 +15,7 @@
15
15
  "url": "https://github.com/stack-spot/citric"
16
16
  },
17
17
  "peerDependencies": {
18
- "@stack-spot/citric-icons": ">=0.2.1",
18
+ "@stack-spot/citric-icons": ">=0.2.2",
19
19
  "@stack-spot/portal-theme": ">=1.2.1",
20
20
  "@stack-spot/portal-translate": ">=1.2.2",
21
21
  "lodash": ">=4.17.21",
@@ -37,6 +37,40 @@ export interface BaseAccordionProps {
37
37
 
38
38
  export type AccordionProps = Omit<React.JSX.IntrinsicElements['div'], 'onChange'> & BaseAccordionProps
39
39
 
40
+ /**
41
+ * Creates an accordion, showing/hiding the children according to the state of the expand/collapse checkbox.
42
+ *
43
+ * The accordion must define a max height, which is 300 by default (measured in pixels). Whenever the content surpasses "maxHeight", a
44
+ * vertical scroll is created. If your content is much shorter than "maxHeight", consider reducing its value for a better animation.
45
+ *
46
+ * @example
47
+ * A simple accordion, styled like a card:
48
+ * ```
49
+ * <Accordion appearance="card" header="This is the title of the accordion" maxHeight={80}>
50
+ * <p>This is the content of the accordion</p>
51
+ * </Accordion>
52
+ * ```
53
+ *
54
+ * A more complex accordion:
55
+ * ```
56
+ * const header = (toggle: React.ReactElement) => (
57
+ * <Row justifyContent="space-between" bg="cyan.500" border="cyan.700" radius="sm">
58
+ * <ImageBox><img src="/my-image.png" /></ImageBox>
59
+ * <Text>Joseph Clinton</Text>
60
+ * <Text>40 years old</Text>
61
+ * {toggle}
62
+ * </Row>
63
+ * )
64
+ * return (
65
+ * <Accordion header={header}>
66
+ * <Center>
67
+ * <img src="/an-image.png" />
68
+ * <p>This is the content of the accordion</p>
69
+ * </Center>
70
+ * </Accordion>
71
+ * )
72
+ * ```
73
+ */
40
74
  export const Accordion = withRef((
41
75
  { id, appearance, expanded, onChange, header, maxHeight = 300, className, style, children, ...props }: AccordionProps,
42
76
  ) => {
@@ -12,5 +12,13 @@ export interface BaseAlertProps {
12
12
 
13
13
  export type AlertProps = React.JSX.IntrinsicElements['div'] & BaseAlertProps
14
14
 
15
+ /**
16
+ * Renders an alert message with an icon and a background. This may be an error, warning or a success feedback.
17
+ *
18
+ * @example
19
+ * ```
20
+ * <Alert type="warning">My warning!</Alert>
21
+ * ```
22
+ */
15
23
  export const Alert = withRef(({ type, className, children, ...props }: AlertProps) =>
16
24
  <CitricComponent tag="div" component="alert" className={listToClass([type, className])} {...props}>{children}</CitricComponent>)
@@ -25,11 +25,25 @@ interface Props {
25
25
  }
26
26
 
27
27
  /**
28
- * Renders a component that provides user feedback on async requests.
29
- * It renders either a loading component, an error component (which is received as prop)
30
- * or the received children props.
28
+ * Renders a component that provides user feedback on async requests. It renders either a loading component, an error component or its
29
+ * children.
31
30
  *
32
- * @param options the props for rendering the component: {@link Props}.
31
+ * The loading and error views can be customized through a CitricController.
32
+ *
33
+ * Errors can be watched through the function `onError` of a CitricController.
34
+ *
35
+ * Attention: for React Suspense, use the component "FallbackBoundary" instead.
36
+ *
37
+ * @example
38
+ * ```
39
+ * const [data, isLoading, error] = useRemoteData()
40
+ *
41
+ * return (
42
+ * <AsyncContent loading={isLoading} error={error}>
43
+ * {data}
44
+ * </AsyncContent>
45
+ * )
46
+ * ```
33
47
  */
34
48
 
35
49
  export const AsyncContent = withRef(({ loading, error, autofocus, children }: Props) => {
@@ -2,6 +2,7 @@ import { listToClass } from '@stack-spot/portal-theme'
2
2
  import { WithColorPalette } from '../types'
3
3
  import { withRef } from '../utils/react'
4
4
  import { CitricComponent } from './CitricComponent'
5
+ import { ImageWithFallback } from './ImageWithFallback'
5
6
 
6
7
  export interface BaseAvatarProps extends WithColorPalette {
7
8
  /**
@@ -24,12 +25,21 @@ export interface BaseAvatarProps extends WithColorPalette {
24
25
 
25
26
  export type AvatarProps = React.JSX.IntrinsicElements['div'] & BaseAvatarProps
26
27
 
28
+ /**
29
+ * Renders an avatar. If an image is provided it's rendered within the space reserved to the avatar, otherwise, the initial of the names
30
+ * are used.
31
+ *
32
+ * @example
33
+ * ```
34
+ * <Avatar name="Rick Sanchez" />
35
+ * ```
36
+ */
27
37
  export const Avatar = withRef(({ size, name, appearance, className, image, ...props }: AvatarProps) => {
28
38
  const parts = name?.split(' ') ?? ['']
29
39
  const acronym = parts.length >= 2 ? `${parts[0][0]}${parts[1][0]}` : parts[0][0]
30
40
  return (
31
41
  <CitricComponent tag="div" component="avatar" className={listToClass([size, appearance, className])} {...props}>
32
- {image ? <img src={image} /> : acronym}
42
+ <ImageWithFallback src={image} fallback={acronym} />
33
43
  </CitricComponent>
34
44
  )
35
45
  })
@@ -25,6 +25,14 @@ export interface BaseAvatarGroupProps extends WithColorPalette {
25
25
 
26
26
  export type AvatarGroupProps = React.JSX.IntrinsicElements['div'] & BaseAvatarGroupProps
27
27
 
28
+ /**
29
+ * Stacks a group of avatars horizontally.
30
+ *
31
+ * @example
32
+ * ```
33
+ * <AvatarGroup items={[{ name: 'John Smith' }, { name: 'Mary Anne', image: 'https://profile.com/123.png' }]} />
34
+ * ```
35
+ */
28
36
  export const AvatarGroup = withRef(({ size, items, appearance, maxItems, className, ...props }: AvatarGroupProps) => {
29
37
  const avatars = items.map(({ name, image }) => <Avatar key={name} name={name} image={image} />, [items])
30
38
  return (
@@ -20,12 +20,28 @@ export interface BaseBadgeProps<T extends ValidTags = ValidTags> extends WithCol
20
20
 
21
21
  export type BadgeProps<T extends ValidTags> = HTMLTag[T] & BaseBadgeProps<T>
22
22
 
23
- function _Badge<T extends ValidTags>({ tag, appearance, className, children, ...props }: BadgeProps<T>) {
24
- return (
25
- <CitricComponent tag={tag || 'div'} component="badge" className={listToClass([appearance, className])} {...props as any}>
26
- {children}
27
- </CitricComponent>
28
- )
29
- }
23
+ /**
24
+ * Renders a badge. Badges have different color grades depending if they're focusable or not. Use `colorPalette` do determine the main
25
+ * color.
26
+ *
27
+ * @example
28
+ * ```
29
+ * <Badge>
30
+ * <Icon icon="PlusMini" />
31
+ * My first badge
32
+ * </Badge>
33
+ * ```
34
+ */
35
+ export const Badge = withRef(
36
+ function Badge<T extends ValidTags>({ tag, appearance, className, children, ...props }: BadgeProps<T>) {
37
+ return (
38
+ <CitricComponent tag={tag || 'div'} component="badge" className={listToClass([appearance, className])} {...props as any}>
39
+ {children}
40
+ </CitricComponent>
41
+ )
42
+ },
43
+ )
44
+
45
+
46
+ // export const Badge = withRef(_Badge)
30
47
 
31
- export const Badge = withRef(_Badge)
@@ -6,5 +6,13 @@ export type BaseBlockquoteProps = WithColorScheme & WithColorPalette
6
6
 
7
7
  export type BlockquoteProps = React.JSX.IntrinsicElements['blockquote'] & BaseBlockquoteProps
8
8
 
9
+ /**
10
+ * Renders a quote.
11
+ *
12
+ * @example
13
+ * ```
14
+ * <Blockquote>To be or not to be, that's the question</Blockquote>
15
+ * ```
16
+ */
9
17
  export const Blockquote = withRef(({ children, ...props }: BlockquoteProps) =>
10
18
  <CitricComponent tag="blockquote" component="blockquote" {...props}>{children}</CitricComponent>)
@@ -1,6 +1,7 @@
1
1
  import { useMemo } from 'react'
2
2
  import { withRef } from '../utils/react'
3
3
  import { CitricComponent } from './CitricComponent'
4
+ import { Link } from './Link'
4
5
 
5
6
  interface BreadCrumbItem {
6
7
  label: string,
@@ -13,10 +14,18 @@ export interface BaseBreadcrumbProps {
13
14
 
14
15
  export type BreadcrumbProps = React.JSX.IntrinsicElements['nav'] & BaseBreadcrumbProps
15
16
 
17
+ /**
18
+ * Renders a simple navigation bar with links to the previous pages.
19
+ *
20
+ * @example
21
+ * ```
22
+ * <Breadcrumb items={[{ label: 'Home', href: '/' }, { label: 'Settings', href: '/settings' }, { label: 'Profile' }]} />
23
+ * ```
24
+ */
16
25
  export const Breadcrumb = withRef(({ items, ...props }: BreadcrumbProps) => {
17
26
  const children = useMemo(
18
27
  () => items.map(
19
- (item, index) => item.href ? <li key={index}><a href={item.href}>{item.label}</a></li> : <li key={index}>{item.label}</li>,
28
+ (item, index) => item.href ? <li key={index}><Link href={item.href}>{item.label}</Link></li> : <li key={index}>{item.label}</li>,
20
29
  ),
21
30
  [items],
22
31
  )
@@ -1,5 +1,5 @@
1
1
  import { listToClass } from '@stack-spot/portal-theme'
2
- import { useState } from 'react'
2
+ import { Children, useMemo, useState } from 'react'
3
3
  import { useCitricController } from '../context/hooks'
4
4
  import { WithColorScheme } from '../types'
5
5
  import { withRef } from '../utils/react'
@@ -48,12 +48,27 @@ export interface BaseButtonProps extends WithColorScheme {
48
48
 
49
49
  export type ButtonProps = Omit<React.JSX.IntrinsicElements['button'], 'onClick'> & BaseButtonProps
50
50
 
51
+ /**
52
+ * Renders a button. The type is "button" by default.
53
+ *
54
+ * Whenever a button is clicked, the function `onClickButton` of the nearest CitricController is called with the event and the value of the
55
+ * prop `analytics`.
56
+ *
57
+ * @example
58
+ * ```
59
+ * <Button>My Button</MyButton>
60
+ * ```
61
+ */
51
62
  export const Button = withRef((
52
63
  { appearance, size, feedback, loading, disabled, onClick, className, children, type = 'button', analytics, ...props }: ButtonProps,
53
64
  ) => {
54
65
  const citric = useCitricController()
55
66
  const [waiting, setWaiting] = useState(false)
56
67
  const busy = loading || waiting
68
+ const isAllLowercase = useMemo(
69
+ () => !Children.toArray(children).some(c => typeof c === 'string' && c.toLocaleLowerCase() !== c),
70
+ [children],
71
+ )
57
72
 
58
73
  async function handleClick(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
59
74
  const result = onClick?.(e)
@@ -71,7 +86,7 @@ export const Button = withRef((
71
86
  <CitricComponent
72
87
  tag="button"
73
88
  component="button"
74
- className={listToClass([size, appearance, className])}
89
+ className={listToClass([size, appearance, isAllLowercase && 'short-text', className])}
75
90
  data-feedback={feedback || undefined}
76
91
  onClick={handleClick}
77
92
  aria-busy={busy}
@@ -3,13 +3,15 @@ import { WithColorScheme } from '../types'
3
3
  import { withRef } from '../utils/react'
4
4
  import { CitricComponent } from './CitricComponent'
5
5
 
6
- export interface BaseCardProps extends WithColorScheme {
6
+ type SupportedTags = 'div' | 'header' | 'ul' | 'ol' | 'dl' | 'section' | 'article' | 'a' | 'button'
7
+
8
+ export interface BaseCardProps<T extends SupportedTags = SupportedTags> extends WithColorScheme {
7
9
  /**
8
10
  * HTML tag to render.
9
11
  *
10
12
  * @default 'div'
11
13
  */
12
- tag?: 'div' | 'header' | 'ul' | 'ol' | 'dl' | 'section' | 'article',
14
+ tag?: T,
13
15
  onClick?: (event: React.MouseEvent<HTMLDivElement>) => void,
14
16
  /**
15
17
  * The size of the card.
@@ -25,16 +27,34 @@ export interface BaseCardProps extends WithColorScheme {
25
27
  bgLevel?: 300 | 400 | 500 | 600,
26
28
  }
27
29
 
28
- export type CardProps = React.JSX.IntrinsicElements['div'] & BaseCardProps
30
+ // applying conditionals to the type in order to increase TS performance. Ideally we'd use React.JSX.IntrinsicElements[T].
31
+ export type CardProps<T extends SupportedTags> = (
32
+ T extends 'a' ? React.JSX.IntrinsicElements['a'] : (
33
+ T extends 'button' ? React.JSX.IntrinsicElements['button'] :
34
+ React.JSX.IntrinsicElements['div'])) & BaseCardProps
29
35
 
30
- export const Card = withRef(({ tag = 'div', onClick, size, bgLevel, className, children, ...props }: CardProps) => (
31
- <CitricComponent
32
- tag={tag}
33
- component="card"
34
- onClick={onClick}
35
- className={listToClass([onClick && 'clickable', size, bgLevel && `bg-${bgLevel}`, className])}
36
- {...props}
37
- >
38
- {children}
39
- </CitricComponent>
40
- ))
36
+ /**
37
+ * Renders a box with padding, border and background-color. If the card is focusable or has an onClick listener, hover events are also
38
+ * present.
39
+ *
40
+ * @example
41
+ * ```
42
+ * <Card>The card content</Card>
43
+ * ```
44
+ */
45
+ export const Card = withRef(
46
+ function Card<T extends SupportedTags>({ tag = 'div', onClick, size, bgLevel, className, children, ...props }: CardProps<T>) {
47
+ const clickable = onClick || props.tabIndex === 0 || tag === 'button' || tag === 'a'
48
+ return (
49
+ <CitricComponent
50
+ tag={tag}
51
+ component="card"
52
+ onClick={onClick}
53
+ className={listToClass([clickable && 'clickable', size, bgLevel && `bg-${bgLevel}`, className])}
54
+ {...props}
55
+ >
56
+ {children}
57
+ </CitricComponent>
58
+ )
59
+ },
60
+ )
@@ -15,6 +15,20 @@ export interface BaseCheckboxProps extends WithColorScheme {
15
15
 
16
16
  export type CheckboxProps = ControlledInput & BaseCheckboxProps
17
17
 
18
+ /**
19
+ * Renders a simple checkbox. If you want to render multiple checkboxes to control the value of multi-selectable field, prefer using the
20
+ * component `CheckboxGroup`.
21
+ *
22
+ * Attention: the prop `onChange` receives a boolean (current value) instead of the event.
23
+ *
24
+ * A checkbox can also be a switch! Just change the property "appearance".
25
+ *
26
+ * @example
27
+ * ```
28
+ * const [value, setValue] = useState(false)
29
+ * return <Checkbox value={value} setValue={setValue}>This is the checkbox label</Checkbox>
30
+ * ```
31
+ */
18
32
  export const Checkbox = withRef((
19
33
  { appearance = 'checkbox', value, onChange, colorScheme, children, className, style, ...props }: CheckboxProps,
20
34
  ) => {
@@ -72,43 +72,64 @@ export interface BaseCheckboxGroupProps<T = any> extends WithColorScheme {
72
72
 
73
73
  export type CheckboxGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseCheckboxGroupProps<T>
74
74
 
75
- function _CheckboxGroup<T>({
76
- appearance = 'checkbox',
77
- name,
78
- value = [],
79
- options,
80
- onChange,
81
- renderLabel = defaultRenderLabel,
82
- renderKey = defaultRenderKey,
83
- renderItem,
84
- isDisabled,
85
- colorScheme,
86
- style,
87
- ...props
88
- }: CheckboxGroupProps<T>) {
89
- const items = useMemo(() => {
90
- const valueKeys = value.map(renderKey)
91
- return options.map((o) => {
92
- const key = renderKey(o)
93
- const checkbox = <CitricComponent
94
- tag="input"
95
- component={appearance}
96
- type="checkbox"
97
- name={name}
98
- value={key}
99
- checked={value.includes(o) || (!isNil(key) && valueKeys.includes(key))}
100
- onChange={(e) => onChange?.(e.target.checked ? [...(value ?? []), o] : (value?.filter(item => item != o) ?? []))}
101
- disabled={isDisabled?.(o)}
102
- />
103
- return renderItem ? renderItem(checkbox, o) : (
104
- <CitricComponent tag="label" component={`${appearance}-row`} key={key} colorScheme={colorScheme}>
105
- {checkbox}
106
- {renderLabel(o)}
107
- </CitricComponent>
108
- )
109
- })
110
- }, [options, value, name, colorScheme, appearance])
111
- return <Column {...props} style={{ gap: '8px', ...style }}>{items}</Column>
112
- }
113
-
114
- export const CheckboxGroup = withRef(_CheckboxGroup)
75
+ /**
76
+ * Renders a list of checkbox for multi-selection. One checkbox is rendered for each option.
77
+ *
78
+ * This component can be heavily customized via its properties. Check the storybook for complex examples.
79
+ *
80
+ * Tip: if you need to implement features like "search" and "select all", use the hook `useCheckboxGroupControls`.
81
+ *
82
+ * @example
83
+ *
84
+ * ```
85
+ * const options = useMemo(() => [
86
+ * { id: 1, name: 'Option 1' },
87
+ * { id: 2, name: 'Option 2' },
88
+ * { id: 3, name: 'Option 3' },
89
+ * ], [])
90
+ *
91
+ * const [value, setValue] = useState<typeof options>([])
92
+ *
93
+ * return <CheckboxGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
94
+ * ```
95
+ */
96
+ export const CheckboxGroup = withRef(
97
+ function CheckboxGroup<T>({
98
+ appearance = 'checkbox',
99
+ name,
100
+ value = [],
101
+ options,
102
+ onChange,
103
+ renderLabel = defaultRenderLabel,
104
+ renderKey = defaultRenderKey,
105
+ renderItem,
106
+ isDisabled,
107
+ colorScheme,
108
+ style,
109
+ ...props
110
+ }: CheckboxGroupProps<T>) {
111
+ const items = useMemo(() => {
112
+ const valueKeys = value.map(renderKey)
113
+ return options.map((o) => {
114
+ const key = renderKey(o)
115
+ const checkbox = <CitricComponent
116
+ tag="input"
117
+ component={appearance}
118
+ type="checkbox"
119
+ name={name}
120
+ value={key}
121
+ checked={value.includes(o) || (!isNil(key) && valueKeys.includes(key))}
122
+ onChange={(e) => onChange?.(e.target.checked ? [...(value ?? []), o] : (value?.filter(item => item != o) ?? []))}
123
+ disabled={isDisabled?.(o)}
124
+ />
125
+ return renderItem ? renderItem(checkbox, o) : (
126
+ <CitricComponent tag="label" component={`${appearance}-row`} key={key} colorScheme={colorScheme}>
127
+ {checkbox}
128
+ {renderLabel(o)}
129
+ </CitricComponent>
130
+ )
131
+ })
132
+ }, [options, value, name, colorScheme, appearance])
133
+ return <Column {...props} style={{ gap: '8px', ...style }}>{items}</Column>
134
+ },
135
+ )
@@ -13,6 +13,14 @@ export interface BaseCircleProps extends WithColorPalette, WithColorScheme {
13
13
  /**
14
14
  * The size of the circle.
15
15
  *
16
+ * - xxs: 8px;
17
+ * - xs: 12px;
18
+ * - sm: 18px;
19
+ * - md: 27px;
20
+ * - lg: 40px;
21
+ * - xl: 60px;
22
+ * - xxl: 90px.
23
+ *
16
24
  * @default 'xs'
17
25
  */
18
26
  size?: 'xxs' | 'xs' | 'sm' | 'lg' | 'xl' | 'xxl',
@@ -20,6 +28,14 @@ export interface BaseCircleProps extends WithColorPalette, WithColorScheme {
20
28
 
21
29
  export type CircleProps = React.JSX.IntrinsicElements['div'] & BaseCircleProps
22
30
 
31
+ /**
32
+ * Renders a simple circle. If the circle has any children, it gets cropped by the circle borders. The content of the circle is centered.
33
+ *
34
+ * @example
35
+ * ```
36
+ * <Circle colorScheme="success" />
37
+ * ```
38
+ */
23
39
  export const Circle = withRef(({ showBorders, className, size, children, ...props }: CircleProps) => (
24
40
  <CitricComponent tag="div" component="circle" className={listToClass([className, showBorders && 'bordered', size])} {...props}>
25
41
  {children}
@@ -24,6 +24,20 @@ export function asCitricProps({ colorScheme, colorPalette, component, ...props }
24
24
  return citricProps
25
25
  }
26
26
 
27
+ /**
28
+ * Renders any tag or component with the appearance of a Citric Component.
29
+ *
30
+ * @example
31
+ * An anchor that looks like a card.
32
+ * ```
33
+ * <CitricComponent tag="a" component="card" href="https://www.google.com" target="_blank">This is a card link</CitricComponent>
34
+ * ```
35
+ *
36
+ * Suppose we have a component called "MyComponent" that accepts the property "myProp". We can make it look like a citric component:
37
+ * ```
38
+ * <CitricComponent render={MyComponent} component="card" myProp="my value" />
39
+ * ```
40
+ */
27
41
  // eslint-disable-next-line react/display-name
28
42
  export const CitricComponent: CitricComponentType = forwardRef<any, any>(
29
43
  (props, ref) => {
@@ -16,8 +16,9 @@ export interface BaseDividerProps extends WithColorScheme {
16
16
 
17
17
  export type DividerProps = React.JSX.IntrinsicElements['hr'] & BaseDividerProps
18
18
 
19
- export const Divider = withRef(({ size, direction, className, children, ...props }: DividerProps) => (
20
- <CitricComponent tag="hr" component="divider" className={listToClass([className, size, direction])} {...props}>
21
- {children}
22
- </CitricComponent>
23
- ))
19
+ /**
20
+ * Renders a divider (hr). "size" determines how thick the ruler is and "direction" places it on the vertical or horizontal axis.
21
+ */
22
+ export const Divider = withRef(({ size, direction, className, ...props }: DividerProps) =>
23
+ <CitricComponent tag="hr" component="divider" className={listToClass([className, size, direction])} {...props} />,
24
+ )
@@ -18,6 +18,19 @@ interface Props {
18
18
 
19
19
  /**
20
20
  * An Error Boundary that renders an error feedback instead of its content if any of its children throws.
21
+ *
22
+ * You can customize the appearance of the error through the function `renderError` of a CitricController.
23
+ *
24
+ * Errors can be watched through the function `onError` of a CitricController.
25
+ *
26
+ * Attention: if you're using React Suspense, consider using the component "FallbackBoundary" instead.
27
+ *
28
+ * @example
29
+ * ```
30
+ * <ErrorBoundary>
31
+ * {content}
32
+ * </ErrorBoundary>
33
+ * ```
21
34
  */
22
35
  export class ErrorBoundary extends Component<Props, State> {
23
36
  static contextType = CitricContext
@@ -6,6 +6,6 @@ import { Text } from './Text'
6
6
  export const ErrorMessage = ({ error }: { error: any }) => (
7
7
  <Row gap="18px" p="20px" justifyContent="center">
8
8
  <Icon icon="TimesCircle" size="xl" style={{ color: theme.color.danger[500] }} />
9
- <Text style={{ margin: '80px' }}>{error.message || `${error}`}</Text>
9
+ <Text>{error.message || `${error}`}</Text>
10
10
  </Row>
11
11
  )
@@ -18,7 +18,18 @@ const loading = (
18
18
  )
19
19
 
20
20
  /**
21
- * Fallbacks for errors and loadings (suspense).
21
+ * A Boundary that renders an error feedback if a child throws an error or a loading feedback if it suspends.
22
+ *
23
+ * You can customize the appearance of the loading and error views through a CitricController.
24
+ *
25
+ * Errors can be watched through the function `onError` of a CitricController.
26
+ *
27
+ * @example
28
+ * ```
29
+ * <FallbackBoundary>
30
+ * {content}
31
+ * </FallbackBoundary>
32
+ * ```
22
33
  */
23
34
  export const FallbackBoundary = ({ children, message }: Props) => (
24
35
  <ErrorBoundary message={message}>
@@ -30,6 +30,18 @@ export interface BaseFavoriteProps {
30
30
 
31
31
  export type FavoriteProps = Omit<ControlledInput, 'size'> & BaseFavoriteProps
32
32
 
33
+ /**
34
+ * Renders a checkbox with the appearance of a favorite button. If unchecked, the stroke of a star is rendered, when checked, a filled
35
+ * yellow star is rendered.
36
+ *
37
+ * You can also set a loading state to indicate the component is busy.
38
+ *
39
+ * @example
40
+ * ```
41
+ * const { isFavorite, setFavorite, isLoading } = useRemoteFavoriteStatus()
42
+ * return <Favorite value={isFavorite} onChange={setFavorite} loading={isLoading} />
43
+ * ```
44
+ */
33
45
  export const Favorite = withRef(({ value, size, appearance, onChange, loading, disabled, className, ...props }: FavoriteProps) =>
34
46
  <CitricComponent
35
47
  tag="input"
@@ -21,6 +21,19 @@ export interface BaseFieldGroupProps {
21
21
 
22
22
  export type FieldGroupProps = React.JSX.IntrinsicElements['div'] & BaseFieldGroupProps
23
23
 
24
+ /**
25
+ * A FieldGroup is used to concatenate an input with other UI elements, like icons and buttons.
26
+ *
27
+ * @example
28
+ * A search field, with a search icon and a button to submit the search.
29
+ * ```
30
+ * <FieldGroup>
31
+ * <Icon icon="Search" />
32
+ * <Input type="search" />
33
+ * <Button colorScheme="light">Submit</Button>
34
+ * </FieldGroup>
35
+ * ```
36
+ */
24
37
  export const FieldGroup = withRef(({ auto = true, fullWidth, className, children, ...props }: FieldGroupProps) => (
25
38
  <CitricComponent
26
39
  tag="div"