@stack-spot/citric-react 0.38.0 → 0.39.1
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.
- package/CHANGELOG.md +13 -13
- package/dist/citric.css +2844 -2844
- package/dist/components/Accordion.d.ts +1 -1
- package/dist/components/Accordion.js +1 -1
- package/dist/components/Alert.d.ts +1 -1
- package/dist/components/Alert.js +1 -1
- package/dist/components/AsyncContent.d.ts +1 -1
- package/dist/components/AsyncContent.js +1 -1
- package/dist/components/Avatar.d.ts +1 -1
- package/dist/components/Avatar.js +1 -1
- package/dist/components/AvatarGroup.d.ts +1 -1
- package/dist/components/AvatarGroup.js +1 -1
- package/dist/components/Badge.d.ts +1 -1
- package/dist/components/Badge.js +1 -1
- package/dist/components/Blockquote.d.ts +1 -1
- package/dist/components/Blockquote.js +1 -1
- package/dist/components/Breadcrumb.d.ts +1 -1
- package/dist/components/Breadcrumb.js +1 -1
- package/dist/components/Button.d.ts +1 -1
- package/dist/components/Button.js +1 -1
- package/dist/components/ButtonLink.d.ts +1 -1
- package/dist/components/ButtonLink.js +1 -1
- package/dist/components/Card.d.ts +1 -1
- package/dist/components/Card.js +1 -1
- package/dist/components/Checkbox.d.ts +1 -1
- package/dist/components/Checkbox.js +1 -1
- package/dist/components/CheckboxGroup.d.ts +1 -1
- package/dist/components/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/CheckboxGroup.js +2 -2
- package/dist/components/CheckboxGroup.js.map +1 -1
- package/dist/components/Circle.d.ts +1 -1
- package/dist/components/Circle.js +1 -1
- package/dist/components/Divider.d.ts +1 -1
- package/dist/components/Divider.js +1 -1
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/ErrorMessage.d.ts +1 -1
- package/dist/components/ErrorMessage.js +1 -1
- package/dist/components/FallbackBoundary.d.ts +1 -1
- package/dist/components/FallbackBoundary.js +1 -1
- package/dist/components/Favorite.d.ts +1 -1
- package/dist/components/Favorite.js +1 -1
- package/dist/components/FieldGroup.d.ts +1 -1
- package/dist/components/FieldGroup.js +1 -1
- package/dist/components/Form.d.ts +2 -2
- package/dist/components/Form.js +1 -1
- package/dist/components/FormGroup.d.ts +1 -1
- package/dist/components/FormGroup.js +1 -1
- package/dist/components/Icon.d.ts +1 -1
- package/dist/components/Icon.js +1 -1
- package/dist/components/IconBox.d.ts +3 -3
- package/dist/components/IconBox.js +1 -1
- package/dist/components/ImageBox.d.ts +3 -3
- package/dist/components/ImageBox.js +1 -1
- package/dist/components/ImageWithFallback.d.ts +1 -1
- package/dist/components/ImageWithFallback.js +1 -1
- package/dist/components/Input.d.ts +1 -1
- package/dist/components/Input.js +1 -1
- package/dist/components/Link.d.ts +1 -1
- package/dist/components/Link.js +1 -1
- package/dist/components/LoadingPanel.d.ts +1 -1
- package/dist/components/LoadingPanel.js +1 -1
- package/dist/components/MenuOverlay/Menu.d.ts +1 -1
- package/dist/components/MenuOverlay/Menu.js +1 -1
- package/dist/components/MenuOverlay/index.d.ts +1 -1
- package/dist/components/MenuOverlay/index.js +1 -1
- package/dist/components/Overlay/index.d.ts +4 -1
- package/dist/components/Overlay/index.d.ts.map +1 -1
- package/dist/components/Overlay/index.js +4 -1
- package/dist/components/Overlay/index.js.map +1 -1
- package/dist/components/Pagination.d.ts +1 -1
- package/dist/components/Pagination.js +1 -1
- package/dist/components/ProgressBar.d.ts +1 -1
- package/dist/components/ProgressBar.js +1 -1
- package/dist/components/ProgressCircular.d.ts +1 -1
- package/dist/components/ProgressCircular.js +1 -1
- package/dist/components/RadioGroup.d.ts +1 -1
- package/dist/components/RadioGroup.d.ts.map +1 -1
- package/dist/components/RadioGroup.js +2 -2
- package/dist/components/RadioGroup.js.map +1 -1
- package/dist/components/Rating.d.ts +1 -1
- package/dist/components/Rating.js +1 -1
- package/dist/components/Select/MultiSelect.d.ts +1 -1
- package/dist/components/Select/MultiSelect.js +1 -1
- package/dist/components/Select/RichSelect.d.ts +1 -1
- package/dist/components/Select/RichSelect.js +1 -1
- package/dist/components/Select/SimpleSelect.d.ts +1 -1
- package/dist/components/Select/SimpleSelect.js +1 -1
- package/dist/components/Select/index.d.ts +1 -1
- package/dist/components/Select/index.js +1 -1
- package/dist/components/SelectBox.d.ts +1 -1
- package/dist/components/SelectBox.js +1 -1
- package/dist/components/Skeleton.d.ts +1 -1
- package/dist/components/Skeleton.js +1 -1
- package/dist/components/Slider.d.ts +1 -1
- package/dist/components/Slider.js +1 -1
- package/dist/components/SmartTable.d.ts +1 -1
- package/dist/components/SmartTable.js +1 -1
- package/dist/components/Stepper.d.ts +1 -1
- package/dist/components/Stepper.js +1 -1
- package/dist/components/Table.d.ts +3 -3
- package/dist/components/Table.js +1 -1
- package/dist/components/Tabs/index.d.ts +1 -1
- package/dist/components/Tabs/index.js +1 -1
- package/dist/components/Textarea.d.ts +1 -1
- package/dist/components/Textarea.js +1 -1
- package/dist/components/Tooltip.d.ts +1 -1
- package/dist/components/Tooltip.js +1 -1
- package/dist/context/CitricProvider.d.ts +1 -1
- package/dist/context/CitricProvider.js +1 -1
- package/dist/overlay.js +1 -1
- package/dist/theme.css +415 -415
- package/package.json +1 -1
- package/scripts/build-css.ts +49 -49
- package/src/components/Accordion.tsx +130 -130
- package/src/components/Alert.tsx +24 -24
- package/src/components/AsyncContent.tsx +70 -70
- package/src/components/Avatar.tsx +45 -45
- package/src/components/AvatarGroup.tsx +49 -49
- package/src/components/Badge.tsx +47 -47
- package/src/components/Blockquote.tsx +18 -18
- package/src/components/Breadcrumb.tsx +33 -33
- package/src/components/Button.tsx +105 -105
- package/src/components/ButtonLink.tsx +45 -45
- package/src/components/Card.tsx +68 -68
- package/src/components/Checkbox.tsx +51 -51
- package/src/components/CheckboxGroup.tsx +153 -152
- package/src/components/Circle.tsx +43 -43
- package/src/components/CitricComponent.ts +47 -47
- package/src/components/Divider.tsx +24 -24
- package/src/components/ErrorBoundary.tsx +75 -75
- package/src/components/ErrorMessage.tsx +11 -11
- package/src/components/FallbackBoundary.tsx +40 -40
- package/src/components/Favorite.tsx +57 -57
- package/src/components/FieldGroup.tsx +46 -46
- package/src/components/Form.tsx +36 -36
- package/src/components/FormGroup.tsx +57 -57
- package/src/components/Icon.tsx +35 -35
- package/src/components/IconBox.tsx +134 -134
- package/src/components/ImageBox.tsx +125 -125
- package/src/components/ImageWithFallback.tsx +65 -65
- package/src/components/Input.tsx +49 -49
- package/src/components/Link.tsx +55 -55
- package/src/components/LoadingPanel.tsx +8 -8
- package/src/components/MenuOverlay/Menu.tsx +158 -158
- package/src/components/MenuOverlay/context.ts +20 -20
- package/src/components/MenuOverlay/index.tsx +55 -55
- package/src/components/MenuOverlay/keyboard.ts +60 -60
- package/src/components/MenuOverlay/types.ts +171 -171
- package/src/components/Overlay/context.ts +10 -10
- package/src/components/Overlay/index.tsx +167 -164
- package/src/components/Overlay/types.ts +70 -70
- package/src/components/Pagination.tsx +133 -133
- package/src/components/ProgressBar.tsx +45 -45
- package/src/components/ProgressCircular.tsx +45 -45
- package/src/components/RadioGroup.tsx +147 -146
- package/src/components/Rating.tsx +98 -98
- package/src/components/Select/MultiSelect.tsx +217 -217
- package/src/components/Select/RichSelect.tsx +128 -128
- package/src/components/Select/SimpleSelect.tsx +73 -73
- package/src/components/Select/hooks.ts +133 -133
- package/src/components/Select/index.tsx +35 -35
- package/src/components/Select/types.ts +134 -134
- package/src/components/SelectBox.tsx +167 -167
- package/src/components/Skeleton.tsx +53 -53
- package/src/components/Slider.tsx +89 -89
- package/src/components/SmartTable.tsx +227 -227
- package/src/components/Stepper.tsx +163 -163
- package/src/components/Table.tsx +234 -234
- package/src/components/Tabs/TabController.ts +54 -54
- package/src/components/Tabs/index.tsx +87 -87
- package/src/components/Tabs/types.ts +54 -54
- package/src/components/Tabs/utils.ts +6 -6
- package/src/components/Text.ts +111 -111
- package/src/components/Textarea.tsx +27 -27
- package/src/components/Tooltip.tsx +72 -72
- package/src/components/layout.tsx +101 -101
- package/src/context/CitricContext.tsx +4 -4
- package/src/context/CitricProvider.tsx +14 -14
- package/src/context/hooks.ts +6 -6
- package/src/index.ts +58 -58
- package/src/overlay.ts +341 -341
- package/src/types.ts +216 -216
- package/src/utils/ValueController.ts +28 -28
- package/src/utils/acessibility.ts +92 -92
- package/src/utils/checkbox.ts +121 -121
- package/src/utils/css.ts +119 -119
- package/src/utils/options.ts +9 -9
- package/src/utils/radio.ts +93 -93
- package/src/utils/react.ts +6 -6
- package/tsconfig.json +10 -10
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import { createElement, forwardRef } from 'react'
|
|
2
|
-
import { WithColorPalette, WithColorScheme } from '../types'
|
|
3
|
-
|
|
4
|
-
export type CitricComponentName = 'alert' | 'avatar' | 'badge' | 'blockquote' | 'breadcrumb' | 'button' | 'card' | 'checkbox' |
|
|
5
|
-
'checkbox-row' | 'divider' | 'field-group' | 'form-group' | 'form' | 'icon-box' | 'input' | 'link' | 'pagination' | 'progress-bar' |
|
|
6
|
-
'progress-circular' | 'radio' | 'radio-row' | 'rating' | 'select' | 'select-box' | 'skeleton' | 'slider' | 'switch' | 'switch-row' |
|
|
7
|
-
'table' | 'tabs' | 'accordion' | 'favorite' | 'textarea' | 'avatar-group' | 'labeled-slider' | 'rich-select' | 'tooltip' | 'menu' |
|
|
8
|
-
'circle' | 'multi-select'
|
|
9
|
-
|
|
10
|
-
interface BaseCitricProps extends WithColorScheme, WithColorPalette {
|
|
11
|
-
component: CitricComponentName,
|
|
12
|
-
ref?: any,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface CitricComponentType {
|
|
16
|
-
<T extends keyof JSX.IntrinsicElements>(props: { tag: T } & BaseCitricProps & JSX.IntrinsicElements[T]): React.ReactNode,
|
|
17
|
-
<T extends Record<string, any>>(props: { render: React.FC<T> } & BaseCitricProps & T): React.ReactNode,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function asCitricProps({ colorScheme, colorPalette, component, ...props }: BaseCitricProps & Record<string, any>) {
|
|
21
|
-
const citricProps: Record<string, any> = { ...props, 'data-citric': component }
|
|
22
|
-
if (colorScheme) citricProps['data-color-scheme'] = colorScheme
|
|
23
|
-
if (colorPalette) citricProps['data-color-palette'] = colorPalette
|
|
24
|
-
return citricProps
|
|
25
|
-
}
|
|
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
|
-
*/
|
|
41
|
-
// eslint-disable-next-line react/display-name
|
|
42
|
-
export const CitricComponent: CitricComponentType = forwardRef<any, any>(
|
|
43
|
-
(props, ref) => {
|
|
44
|
-
const { tag, render, ...citricProps } = asCitricProps(props)
|
|
45
|
-
return createElement(tag || render, { ...citricProps, ref })
|
|
46
|
-
},
|
|
47
|
-
)
|
|
1
|
+
import { createElement, forwardRef } from 'react'
|
|
2
|
+
import { WithColorPalette, WithColorScheme } from '../types'
|
|
3
|
+
|
|
4
|
+
export type CitricComponentName = 'alert' | 'avatar' | 'badge' | 'blockquote' | 'breadcrumb' | 'button' | 'card' | 'checkbox' |
|
|
5
|
+
'checkbox-row' | 'divider' | 'field-group' | 'form-group' | 'form' | 'icon-box' | 'input' | 'link' | 'pagination' | 'progress-bar' |
|
|
6
|
+
'progress-circular' | 'radio' | 'radio-row' | 'rating' | 'select' | 'select-box' | 'skeleton' | 'slider' | 'switch' | 'switch-row' |
|
|
7
|
+
'table' | 'tabs' | 'accordion' | 'favorite' | 'textarea' | 'avatar-group' | 'labeled-slider' | 'rich-select' | 'tooltip' | 'menu' |
|
|
8
|
+
'circle' | 'multi-select'
|
|
9
|
+
|
|
10
|
+
interface BaseCitricProps extends WithColorScheme, WithColorPalette {
|
|
11
|
+
component: CitricComponentName,
|
|
12
|
+
ref?: any,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CitricComponentType {
|
|
16
|
+
<T extends keyof JSX.IntrinsicElements>(props: { tag: T } & BaseCitricProps & JSX.IntrinsicElements[T]): React.ReactNode,
|
|
17
|
+
<T extends Record<string, any>>(props: { render: React.FC<T> } & BaseCitricProps & T): React.ReactNode,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function asCitricProps({ colorScheme, colorPalette, component, ...props }: BaseCitricProps & Record<string, any>) {
|
|
21
|
+
const citricProps: Record<string, any> = { ...props, 'data-citric': component }
|
|
22
|
+
if (colorScheme) citricProps['data-color-scheme'] = colorScheme
|
|
23
|
+
if (colorPalette) citricProps['data-color-palette'] = colorPalette
|
|
24
|
+
return citricProps
|
|
25
|
+
}
|
|
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
|
+
*/
|
|
41
|
+
// eslint-disable-next-line react/display-name
|
|
42
|
+
export const CitricComponent: CitricComponentType = forwardRef<any, any>(
|
|
43
|
+
(props, ref) => {
|
|
44
|
+
const { tag, render, ...citricProps } = asCitricProps(props)
|
|
45
|
+
return createElement(tag || render, { ...citricProps, ref })
|
|
46
|
+
},
|
|
47
|
+
)
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { listToClass } from '@stack-spot/portal-theme'
|
|
2
|
-
import { WithColorScheme } from '../types'
|
|
3
|
-
import { withRef } from '../utils/react'
|
|
4
|
-
import { CitricComponent } from './CitricComponent'
|
|
5
|
-
|
|
6
|
-
export interface BaseDividerProps extends WithColorScheme {
|
|
7
|
-
/**
|
|
8
|
-
* @default 'horizontal'
|
|
9
|
-
*/
|
|
10
|
-
direction?: 'horizontal' | 'vertical',
|
|
11
|
-
/**
|
|
12
|
-
* @default 'sm'
|
|
13
|
-
*/
|
|
14
|
-
size?: 'sm' | 'md' | 'lg',
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type DividerProps = React.JSX.IntrinsicElements['hr'] & BaseDividerProps
|
|
18
|
-
|
|
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
|
-
)
|
|
1
|
+
import { listToClass } from '@stack-spot/portal-theme'
|
|
2
|
+
import { WithColorScheme } from '../types'
|
|
3
|
+
import { withRef } from '../utils/react'
|
|
4
|
+
import { CitricComponent } from './CitricComponent'
|
|
5
|
+
|
|
6
|
+
export interface BaseDividerProps extends WithColorScheme {
|
|
7
|
+
/**
|
|
8
|
+
* @default 'horizontal'
|
|
9
|
+
*/
|
|
10
|
+
direction?: 'horizontal' | 'vertical',
|
|
11
|
+
/**
|
|
12
|
+
* @default 'sm'
|
|
13
|
+
*/
|
|
14
|
+
size?: 'sm' | 'md' | 'lg',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type DividerProps = React.JSX.IntrinsicElements['hr'] & BaseDividerProps
|
|
18
|
+
|
|
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
|
+
)
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import { Component } from 'react'
|
|
2
|
-
import { CitricContext } from '../context/CitricContext'
|
|
3
|
-
import { ErrorMessage } from './ErrorMessage'
|
|
4
|
-
|
|
5
|
-
interface State {
|
|
6
|
-
error?: any,
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface Props {
|
|
10
|
-
children: React.ReactNode,
|
|
11
|
-
/**
|
|
12
|
-
* Sets a default error string when a string is provided.
|
|
13
|
-
*
|
|
14
|
-
* Replaces the error component, if a function is provided.
|
|
15
|
-
*/
|
|
16
|
-
message?: React.ReactNode | ((error: any) => React.ReactNode),
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
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
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export class ErrorBoundary extends Component<Props, State> {
|
|
36
|
-
static contextType = CitricContext
|
|
37
|
-
declare context: React.ContextType<typeof CitricContext>
|
|
38
|
-
|
|
39
|
-
constructor(props: Props) {
|
|
40
|
-
super(props)
|
|
41
|
-
this.state = {}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
static getDerivedStateFromError(error: any) {
|
|
45
|
-
return { error }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
componentDidCatch(error: any, errorInfo: any) {
|
|
49
|
-
this.context?.onError?.(error)
|
|
50
|
-
// eslint-disable-next-line no-console
|
|
51
|
-
console.error(error, errorInfo)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
55
|
-
if (this.state.error && this.props.children !== prevProps.children) {
|
|
56
|
-
this.setState({ error: null })
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private renderCustomErrorUI() {
|
|
61
|
-
return this.context?.renderError?.(this.state.error)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private renderErrorUI() {
|
|
65
|
-
if (typeof this.props.message === 'function') return this.props.message(this.state.error)
|
|
66
|
-
return (this.props.message || !this.context?.renderError)
|
|
67
|
-
? <ErrorMessage error={this.props.message || this.state.error} />
|
|
68
|
-
: this.renderCustomErrorUI()
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
render() {
|
|
73
|
-
return this.state.error ? this.renderErrorUI() : this.props.children
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
import { Component } from 'react'
|
|
2
|
+
import { CitricContext } from '../context/CitricContext'
|
|
3
|
+
import { ErrorMessage } from './ErrorMessage'
|
|
4
|
+
|
|
5
|
+
interface State {
|
|
6
|
+
error?: any,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
children: React.ReactNode,
|
|
11
|
+
/**
|
|
12
|
+
* Sets a default error string when a string is provided.
|
|
13
|
+
*
|
|
14
|
+
* Replaces the error component, if a function is provided.
|
|
15
|
+
*/
|
|
16
|
+
message?: React.ReactNode | ((error: any) => React.ReactNode),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
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
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class ErrorBoundary extends Component<Props, State> {
|
|
36
|
+
static contextType = CitricContext
|
|
37
|
+
declare context: React.ContextType<typeof CitricContext>
|
|
38
|
+
|
|
39
|
+
constructor(props: Props) {
|
|
40
|
+
super(props)
|
|
41
|
+
this.state = {}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static getDerivedStateFromError(error: any) {
|
|
45
|
+
return { error }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
componentDidCatch(error: any, errorInfo: any) {
|
|
49
|
+
this.context?.onError?.(error)
|
|
50
|
+
// eslint-disable-next-line no-console
|
|
51
|
+
console.error(error, errorInfo)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
55
|
+
if (this.state.error && this.props.children !== prevProps.children) {
|
|
56
|
+
this.setState({ error: null })
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private renderCustomErrorUI() {
|
|
61
|
+
return this.context?.renderError?.(this.state.error)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private renderErrorUI() {
|
|
65
|
+
if (typeof this.props.message === 'function') return this.props.message(this.state.error)
|
|
66
|
+
return (this.props.message || !this.context?.renderError)
|
|
67
|
+
? <ErrorMessage error={this.props.message || this.state.error} />
|
|
68
|
+
: this.renderCustomErrorUI()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
render() {
|
|
73
|
+
return this.state.error ? this.renderErrorUI() : this.props.children
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Icon } from '@stack-spot/citric-icons'
|
|
2
|
-
import { theme } from '@stack-spot/portal-theme'
|
|
3
|
-
import { Row } from './layout'
|
|
4
|
-
import { Text } from './Text'
|
|
5
|
-
|
|
6
|
-
export const ErrorMessage = ({ error }: { error: any }) => (
|
|
7
|
-
<Row gap="18px" p="20px" justifyContent="center">
|
|
8
|
-
<Icon icon="TimesCircle" size="xl" style={{ color: theme.color.danger[500] }} />
|
|
9
|
-
<Text>{error.message || `${error}`}</Text>
|
|
10
|
-
</Row>
|
|
11
|
-
)
|
|
1
|
+
import { Icon } from '@stack-spot/citric-icons'
|
|
2
|
+
import { theme } from '@stack-spot/portal-theme'
|
|
3
|
+
import { Row } from './layout'
|
|
4
|
+
import { Text } from './Text'
|
|
5
|
+
|
|
6
|
+
export const ErrorMessage = ({ error }: { error: any }) => (
|
|
7
|
+
<Row gap="18px" p="20px" justifyContent="center">
|
|
8
|
+
<Icon icon="TimesCircle" size="xl" style={{ color: theme.color.danger[500] }} />
|
|
9
|
+
<Text>{error.message || `${error}`}</Text>
|
|
10
|
+
</Row>
|
|
11
|
+
)
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import { Suspense } from 'react'
|
|
2
|
-
import { ErrorBoundary } from './ErrorBoundary'
|
|
3
|
-
import { Center } from './layout'
|
|
4
|
-
import { ProgressCircular } from './ProgressCircular'
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
/**
|
|
8
|
-
* Replaces the error message with this text.
|
|
9
|
-
*/
|
|
10
|
-
message?: string,
|
|
11
|
-
children: React.ReactNode,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const loading = (
|
|
15
|
-
<Center flex={1} p="80px" data-test-hint="loading">
|
|
16
|
-
<ProgressCircular />
|
|
17
|
-
</Center>
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
/**
|
|
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
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
export const FallbackBoundary = ({ children, message }: Props) => (
|
|
35
|
-
<ErrorBoundary message={message}>
|
|
36
|
-
<Suspense fallback={loading}>
|
|
37
|
-
{children}
|
|
38
|
-
</Suspense>
|
|
39
|
-
</ErrorBoundary>
|
|
40
|
-
)
|
|
1
|
+
import { Suspense } from 'react'
|
|
2
|
+
import { ErrorBoundary } from './ErrorBoundary'
|
|
3
|
+
import { Center } from './layout'
|
|
4
|
+
import { ProgressCircular } from './ProgressCircular'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
/**
|
|
8
|
+
* Replaces the error message with this text.
|
|
9
|
+
*/
|
|
10
|
+
message?: string,
|
|
11
|
+
children: React.ReactNode,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const loading = (
|
|
15
|
+
<Center flex={1} p="80px" data-test-hint="loading">
|
|
16
|
+
<ProgressCircular />
|
|
17
|
+
</Center>
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
/**
|
|
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
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export const FallbackBoundary = ({ children, message }: Props) => (
|
|
35
|
+
<ErrorBoundary message={message}>
|
|
36
|
+
<Suspense fallback={loading}>
|
|
37
|
+
{children}
|
|
38
|
+
</Suspense>
|
|
39
|
+
</ErrorBoundary>
|
|
40
|
+
)
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { listToClass } from '@stack-spot/portal-theme'
|
|
2
|
-
import { ControlledInput } from '../types'
|
|
3
|
-
import { withRef } from '../utils/react'
|
|
4
|
-
import { CitricComponent } from './CitricComponent'
|
|
5
|
-
|
|
6
|
-
type FavoriteAppearance = 'square' | 'circle' | 'text'
|
|
7
|
-
|
|
8
|
-
export interface BaseFavoriteProps {
|
|
9
|
-
value: boolean | undefined,
|
|
10
|
-
/**
|
|
11
|
-
* Size of the button.
|
|
12
|
-
*
|
|
13
|
-
* @default 'md'
|
|
14
|
-
*/
|
|
15
|
-
size?: 'sm' | 'md' | 'lg' | 'fit-parent',
|
|
16
|
-
/**
|
|
17
|
-
* Button appearance.
|
|
18
|
-
*
|
|
19
|
-
* @default 'text'
|
|
20
|
-
*/
|
|
21
|
-
appearance?: FavoriteAppearance,
|
|
22
|
-
onChange: (value: boolean) => void,
|
|
23
|
-
/**
|
|
24
|
-
* Whether or not to show the loading feedback.
|
|
25
|
-
*
|
|
26
|
-
* If `loading` is true, this button becomes disabled.
|
|
27
|
-
*/
|
|
28
|
-
loading?: boolean,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type FavoriteProps = Omit<ControlledInput, 'size'> & BaseFavoriteProps
|
|
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
|
-
*/
|
|
45
|
-
export const Favorite = withRef(({ value, size, appearance, onChange, loading, disabled, className, ...props }: FavoriteProps) =>
|
|
46
|
-
<CitricComponent
|
|
47
|
-
tag="input"
|
|
48
|
-
type="checkbox"
|
|
49
|
-
component="favorite"
|
|
50
|
-
className={listToClass([appearance, size, className])}
|
|
51
|
-
checked={!!value}
|
|
52
|
-
onChange={() => onChange(!value)}
|
|
53
|
-
aria-busy={loading}
|
|
54
|
-
disabled={loading || disabled}
|
|
55
|
-
{...props}
|
|
56
|
-
/>,
|
|
57
|
-
)
|
|
1
|
+
import { listToClass } from '@stack-spot/portal-theme'
|
|
2
|
+
import { ControlledInput } from '../types'
|
|
3
|
+
import { withRef } from '../utils/react'
|
|
4
|
+
import { CitricComponent } from './CitricComponent'
|
|
5
|
+
|
|
6
|
+
type FavoriteAppearance = 'square' | 'circle' | 'text'
|
|
7
|
+
|
|
8
|
+
export interface BaseFavoriteProps {
|
|
9
|
+
value: boolean | undefined,
|
|
10
|
+
/**
|
|
11
|
+
* Size of the button.
|
|
12
|
+
*
|
|
13
|
+
* @default 'md'
|
|
14
|
+
*/
|
|
15
|
+
size?: 'sm' | 'md' | 'lg' | 'fit-parent',
|
|
16
|
+
/**
|
|
17
|
+
* Button appearance.
|
|
18
|
+
*
|
|
19
|
+
* @default 'text'
|
|
20
|
+
*/
|
|
21
|
+
appearance?: FavoriteAppearance,
|
|
22
|
+
onChange: (value: boolean) => void,
|
|
23
|
+
/**
|
|
24
|
+
* Whether or not to show the loading feedback.
|
|
25
|
+
*
|
|
26
|
+
* If `loading` is true, this button becomes disabled.
|
|
27
|
+
*/
|
|
28
|
+
loading?: boolean,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type FavoriteProps = Omit<ControlledInput, 'size'> & BaseFavoriteProps
|
|
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
|
+
*/
|
|
45
|
+
export const Favorite = withRef(({ value, size, appearance, onChange, loading, disabled, className, ...props }: FavoriteProps) =>
|
|
46
|
+
<CitricComponent
|
|
47
|
+
tag="input"
|
|
48
|
+
type="checkbox"
|
|
49
|
+
component="favorite"
|
|
50
|
+
className={listToClass([appearance, size, className])}
|
|
51
|
+
checked={!!value}
|
|
52
|
+
onChange={() => onChange(!value)}
|
|
53
|
+
aria-busy={loading}
|
|
54
|
+
disabled={loading || disabled}
|
|
55
|
+
{...props}
|
|
56
|
+
/>,
|
|
57
|
+
)
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { listToClass } from '@stack-spot/portal-theme'
|
|
2
|
-
import { withRef } from '../utils/react'
|
|
3
|
-
import { CitricComponent } from './CitricComponent'
|
|
4
|
-
|
|
5
|
-
export interface BaseFieldGroupProps {
|
|
6
|
-
/**
|
|
7
|
-
* When this is true, the component will automatically mark the addons.
|
|
8
|
-
*
|
|
9
|
-
* When this is false, you must add the class "addon" manually to each of the addons.
|
|
10
|
-
*
|
|
11
|
-
* @default true
|
|
12
|
-
*/
|
|
13
|
-
auto?: boolean,
|
|
14
|
-
/**
|
|
15
|
-
* When this is true, the FieldGroup will occupy all the width available instead of just what its children need.
|
|
16
|
-
*
|
|
17
|
-
* @default false
|
|
18
|
-
*/
|
|
19
|
-
fullWidth?: boolean,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type FieldGroupProps = React.JSX.IntrinsicElements['div'] & BaseFieldGroupProps
|
|
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
|
-
*/
|
|
37
|
-
export const FieldGroup = withRef(({ auto = true, fullWidth, className, children, ...props }: FieldGroupProps) => (
|
|
38
|
-
<CitricComponent
|
|
39
|
-
tag="div"
|
|
40
|
-
component="field-group"
|
|
41
|
-
className={listToClass([className, auto && 'auto', fullWidth && 'full-width'])}
|
|
42
|
-
{...props}
|
|
43
|
-
>
|
|
44
|
-
{children}
|
|
45
|
-
</CitricComponent>
|
|
46
|
-
))
|
|
1
|
+
import { listToClass } from '@stack-spot/portal-theme'
|
|
2
|
+
import { withRef } from '../utils/react'
|
|
3
|
+
import { CitricComponent } from './CitricComponent'
|
|
4
|
+
|
|
5
|
+
export interface BaseFieldGroupProps {
|
|
6
|
+
/**
|
|
7
|
+
* When this is true, the component will automatically mark the addons.
|
|
8
|
+
*
|
|
9
|
+
* When this is false, you must add the class "addon" manually to each of the addons.
|
|
10
|
+
*
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
auto?: boolean,
|
|
14
|
+
/**
|
|
15
|
+
* When this is true, the FieldGroup will occupy all the width available instead of just what its children need.
|
|
16
|
+
*
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
fullWidth?: boolean,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type FieldGroupProps = React.JSX.IntrinsicElements['div'] & BaseFieldGroupProps
|
|
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
|
+
*/
|
|
37
|
+
export const FieldGroup = withRef(({ auto = true, fullWidth, className, children, ...props }: FieldGroupProps) => (
|
|
38
|
+
<CitricComponent
|
|
39
|
+
tag="div"
|
|
40
|
+
component="field-group"
|
|
41
|
+
className={listToClass([className, auto && 'auto', fullWidth && 'full-width'])}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
</CitricComponent>
|
|
46
|
+
))
|