@stack-spot/citric-react 0.35.1 → 0.37.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 (186) hide show
  1. package/dist/citric.css +2844 -2832
  2. package/dist/components/Accordion.d.ts +1 -1
  3. package/dist/components/Accordion.js +1 -1
  4. package/dist/components/Alert.d.ts +1 -1
  5. package/dist/components/Alert.js +1 -1
  6. package/dist/components/AsyncContent.d.ts +1 -1
  7. package/dist/components/AsyncContent.js +1 -1
  8. package/dist/components/Avatar.d.ts +1 -1
  9. package/dist/components/Avatar.js +1 -1
  10. package/dist/components/AvatarGroup.d.ts +1 -1
  11. package/dist/components/AvatarGroup.js +1 -1
  12. package/dist/components/Badge.d.ts +1 -1
  13. package/dist/components/Badge.js +1 -1
  14. package/dist/components/Blockquote.d.ts +1 -1
  15. package/dist/components/Blockquote.js +1 -1
  16. package/dist/components/Breadcrumb.d.ts +1 -1
  17. package/dist/components/Breadcrumb.js +1 -1
  18. package/dist/components/Button.d.ts +1 -1
  19. package/dist/components/Button.js +1 -1
  20. package/dist/components/ButtonLink.d.ts +1 -1
  21. package/dist/components/ButtonLink.js +1 -1
  22. package/dist/components/Card.d.ts +1 -1
  23. package/dist/components/Card.js +1 -1
  24. package/dist/components/Checkbox.d.ts +1 -1
  25. package/dist/components/Checkbox.js +1 -1
  26. package/dist/components/CheckboxGroup.d.ts +1 -1
  27. package/dist/components/CheckboxGroup.js +1 -1
  28. package/dist/components/Circle.d.ts +1 -1
  29. package/dist/components/Circle.js +1 -1
  30. package/dist/components/Divider.d.ts +1 -1
  31. package/dist/components/Divider.js +1 -1
  32. package/dist/components/ErrorBoundary.d.ts +1 -1
  33. package/dist/components/ErrorBoundary.js +1 -1
  34. package/dist/components/ErrorMessage.d.ts +1 -1
  35. package/dist/components/ErrorMessage.js +1 -1
  36. package/dist/components/FallbackBoundary.d.ts +1 -1
  37. package/dist/components/FallbackBoundary.js +1 -1
  38. package/dist/components/Favorite.d.ts +1 -1
  39. package/dist/components/Favorite.js +1 -1
  40. package/dist/components/FieldGroup.d.ts +1 -1
  41. package/dist/components/FieldGroup.js +1 -1
  42. package/dist/components/Form.d.ts +2 -2
  43. package/dist/components/Form.js +1 -1
  44. package/dist/components/FormGroup.d.ts +1 -1
  45. package/dist/components/FormGroup.js +1 -1
  46. package/dist/components/Icon.d.ts +1 -1
  47. package/dist/components/Icon.js +1 -1
  48. package/dist/components/IconBox.d.ts +3 -3
  49. package/dist/components/IconBox.js +1 -1
  50. package/dist/components/ImageBox.d.ts +3 -3
  51. package/dist/components/ImageBox.js +1 -1
  52. package/dist/components/ImageWithFallback.d.ts +1 -1
  53. package/dist/components/ImageWithFallback.js +1 -1
  54. package/dist/components/Input.d.ts +1 -1
  55. package/dist/components/Input.js +1 -1
  56. package/dist/components/Link.d.ts +1 -1
  57. package/dist/components/Link.js +1 -1
  58. package/dist/components/LoadingPanel.d.ts +1 -1
  59. package/dist/components/LoadingPanel.js +1 -1
  60. package/dist/components/MenuOverlay/Menu.d.ts +1 -1
  61. package/dist/components/MenuOverlay/Menu.js +1 -1
  62. package/dist/components/MenuOverlay/index.d.ts +1 -1
  63. package/dist/components/MenuOverlay/index.js +1 -1
  64. package/dist/components/Overlay/index.d.ts +1 -1
  65. package/dist/components/Overlay/index.js +1 -1
  66. package/dist/components/Pagination.d.ts +1 -1
  67. package/dist/components/Pagination.js +1 -1
  68. package/dist/components/ProgressBar.d.ts +1 -1
  69. package/dist/components/ProgressBar.js +1 -1
  70. package/dist/components/ProgressCircular.d.ts +1 -1
  71. package/dist/components/ProgressCircular.js +1 -1
  72. package/dist/components/RadioGroup.d.ts +1 -1
  73. package/dist/components/RadioGroup.js +1 -1
  74. package/dist/components/Rating.d.ts +17 -3
  75. package/dist/components/Rating.d.ts.map +1 -1
  76. package/dist/components/Rating.js +11 -3
  77. package/dist/components/Rating.js.map +1 -1
  78. package/dist/components/Select/MultiSelect.d.ts +1 -1
  79. package/dist/components/Select/MultiSelect.js +1 -1
  80. package/dist/components/Select/RichSelect.d.ts +1 -1
  81. package/dist/components/Select/RichSelect.js +1 -1
  82. package/dist/components/Select/SimpleSelect.d.ts +1 -1
  83. package/dist/components/Select/SimpleSelect.js +1 -1
  84. package/dist/components/Select/index.d.ts +1 -1
  85. package/dist/components/Select/index.js +1 -1
  86. package/dist/components/SelectBox.d.ts +1 -1
  87. package/dist/components/SelectBox.js +1 -1
  88. package/dist/components/Skeleton.d.ts +1 -1
  89. package/dist/components/Skeleton.js +1 -1
  90. package/dist/components/Slider.d.ts +1 -1
  91. package/dist/components/Slider.js +1 -1
  92. package/dist/components/SmartTable.d.ts +1 -1
  93. package/dist/components/SmartTable.js +1 -1
  94. package/dist/components/Stepper.d.ts +1 -1
  95. package/dist/components/Stepper.js +1 -1
  96. package/dist/components/Table.d.ts +3 -3
  97. package/dist/components/Table.js +1 -1
  98. package/dist/components/Tabs/index.d.ts +1 -1
  99. package/dist/components/Tabs/index.js +1 -1
  100. package/dist/components/Textarea.d.ts +1 -1
  101. package/dist/components/Textarea.js +1 -1
  102. package/dist/components/Tooltip.d.ts +1 -1
  103. package/dist/components/Tooltip.js +1 -1
  104. package/dist/context/CitricProvider.d.ts +1 -1
  105. package/dist/context/CitricProvider.js +1 -1
  106. package/dist/overlay.js +1 -1
  107. package/dist/theme.css +415 -415
  108. package/package.json +7 -6
  109. package/scripts/build-css.ts +49 -49
  110. package/src/components/Accordion.tsx +130 -130
  111. package/src/components/Alert.tsx +24 -24
  112. package/src/components/AsyncContent.tsx +70 -70
  113. package/src/components/Avatar.tsx +45 -45
  114. package/src/components/AvatarGroup.tsx +49 -49
  115. package/src/components/Badge.tsx +47 -47
  116. package/src/components/Blockquote.tsx +18 -18
  117. package/src/components/Breadcrumb.tsx +33 -33
  118. package/src/components/Button.tsx +105 -105
  119. package/src/components/ButtonLink.tsx +45 -45
  120. package/src/components/Card.tsx +68 -68
  121. package/src/components/Checkbox.tsx +51 -51
  122. package/src/components/CheckboxGroup.tsx +152 -152
  123. package/src/components/Circle.tsx +43 -43
  124. package/src/components/CitricComponent.ts +47 -47
  125. package/src/components/Divider.tsx +24 -24
  126. package/src/components/ErrorBoundary.tsx +75 -75
  127. package/src/components/ErrorMessage.tsx +11 -11
  128. package/src/components/FallbackBoundary.tsx +40 -40
  129. package/src/components/Favorite.tsx +57 -57
  130. package/src/components/FieldGroup.tsx +46 -46
  131. package/src/components/Form.tsx +36 -36
  132. package/src/components/FormGroup.tsx +57 -57
  133. package/src/components/Icon.tsx +35 -35
  134. package/src/components/IconBox.tsx +134 -134
  135. package/src/components/ImageBox.tsx +125 -125
  136. package/src/components/ImageWithFallback.tsx +65 -65
  137. package/src/components/Input.tsx +49 -49
  138. package/src/components/Link.tsx +55 -55
  139. package/src/components/LoadingPanel.tsx +8 -8
  140. package/src/components/MenuOverlay/Menu.tsx +158 -158
  141. package/src/components/MenuOverlay/context.ts +20 -20
  142. package/src/components/MenuOverlay/index.tsx +55 -55
  143. package/src/components/MenuOverlay/keyboard.ts +60 -60
  144. package/src/components/MenuOverlay/types.ts +171 -171
  145. package/src/components/Overlay/context.ts +10 -10
  146. package/src/components/Overlay/index.tsx +164 -164
  147. package/src/components/Overlay/types.ts +70 -70
  148. package/src/components/Pagination.tsx +113 -113
  149. package/src/components/ProgressBar.tsx +45 -45
  150. package/src/components/ProgressCircular.tsx +45 -45
  151. package/src/components/RadioGroup.tsx +146 -146
  152. package/src/components/Rating.tsx +98 -35
  153. package/src/components/Select/MultiSelect.tsx +217 -217
  154. package/src/components/Select/RichSelect.tsx +128 -128
  155. package/src/components/Select/SimpleSelect.tsx +73 -73
  156. package/src/components/Select/hooks.ts +133 -133
  157. package/src/components/Select/index.tsx +35 -35
  158. package/src/components/Select/types.ts +134 -134
  159. package/src/components/SelectBox.tsx +167 -167
  160. package/src/components/Skeleton.tsx +53 -53
  161. package/src/components/Slider.tsx +89 -89
  162. package/src/components/SmartTable.tsx +227 -227
  163. package/src/components/Stepper.tsx +163 -163
  164. package/src/components/Table.tsx +234 -234
  165. package/src/components/Tabs/TabController.ts +54 -54
  166. package/src/components/Tabs/index.tsx +87 -87
  167. package/src/components/Tabs/types.ts +54 -54
  168. package/src/components/Tabs/utils.ts +6 -6
  169. package/src/components/Text.ts +111 -111
  170. package/src/components/Textarea.tsx +27 -27
  171. package/src/components/Tooltip.tsx +72 -72
  172. package/src/components/layout.tsx +101 -101
  173. package/src/context/CitricContext.tsx +4 -4
  174. package/src/context/CitricProvider.tsx +14 -14
  175. package/src/context/hooks.ts +6 -6
  176. package/src/index.ts +58 -58
  177. package/src/overlay.ts +341 -341
  178. package/src/types.ts +216 -216
  179. package/src/utils/ValueController.ts +28 -28
  180. package/src/utils/acessibility.ts +92 -92
  181. package/src/utils/checkbox.ts +121 -121
  182. package/src/utils/css.ts +119 -119
  183. package/src/utils/options.ts +9 -9
  184. package/src/utils/radio.ts +93 -93
  185. package/src/utils/react.ts +6 -6
  186. package/tsconfig.json +10 -10
