@stack-spot/citric-react 0.38.0 → 0.39.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 (189) hide show
  1. package/CHANGELOG.md +13 -13
  2. package/dist/citric.css +2844 -2844
  3. package/dist/components/Accordion.d.ts +1 -1
  4. package/dist/components/Accordion.js +1 -1
  5. package/dist/components/Alert.d.ts +1 -1
  6. package/dist/components/Alert.js +1 -1
  7. package/dist/components/AsyncContent.d.ts +1 -1
  8. package/dist/components/AsyncContent.js +1 -1
  9. package/dist/components/Avatar.d.ts +1 -1
  10. package/dist/components/Avatar.js +1 -1
  11. package/dist/components/AvatarGroup.d.ts +1 -1
  12. package/dist/components/AvatarGroup.js +1 -1
  13. package/dist/components/Badge.d.ts +1 -1
  14. package/dist/components/Badge.js +1 -1
  15. package/dist/components/Blockquote.d.ts +1 -1
  16. package/dist/components/Blockquote.js +1 -1
  17. package/dist/components/Breadcrumb.d.ts +1 -1
  18. package/dist/components/Breadcrumb.js +1 -1
  19. package/dist/components/Button.d.ts +1 -1
  20. package/dist/components/Button.js +1 -1
  21. package/dist/components/ButtonLink.d.ts +1 -1
  22. package/dist/components/ButtonLink.js +1 -1
  23. package/dist/components/Card.d.ts +1 -1
  24. package/dist/components/Card.js +1 -1
  25. package/dist/components/Checkbox.d.ts +1 -1
  26. package/dist/components/Checkbox.js +1 -1
  27. package/dist/components/CheckboxGroup.d.ts +1 -1
  28. package/dist/components/CheckboxGroup.d.ts.map +1 -1
  29. package/dist/components/CheckboxGroup.js +2 -2
  30. package/dist/components/CheckboxGroup.js.map +1 -1
  31. package/dist/components/Circle.d.ts +1 -1
  32. package/dist/components/Circle.js +1 -1
  33. package/dist/components/Divider.d.ts +1 -1
  34. package/dist/components/Divider.js +1 -1
  35. package/dist/components/ErrorBoundary.d.ts +1 -1
  36. package/dist/components/ErrorBoundary.js +1 -1
  37. package/dist/components/ErrorMessage.d.ts +1 -1
  38. package/dist/components/ErrorMessage.js +1 -1
  39. package/dist/components/FallbackBoundary.d.ts +1 -1
  40. package/dist/components/FallbackBoundary.js +1 -1
  41. package/dist/components/Favorite.d.ts +1 -1
  42. package/dist/components/Favorite.js +1 -1
  43. package/dist/components/FieldGroup.d.ts +1 -1
  44. package/dist/components/FieldGroup.js +1 -1
  45. package/dist/components/Form.d.ts +2 -2
  46. package/dist/components/Form.js +1 -1
  47. package/dist/components/FormGroup.d.ts +1 -1
  48. package/dist/components/FormGroup.js +1 -1
  49. package/dist/components/Icon.d.ts +1 -1
  50. package/dist/components/Icon.js +1 -1
  51. package/dist/components/IconBox.d.ts +3 -3
  52. package/dist/components/IconBox.js +1 -1
  53. package/dist/components/ImageBox.d.ts +3 -3
  54. package/dist/components/ImageBox.js +1 -1
  55. package/dist/components/ImageWithFallback.d.ts +1 -1
  56. package/dist/components/ImageWithFallback.js +1 -1
  57. package/dist/components/Input.d.ts +1 -1
  58. package/dist/components/Input.js +1 -1
  59. package/dist/components/Link.d.ts +1 -1
  60. package/dist/components/Link.js +1 -1
  61. package/dist/components/LoadingPanel.d.ts +1 -1
  62. package/dist/components/LoadingPanel.js +1 -1
  63. package/dist/components/MenuOverlay/Menu.d.ts +1 -1
  64. package/dist/components/MenuOverlay/Menu.js +1 -1
  65. package/dist/components/MenuOverlay/index.d.ts +1 -1
  66. package/dist/components/MenuOverlay/index.js +1 -1
  67. package/dist/components/Overlay/index.d.ts +4 -1
  68. package/dist/components/Overlay/index.d.ts.map +1 -1
  69. package/dist/components/Overlay/index.js +4 -1
  70. package/dist/components/Overlay/index.js.map +1 -1
  71. package/dist/components/Pagination.d.ts +1 -1
  72. package/dist/components/Pagination.js +1 -1
  73. package/dist/components/ProgressBar.d.ts +1 -1
  74. package/dist/components/ProgressBar.js +1 -1
  75. package/dist/components/ProgressCircular.d.ts +1 -1
  76. package/dist/components/ProgressCircular.js +1 -1
  77. package/dist/components/RadioGroup.d.ts +1 -1
  78. package/dist/components/RadioGroup.js +1 -1
  79. package/dist/components/Rating.d.ts +1 -1
  80. package/dist/components/Rating.js +1 -1
  81. package/dist/components/Select/MultiSelect.d.ts +1 -1
  82. package/dist/components/Select/MultiSelect.js +1 -1
  83. package/dist/components/Select/RichSelect.d.ts +1 -1
  84. package/dist/components/Select/RichSelect.js +1 -1
  85. package/dist/components/Select/SimpleSelect.d.ts +1 -1
  86. package/dist/components/Select/SimpleSelect.js +1 -1
  87. package/dist/components/Select/index.d.ts +1 -1
  88. package/dist/components/Select/index.js +1 -1
  89. package/dist/components/SelectBox.d.ts +1 -1
  90. package/dist/components/SelectBox.js +1 -1
  91. package/dist/components/Skeleton.d.ts +1 -1
  92. package/dist/components/Skeleton.js +1 -1
  93. package/dist/components/Slider.d.ts +1 -1
  94. package/dist/components/Slider.js +1 -1
  95. package/dist/components/SmartTable.d.ts +1 -1
  96. package/dist/components/SmartTable.js +1 -1
  97. package/dist/components/Stepper.d.ts +1 -1
  98. package/dist/components/Stepper.js +1 -1
  99. package/dist/components/Table.d.ts +3 -3
  100. package/dist/components/Table.js +1 -1
  101. package/dist/components/Tabs/index.d.ts +1 -1
  102. package/dist/components/Tabs/index.js +1 -1
  103. package/dist/components/Textarea.d.ts +1 -1
  104. package/dist/components/Textarea.js +1 -1
  105. package/dist/components/Tooltip.d.ts +1 -1
  106. package/dist/components/Tooltip.js +1 -1
  107. package/dist/context/CitricProvider.d.ts +1 -1
  108. package/dist/context/CitricProvider.js +1 -1
  109. package/dist/overlay.js +1 -1
  110. package/dist/theme.css +415 -415
  111. package/package.json +1 -1
  112. package/scripts/build-css.ts +49 -49
  113. package/src/components/Accordion.tsx +130 -130
  114. package/src/components/Alert.tsx +24 -24
  115. package/src/components/AsyncContent.tsx +70 -70
  116. package/src/components/Avatar.tsx +45 -45
  117. package/src/components/AvatarGroup.tsx +49 -49
  118. package/src/components/Badge.tsx +47 -47
  119. package/src/components/Blockquote.tsx +18 -18
  120. package/src/components/Breadcrumb.tsx +33 -33
  121. package/src/components/Button.tsx +105 -105
  122. package/src/components/ButtonLink.tsx +45 -45
  123. package/src/components/Card.tsx +68 -68
  124. package/src/components/Checkbox.tsx +51 -51
  125. package/src/components/CheckboxGroup.tsx +153 -152
  126. package/src/components/Circle.tsx +43 -43
  127. package/src/components/CitricComponent.ts +47 -47
  128. package/src/components/Divider.tsx +24 -24
  129. package/src/components/ErrorBoundary.tsx +75 -75
  130. package/src/components/ErrorMessage.tsx +11 -11
  131. package/src/components/FallbackBoundary.tsx +40 -40
  132. package/src/components/Favorite.tsx +57 -57
  133. package/src/components/FieldGroup.tsx +46 -46
  134. package/src/components/Form.tsx +36 -36
  135. package/src/components/FormGroup.tsx +57 -57
  136. package/src/components/Icon.tsx +35 -35
  137. package/src/components/IconBox.tsx +134 -134
  138. package/src/components/ImageBox.tsx +125 -125
  139. package/src/components/ImageWithFallback.tsx +65 -65
  140. package/src/components/Input.tsx +49 -49
  141. package/src/components/Link.tsx +55 -55
  142. package/src/components/LoadingPanel.tsx +8 -8
  143. package/src/components/MenuOverlay/Menu.tsx +158 -158
  144. package/src/components/MenuOverlay/context.ts +20 -20
  145. package/src/components/MenuOverlay/index.tsx +55 -55
  146. package/src/components/MenuOverlay/keyboard.ts +60 -60
  147. package/src/components/MenuOverlay/types.ts +171 -171
  148. package/src/components/Overlay/context.ts +10 -10
  149. package/src/components/Overlay/index.tsx +167 -164
  150. package/src/components/Overlay/types.ts +70 -70
  151. package/src/components/Pagination.tsx +133 -133
  152. package/src/components/ProgressBar.tsx +45 -45
  153. package/src/components/ProgressCircular.tsx +45 -45
  154. package/src/components/RadioGroup.tsx +146 -146
  155. package/src/components/Rating.tsx +98 -98
  156. package/src/components/Select/MultiSelect.tsx +217 -217
  157. package/src/components/Select/RichSelect.tsx +128 -128
  158. package/src/components/Select/SimpleSelect.tsx +73 -73
  159. package/src/components/Select/hooks.ts +133 -133
  160. package/src/components/Select/index.tsx +35 -35
  161. package/src/components/Select/types.ts +134 -134
  162. package/src/components/SelectBox.tsx +167 -167
  163. package/src/components/Skeleton.tsx +53 -53
  164. package/src/components/Slider.tsx +89 -89
  165. package/src/components/SmartTable.tsx +227 -227
  166. package/src/components/Stepper.tsx +163 -163
  167. package/src/components/Table.tsx +234 -234
  168. package/src/components/Tabs/TabController.ts +54 -54
  169. package/src/components/Tabs/index.tsx +87 -87
  170. package/src/components/Tabs/types.ts +54 -54
  171. package/src/components/Tabs/utils.ts +6 -6
  172. package/src/components/Text.ts +111 -111
  173. package/src/components/Textarea.tsx +27 -27
  174. package/src/components/Tooltip.tsx +72 -72
  175. package/src/components/layout.tsx +101 -101
  176. package/src/context/CitricContext.tsx +4 -4
  177. package/src/context/CitricProvider.tsx +14 -14
  178. package/src/context/hooks.ts +6 -6
  179. package/src/index.ts +58 -58
  180. package/src/overlay.ts +341 -341
  181. package/src/types.ts +216 -216
  182. package/src/utils/ValueController.ts +28 -28
  183. package/src/utils/acessibility.ts +92 -92
  184. package/src/utils/checkbox.ts +121 -121
  185. package/src/utils/css.ts +119 -119
  186. package/src/utils/options.ts +9 -9
  187. package/src/utils/radio.ts +93 -93
  188. package/src/utils/react.ts +6 -6
  189. package/tsconfig.json +10 -10