@@ -1,45 +1,45 @@
1
- import { listToClass } from '@stack-spot/portal-theme'
2
- import { Children, useMemo } from 'react'
3
- import { useCitricController } from '../context/hooks'
4
- import { withRef } from '../utils/react'
5
- import { BaseButtonProps } from './Button'
6
- import { asCitricProps, CitricComponent } from './CitricComponent'
7
-
8
- export type BaseButtonLinkProps = Omit<BaseButtonProps, 'onClick' | 'loading' | 'type'>
9
- export type ButtonLinkProps = React.JSX.IntrinsicElements['a'] & BaseButtonLinkProps
10
-
11
- /**
12
- * Renders a link with the appearance of a button.
13
- *
14
- * Whenever a link is clicked, the function `onClickLink` of the nearest CitricController is called with the event and the value of the
15
- * prop `metadata`.
16
- *
17
- * @example
18
- * ```
19
- * <ButtonLink href="#">My Button Link</ButtonLink>
20
- * ```
21
- */
22
- export const ButtonLink = withRef((
23
- { appearance, size, feedback, onClick, className, children, metadata, ...props }: ButtonLinkProps,
24
- ) => {
25
- const citric = useCitricController()
26
- const isAllLowercase = useMemo(
27
- () => !Children.toArray(children).some(c => typeof c === 'string' && c.toLocaleLowerCase() !== c),
28
- [children],
29
- )
30
-
31
- const linkProps = {
32
- component: 'button',
33
- className: listToClass([size, appearance, isAllLowercase && 'short-text', className]),
34
- onClick: (e: React.MouseEvent<HTMLAnchorElement>) => {
35
- onClick?.(e)
36
- citric?.onClickLink?.(e, metadata)
37
- },
38
- 'data-feedback': feedback || undefined,
39
- ...props,
40
- } as const
41
-
42
- return citric?.renderLink
43
- ? citric.renderLink(asCitricProps({ ...linkProps, children }))
44
- : <CitricComponent tag="a" {...linkProps}>{children}</CitricComponent>
45
- })
1
+ import { listToClass } from '@stack-spot/portal-theme'
2
+ import { Children, useMemo } from 'react'
3
+ import { useCitricController } from '../context/hooks'
4
+ import { withRef } from '../utils/react'
5
+ import { BaseButtonProps } from './Button'
6
+ import { asCitricProps, CitricComponent } from './CitricComponent'
7
+
8
+ export type BaseButtonLinkProps = Omit<BaseButtonProps, 'onClick' | 'loading' | 'type'>
9
+ export type ButtonLinkProps = React.JSX.IntrinsicElements['a'] & BaseButtonLinkProps
10
+
11
+ /**
12
+ * Renders a link with the appearance of a button.
13
+ *
14
+ * Whenever a link is clicked, the function `onClickLink` of the nearest CitricController is called with the event and the value of the
15
+ * prop `metadata`.
16
+ *
17
+ * @example
18
+ * ```
19
+ * <ButtonLink href="#">My Button Link</ButtonLink>
20
+ * ```
21
+ */
22
+ export const ButtonLink = withRef((
23
+ { appearance, size, feedback, onClick, className, children, metadata, ...props }: ButtonLinkProps,
24
+ ) => {
25
+ const citric = useCitricController()
26
+ const isAllLowercase = useMemo(
27
+ () => !Children.toArray(children).some(c => typeof c === 'string' && c.toLocaleLowerCase() !== c),
28
+ [children],
29
+ )
30
+
31
+ const linkProps = {
32
+ component: 'button',
33
+ className: listToClass([size, appearance, isAllLowercase && 'short-text', className]),
34
+ onClick: (e: React.MouseEvent<HTMLAnchorElement>) => {
35
+ onClick?.(e)
36
+ citric?.onClickLink?.(e, metadata)
37
+ },
38
+ 'data-feedback': feedback || undefined,
39
+ ...props,
40
+ } as const
41
+
42
+ return citric?.renderLink
43
+ ? citric.renderLink(asCitricProps({ ...linkProps, children }))
44
+ : <CitricComponent tag="a" {...linkProps}>{children}</CitricComponent>
45
+ })
@@ -1,68 +1,68 @@
1
- import { listToClass } from '@stack-spot/portal-theme'
2
- import { useCitricController } from '../context/hooks'
3
- import { WithColorScheme, WithStyleShortcuts } from '../types'
4
- import { applyStyles } from '../utils/css'
5
- import { withRef } from '../utils/react'
6
- import { asCitricProps, CitricComponent } from './CitricComponent'
7
-
8
- type SupportedTags = 'div' | 'header' | 'ul' | 'ol' | 'dl' | 'section' | 'article' | 'a' | 'button' | 'header'
9
-
10
- export interface BaseCardProps<T extends SupportedTags = SupportedTags> extends WithColorScheme, Omit<WithStyleShortcuts, 'bg'> {
11
- /**
12
- * HTML tag to render.
13
- *
14
- * @default 'div'
15
- */
16
- tag?: T,
17
- onClick?: (event: React.MouseEvent<HTMLDivElement>) => void,
18
- /**
19
- * The size of the card.
20
- *
21
- * @default 'md'
22
- */
23
- size?: 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl',
24
- /**
25
- * The background color level. The main color will depend on the "colorScheme", which is "light" by default.
26
- *
27
- * @default 300
28
- */
29
- bgLevel?: 300 | 400 | 500 | 600,
30
- /**
31
- * The direction of the items in the card.
32
- *
33
- * @default column
34
- */
35
- direction?: 'column' | 'row',
36
- }
37
-
38
- // applying conditionals to the type in order to increase TS performance. Ideally we'd use React.JSX.IntrinsicElements[T].
39
- export type CardProps<T extends SupportedTags> = (
40
- T extends 'a' ? React.JSX.IntrinsicElements['a'] : (
41
- T extends 'button' ? React.JSX.IntrinsicElements['button'] :
42
- React.JSX.IntrinsicElements['div'])) & BaseCardProps
43
-
44
- /**
45
- * Renders a box with padding, border and background-color. If the card is focusable or has an onClick listener, hover events are also
46
- * present.
47
- *
48
- * @example
49
- * ```
50
- * <Card>The card content</Card>
51
- * ```
52
- */
53
- export const Card = withRef(
54
- function Card<T extends SupportedTags>({ tag = 'div', onClick, size, bgLevel, className, children, direction, ...props }: CardProps<T>) {
55
- const citric = useCitricController()
56
- const clickable = onClick || props.tabIndex === 0 || tag === 'button' || tag === 'a'
57
- const componentProps = {
58
- tag,
59
- component: 'card',
60
- onClick,
61
- className: listToClass([clickable && 'clickable', size, bgLevel && `bg-${bgLevel}`, direction, className]),
62
- ...applyStyles(props),
63
- } as const
64
- return tag === 'a' && citric?.renderLink
65
- ? citric.renderLink(asCitricProps(componentProps))
66
- : <CitricComponent {...componentProps}>{children}</CitricComponent>
67
- },
68
- )
1
+ import { listToClass } from '@stack-spot/portal-theme'
2
+ import { useCitricController } from '../context/hooks'
3
+ import { WithColorScheme, WithStyleShortcuts } from '../types'
4
+ import { applyStyles } from '../utils/css'
5
+ import { withRef } from '../utils/react'
6
+ import { asCitricProps, CitricComponent } from './CitricComponent'
7
+
8
+ type SupportedTags = 'div' | 'header' | 'ul' | 'ol' | 'dl' | 'section' | 'article' | 'a' | 'button' | 'header'
9
+
10
+ export interface BaseCardProps<T extends SupportedTags = SupportedTags> extends WithColorScheme, Omit<WithStyleShortcuts, 'bg'> {
11
+ /**
12
+ * HTML tag to render.
13
+ *
14
+ * @default 'div'
15
+ */
16
+ tag?: T,
17
+ onClick?: (event: React.MouseEvent<HTMLDivElement>) => void,
18
+ /**
19
+ * The size of the card.
20
+ *
21
+ * @default 'md'
22
+ */
23
+ size?: 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl',
24
+ /**
25
+ * The background color level. The main color will depend on the "colorScheme", which is "light" by default.
26
+ *
27
+ * @default 300
28
+ */
29
+ bgLevel?: 300 | 400 | 500 | 600,
30
+ /**
31
+ * The direction of the items in the card.
32
+ *
33
+ * @default column
34
+ */
35
+ direction?: 'column' | 'row',
36
+ }
37
+
38
+ // applying conditionals to the type in order to increase TS performance. Ideally we'd use React.JSX.IntrinsicElements[T].
39
+ export type CardProps<T extends SupportedTags> = (
40
+ T extends 'a' ? React.JSX.IntrinsicElements['a'] : (
41
+ T extends 'button' ? React.JSX.IntrinsicElements['button'] :
42
+ React.JSX.IntrinsicElements['div'])) & BaseCardProps
43
+
44
+ /**
45
+ * Renders a box with padding, border and background-color. If the card is focusable or has an onClick listener, hover events are also
46
+ * present.
47
+ *
48
+ * @example
49
+ * ```
50
+ * <Card>The card content</Card>
51
+ * ```
52
+ */
53
+ export const Card = withRef(
54
+ function Card<T extends SupportedTags>({ tag = 'div', onClick, size, bgLevel, className, children, direction, ...props }: CardProps<T>) {
55
+ const citric = useCitricController()
56
+ const clickable = onClick || props.tabIndex === 0 || tag === 'button' || tag === 'a'
57
+ const componentProps = {
58
+ tag,
59
+ component: 'card',
60
+ onClick,
61
+ className: listToClass([clickable && 'clickable', size, bgLevel && `bg-${bgLevel}`, direction, className]),
62
+ ...applyStyles(props),
63
+ } as const
64
+ return tag === 'a' && citric?.renderLink
65
+ ? citric.renderLink(asCitricProps(componentProps))
66
+ : <CitricComponent {...componentProps}>{children}</CitricComponent>
67
+ },
68
+ )
@@ -1,51 +1,51 @@
1
- import { ControlledInput, WithColorScheme } from '../types'
2
- import { withRef } from '../utils/react'
3
- import { CitricComponent } from './CitricComponent'
4
-
5
- export interface BaseCheckboxProps extends WithColorScheme {
6
- /**
7
- * "checkbox" for common check boxes, "switch" for toggles.
8
- * @default 'checkbox'
9
- */
10
- appearance?: 'checkbox' | 'switch',
11
- value?: boolean,
12
- onChange?: (value: boolean) => void,
13
- children?: React.ReactNode,
14
- }
15
-
16
- export type CheckboxProps = ControlledInput & BaseCheckboxProps
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
- */
32
- export const Checkbox = withRef((
33
- { appearance = 'checkbox', value, onChange, colorScheme, children, className, style, ...props }: CheckboxProps,
34
- ) => {
35
- const handleChange = onChange ? () => onChange(!value) : undefined
36
- return children ? (
37
- <CitricComponent tag="label" component={`${appearance}-row`} colorScheme={colorScheme} style={style} className={className}>
38
- <input type="checkbox" checked={value} onChange={handleChange} {...props} />
39
- {children}
40
- </CitricComponent>
41
- ) : <CitricComponent
42
- tag="input"
43
- type="checkbox"
44
- component={appearance}
45
- checked={value}
46
- onChange={handleChange}
47
- className={className}
48
- style={style}
49
- {...props}
50
- />
51
- })
1
+ import { ControlledInput, WithColorScheme } from '../types'
2
+ import { withRef } from '../utils/react'
3
+ import { CitricComponent } from './CitricComponent'
4
+
5
+ export interface BaseCheckboxProps extends WithColorScheme {
6
+ /**
7
+ * "checkbox" for common check boxes, "switch" for toggles.
8
+ * @default 'checkbox'
9
+ */
10
+ appearance?: 'checkbox' | 'switch',
11
+ value?: boolean,
12
+ onChange?: (value: boolean) => void,
13
+ children?: React.ReactNode,
14
+ }
15
+
16
+ export type CheckboxProps = ControlledInput & BaseCheckboxProps
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
+ */
32
+ export const Checkbox = withRef((
33
+ { appearance = 'checkbox', value, onChange, colorScheme, children, className, style, ...props }: CheckboxProps,
34
+ ) => {
35
+ const handleChange = onChange ? () => onChange(!value) : undefined
36
+ return children ? (
37
+ <CitricComponent tag="label" component={`${appearance}-row`} colorScheme={colorScheme} style={style} className={className}>
38
+ <input type="checkbox" checked={value} onChange={handleChange} {...props} />
39
+ {children}
40
+ </CitricComponent>
41
+ ) : <CitricComponent
42
+ tag="input"
43
+ type="checkbox"
44
+ component={appearance}
45
+ checked={value}
46
+ onChange={handleChange}
47
+ className={className}
48
+ style={style}
49
+ {...props}
50
+ />
51
+ })
@@ -1,152 +1,152 @@
1
- import { isNil } from 'lodash'
2
- import { useMemo } from 'react'
3
- import { WithColorScheme } from '../types'
4
- import { defaultRenderKey, defaultRenderLabel } from '../utils/options'
5
- import { withRef } from '../utils/react'
6
- import { CitricComponent } from './CitricComponent'
7
- import { Column } from './layout'
8
-
9
- export interface BaseCheckboxGroupProps<T = any> extends WithColorScheme {
10
- /**
11
- * "checkbox" for common check boxes, "switch" for toggles.
12
- * @default 'checkbox'
13
- */
14
- appearance?: 'checkbox' | 'switch',
15
- /**
16
- * The field name.
17
- */
18
- name?: string,
19
- /**
20
- * All items corresponding to the selected checkboxes.
21
- */
22
- value: T[],
23
- /**
24
- * All the items (checkboxes) to render.
25
- */
26
- options: T[],
27
- /**
28
- * Called whenever the selected checkboxes changes.
29
- * @param value the currently selected items.
30
- */
31
- onChange: (value: T[]) => void,
32
- /**
33
- * A function to render the item label.
34
- *
35
- * Attention: ignored if `renderItem` is set.
36
- *
37
- * @example
38
- * `(option) => option.name`
39
- * @default "the item's toString() result."
40
- * @param option the item to render.
41
- * @returns a React Node to render.
42
- */
43
- renderLabel?: (option: T) => React.ReactNode,
44
- /**
45
- * A function to render the item with the checkbox. When set, `renderLabel` is ignored.
46
- * @example
47
- * ```
48
- * (checkbox, option) => <label>{checkbox} {option.name}</label>
49
- * ```
50
- * @param checkbox the checkbox.
51
- * @param option the current item.
52
- * @returns a React Node to render.
53
- */
54
- renderItem?: (checkbox: React.ReactElement, option: T) => React.ReactNode,
55
- /**
56
- * A function to render the item value, a unique identifier for the option.
57
- * @example
58
- * `(option) => option.id`
59
- * @default "if the item is a string or a number, the stringified item. Otherwise, undefined."
60
- * @param option the item to compute a key for.
61
- * @returns a string key.
62
- */
63
- renderKey?: (option: T) => string | number | undefined,
64
- /**
65
- * If this function returns true for the item, this option is disabled.
66
- * @default "nothing is disabled"
67
- * @param option the item to calculate "disabled" for.
68
- * @returns true if the item should be disabled, false otherwise.
69
- */
70
- isDisabled?: (option: T) => boolean,
71
- /**
72
- * The space between options.
73
- *
74
- * @default "8px"
75
- */
76
- gap?: string,
77
- /**
78
- * If set to false, the checkboxes will have tabIndex = -1.
79
- *
80
- * @default true
81
- */
82
- focusable?: boolean,
83
- }
84
-
85
- export type CheckboxGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseCheckboxGroupProps<T>
86
-
87
- /**
88
- * Renders a list of checkbox for multi-selection. One checkbox is rendered for each option.
89
- *
90
- * This component can be heavily customized via its properties. Check the storybook for complex examples.
91
- *
92
- * Tip: if you need to implement features like "search" and "select all", use the hook `useCheckboxGroupControls`.
93
- *
94
- * Tip: If you need a checkbox group that doesn't occupy much height, consider using a MultiSelect.
95
- *
96
- * @example
97
- *
98
- * ```
99
- * const options = useMemo(() => [
100
- * { id: 1, name: 'Option 1' },
101
- * { id: 2, name: 'Option 2' },
102
- * { id: 3, name: 'Option 3' },
103
- * ], [])
104
- *
105
- * const [value, setValue] = useState<typeof options>([])
106
- *
107
- * return <CheckboxGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
108
- * ```
109
- */
110
- export const CheckboxGroup = withRef(
111
- function CheckboxGroup<T>({
112
- appearance = 'checkbox',
113
- name,
114
- value = [],
115
- options,
116
- onChange,
117
- renderLabel = defaultRenderLabel,
118
- renderKey = defaultRenderKey,
119
- renderItem,
120
- isDisabled,
121
- colorScheme,
122
- style,
123
- gap = '8px',
124
- focusable = true,
125
- ...props
126
- }: CheckboxGroupProps<T>) {
127
- const items = useMemo(() => {
128
- const valueKeys = value.map(renderKey)
129
- return options.map((o) => {
130
- const key = renderKey(o)
131
- const checkbox = <CitricComponent
132
- tag="input"
133
- component={appearance}
134
- type="checkbox"
135
- name={name}
136
- value={key}
137
- checked={value.includes(o) || (!isNil(key) && valueKeys.includes(key))}
138
- onChange={(e) => onChange?.(e.target.checked ? [...(value ?? []), o] : (value?.filter(item => item != o) ?? []))}
139
- disabled={isDisabled?.(o)}
140
- tabIndex={focusable ? undefined : -1}
141
- />
142
- return renderItem ? renderItem(checkbox, o) : (
143
- <CitricComponent tag="label" component={`${appearance}-row`} key={key} colorScheme={colorScheme}>
144
- {checkbox}
145
- {renderLabel(o)}
146
- </CitricComponent>
147
- )
148
- })
149
- }, [options, value, name, colorScheme, appearance])
150
- return <Column {...props} style={{ gap, ...style }}>{items}</Column>
151
- },
152
- )
1
+ import { isNil } from 'lodash'
2
+ import { useMemo } from 'react'
3
+ import { WithColorScheme } from '../types'
4
+ import { defaultRenderKey, defaultRenderLabel } from '../utils/options'
5
+ import { withRef } from '../utils/react'
6
+ import { CitricComponent } from './CitricComponent'
7
+ import { Column } from './layout'
8
+
9
+ export interface BaseCheckboxGroupProps<T = any> extends WithColorScheme {
10
+ /**
11
+ * "checkbox" for common check boxes, "switch" for toggles.
12
+ * @default 'checkbox'
13
+ */
14
+ appearance?: 'checkbox' | 'switch',
15
+ /**
16
+ * The field name.
17
+ */
18
+ name?: string,
19
+ /**
20
+ * All items corresponding to the selected checkboxes.
21
+ */
22
+ value: T[],
23
+ /**
24
+ * All the items (checkboxes) to render.
25
+ */
26
+ options: T[],
27
+ /**
28
+ * Called whenever the selected checkboxes changes.
29
+ * @param value the currently selected items.
30
+ */
31
+ onChange: (value: T[]) => void,
32
+ /**
33
+ * A function to render the item label.
34
+ *
35
+ * Attention: ignored if `renderItem` is set.
36
+ *
37
+ * @example
38
+ * `(option) => option.name`
39
+ * @default "the item's toString() result."
40
+ * @param option the item to render.
41
+ * @returns a React Node to render.
42
+ */
43
+ renderLabel?: (option: T) => React.ReactNode,
44
+ /**
45
+ * A function to render the item with the checkbox. When set, `renderLabel` is ignored.
46
+ * @example
47
+ * ```
48
+ * (checkbox, option) => <label>{checkbox} {option.name}</label>
49
+ * ```
50
+ * @param checkbox the checkbox.
51
+ * @param option the current item.
52
+ * @returns a React Node to render.
53
+ */
54
+ renderItem?: (checkbox: React.ReactElement, option: T) => React.ReactNode,
55
+ /**
56
+ * A function to render the item value, a unique identifier for the option.
57
+ * @example
58
+ * `(option) => option.id`
59
+ * @default "if the item is a string or a number, the stringified item. Otherwise, undefined."
60
+ * @param option the item to compute a key for.
61
+ * @returns a string key.
62
+ */
63
+ renderKey?: (option: T) => string | number | undefined,
64
+ /**
65
+ * If this function returns true for the item, this option is disabled.
66
+ * @default "nothing is disabled"
67
+ * @param option the item to calculate "disabled" for.
68
+ * @returns true if the item should be disabled, false otherwise.
69
+ */
70
+ isDisabled?: (option: T) => boolean,
71
+ /**
72
+ * The space between options.
73
+ *
74
+ * @default "8px"
75
+ */
76
+ gap?: string,
77
+ /**
78
+ * If set to false, the checkboxes will have tabIndex = -1.
79
+ *
80
+ * @default true
81
+ */
82
+ focusable?: boolean,
83
+ }
84
+
85
+ export type CheckboxGroupProps<T> = Omit<React.JSX.IntrinsicElements['div'], 'onChange' | 'children'> & BaseCheckboxGroupProps<T>
86
+
87
+ /**
88
+ * Renders a list of checkbox for multi-selection. One checkbox is rendered for each option.
89
+ *
90
+ * This component can be heavily customized via its properties. Check the storybook for complex examples.
91
+ *
92
+ * Tip: if you need to implement features like "search" and "select all", use the hook `useCheckboxGroupControls`.
93
+ *
94
+ * Tip: If you need a checkbox group that doesn't occupy much height, consider using a MultiSelect.
95
+ *
96
+ * @example
97
+ *
98
+ * ```
99
+ * const options = useMemo(() => [
100
+ * { id: 1, name: 'Option 1' },
101
+ * { id: 2, name: 'Option 2' },
102
+ * { id: 3, name: 'Option 3' },
103
+ * ], [])
104
+ *
105
+ * const [value, setValue] = useState<typeof options>([])
106
+ *
107
+ * return <CheckboxGroup options={options} renderLabel={o => o.name} renderKey={o => o.id} value={value} setValue={setValue} />
108
+ * ```
109
+ */
110
+ export const CheckboxGroup = withRef(
111
+ function CheckboxGroup<T>({
112
+ appearance = 'checkbox',
113
+ name,
114
+ value = [],
115
+ options,
116
+ onChange,
117
+ renderLabel = defaultRenderLabel,
118
+ renderKey = defaultRenderKey,
119
+ renderItem,
120
+ isDisabled,
121
+ colorScheme,
122
+ style,
123
+ gap = '8px',
124
+ focusable = true,
125
+ ...props
126
+ }: CheckboxGroupProps<T>) {
127
+ const items = useMemo(() => {
128
+ const valueKeys = value.map(renderKey)
129
+ return options.map((o) => {
130
+ const key = renderKey(o)
131
+ const checkbox = <CitricComponent
132
+ tag="input"
133
+ component={appearance}
134
+ type="checkbox"
135
+ name={name}
136
+ value={key}
137
+ checked={value.includes(o) || (!isNil(key) && valueKeys.includes(key))}
138
+ onChange={(e) => onChange?.(e.target.checked ? [...(value ?? []), o] : (value?.filter(item => item != o) ?? []))}
139
+ disabled={isDisabled?.(o)}
140
+ tabIndex={focusable ? undefined : -1}
141
+ />
142
+ return renderItem ? renderItem(checkbox, o) : (
143
+ <CitricComponent tag="label" component={`${appearance}-row`} key={key} colorScheme={colorScheme}>
144
+ {checkbox}
145
+ {renderLabel(o)}
146
+ </CitricComponent>
147
+ )
148
+ })
149
+ }, [options, value, name, colorScheme, appearance])
150
+ return <Column {...props} style={{ gap, ...style }}>{items}</Column>
151
+ },
152
+ )