@@ -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,153 @@
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
+ colorScheme={colorScheme}
142
+ />
143
+ return renderItem ? renderItem(checkbox, o) : (
144
+ <CitricComponent tag="label" component={`${appearance}-row`} key={key} colorScheme={colorScheme}>
145
+ {checkbox}
146
+ {renderLabel(o)}
147
+ </CitricComponent>
148
+ )
149
+ })
150
+ }, [options, value, name, colorScheme, appearance])
151
+ return <Column {...props} style={{ gap, ...style }}>{items}</Column>
152
+ },
153
+ )
@@ -1,43 +1,43 @@
1
- import { listToClass } from '@stack-spot/portal-theme'
2
- import { WithColorPalette, WithColorScheme } from '../types'
3
- import { withRef } from '../utils/react'
4
- import { CitricComponent } from './CitricComponent'
5
-
6
- export interface BaseCircleProps extends WithColorPalette, WithColorScheme {
7
- /**
8
- * Whether or not to show borders.
9
- *
10
- * @default false
11
- */
12
- showBorders?: boolean,
13
- /**
14
- * The size of the circle.
15
- *
16
- * - xxs: 8px;
17
- * - xs: 12px;
18
- * - sm: 18px;
19
- * - md: 27px;
20
- * - lg: 40px;
21
- * - xl: 60px;
22
- * - xxl: 90px.
23
- *
24
- * @default 'xs'
25
- */
26
- size?: 'xxs' | 'xs' | 'sm' | 'lg' | 'xl' | 'xxl',
27
- }
28
-
29
- export type CircleProps = React.JSX.IntrinsicElements['div'] & BaseCircleProps
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
- */
39
- export const Circle = withRef(({ showBorders, className, size, children, ...props }: CircleProps) => (
40
- <CitricComponent tag="div" component="circle" className={listToClass([className, showBorders && 'bordered', size])} {...props}>
41
- {children}
42
- </CitricComponent>
43
- ))
1
+ import { listToClass } from '@stack-spot/portal-theme'
2
+ import { WithColorPalette, WithColorScheme } from '../types'
3
+ import { withRef } from '../utils/react'
4
+ import { CitricComponent } from './CitricComponent'
5
+
6
+ export interface BaseCircleProps extends WithColorPalette, WithColorScheme {
7
+ /**
8
+ * Whether or not to show borders.
9
+ *
10
+ * @default false
11
+ */
12
+ showBorders?: boolean,
13
+ /**
14
+ * The size of the circle.
15
+ *
16
+ * - xxs: 8px;
17
+ * - xs: 12px;
18
+ * - sm: 18px;
19
+ * - md: 27px;
20
+ * - lg: 40px;
21
+ * - xl: 60px;
22
+ * - xxl: 90px.
23
+ *
24
+ * @default 'xs'
25
+ */
26
+ size?: 'xxs' | 'xs' | 'sm' | 'lg' | 'xl' | 'xxl',
27
+ }
28
+
29
+ export type CircleProps = React.JSX.IntrinsicElements['div'] & BaseCircleProps
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
+ */
39
+ export const Circle = withRef(({ showBorders, className, size, children, ...props }: CircleProps) => (
40
+ <CitricComponent tag="div" component="circle" className={listToClass([className, showBorders && 'bordered', size])} {...props}>
41
+ {children}
42
+ </CitricComponent>
43
+ ))