@tecsinapse/cortex-react 1.0.2
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/README.md +11 -0
- package/package.json +33 -0
- package/src/components/Badge.tsx +45 -0
- package/src/components/Button.tsx +19 -0
- package/src/components/Card.tsx +18 -0
- package/src/components/Hint.tsx +31 -0
- package/src/components/Input.tsx +110 -0
- package/src/components/Modal.tsx +24 -0
- package/src/components/SearchInput.tsx +86 -0
- package/src/components/Select.tsx +170 -0
- package/src/components/Snackbar.tsx +26 -0
- package/src/components/Tag.tsx +19 -0
- package/src/components/TextArea.tsx +121 -0
- package/src/components/Toggle.tsx +25 -0
- package/src/components/index.ts +11 -0
- package/src/docs/badge-anchor.stories.tsx +42 -0
- package/src/docs/badge.stories.tsx +31 -0
- package/src/docs/button.stories.tsx +37 -0
- package/src/docs/card.stories.tsx +29 -0
- package/src/docs/hint.stories.tsx +32 -0
- package/src/docs/input-custom.stories.tsx +45 -0
- package/src/docs/input.stories.tsx +40 -0
- package/src/docs/modal.stories.tsx +48 -0
- package/src/docs/select-grouped.stories.tsx +79 -0
- package/src/docs/select.stories.tsx +70 -0
- package/src/docs/snackbar.stories.tsx +31 -0
- package/src/docs/tag.stories.tsx +37 -0
- package/src/docs/text-area.stories.tsx +50 -0
- package/src/docs/toggle.stories.tsx +18 -0
- package/src/docs/utils.ts +8 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDebouncedState.ts +24 -0
- package/src/index.ts +1 -0
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tecsinapse/cortex-react",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "React components based in @tecsinapse/cortex-core",
|
|
5
|
+
"author": "ryancarloscorrea <ryancarlos38@gmail.com>",
|
|
6
|
+
"homepage": "https://github.com/tecsinapse/design-system#readme",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"main": "src/index.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/tecsinapse/design-system.git"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "rollup --config --watch",
|
|
18
|
+
"dev:dts": "tsc --project tsconfig.build.json --watch",
|
|
19
|
+
"build:es": "rollup --config",
|
|
20
|
+
"build:dts": "tsc --project tsconfig.build.json"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/tecsinapse/design-system/issues"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"tailwind": ">=3.3.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@tecsinapse/cortex-core": "0.1.10",
|
|
30
|
+
"clsx": "*",
|
|
31
|
+
"react-icons": "^5.2.1"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { forwardRef, HTMLProps } from 'react';
|
|
2
|
+
import { badge, BadgeVariants, containerBadge } from '@tecsinapse/cortex-core';
|
|
3
|
+
|
|
4
|
+
interface BadgeProps {
|
|
5
|
+
value: string | number;
|
|
6
|
+
variants?: BadgeVariants;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface BadgeAnchorProps extends BadgeProps {
|
|
10
|
+
children: JSX.Element;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const Badge = forwardRef<
|
|
14
|
+
HTMLDivElement,
|
|
15
|
+
BadgeProps & Omit<HTMLProps<HTMLDivElement>, 'className'>
|
|
16
|
+
>((props, ref) => {
|
|
17
|
+
const { value, variants, ...rest } = props;
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={badge({
|
|
22
|
+
className: `relative ${variants?.className}`,
|
|
23
|
+
intent: variants?.intent,
|
|
24
|
+
})}
|
|
25
|
+
{...rest}
|
|
26
|
+
>
|
|
27
|
+
{value}
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const BadgeAnchor = forwardRef<
|
|
33
|
+
HTMLDivElement,
|
|
34
|
+
BadgeAnchorProps & Omit<HTMLProps<HTMLDivElement>, 'className'>
|
|
35
|
+
>((props, ref) => {
|
|
36
|
+
const { value, variants, children, ...rest } = props;
|
|
37
|
+
return (
|
|
38
|
+
<div className={containerBadge()}>
|
|
39
|
+
{children}
|
|
40
|
+
<div ref={ref} className={badge(variants)} {...rest}>
|
|
41
|
+
{value}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { button, ButtonVariants } from '@tecsinapse/cortex-core';
|
|
3
|
+
|
|
4
|
+
interface ButtonProps {
|
|
5
|
+
variants?: ButtonVariants;
|
|
6
|
+
children?: JSX.Element;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const Button = forwardRef<
|
|
10
|
+
HTMLButtonElement,
|
|
11
|
+
ButtonProps & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className'>
|
|
12
|
+
>((props, ref) => {
|
|
13
|
+
const { variants, children, ...rest } = props;
|
|
14
|
+
return (
|
|
15
|
+
<button className={button(variants)} ref={ref} {...rest}>
|
|
16
|
+
{children}
|
|
17
|
+
</button>
|
|
18
|
+
);
|
|
19
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { forwardRef, HTMLProps } from 'react'
|
|
2
|
+
import { card } from '@tecsinapse/cortex-core'
|
|
3
|
+
|
|
4
|
+
interface CardProps {
|
|
5
|
+
children: JSX.Element
|
|
6
|
+
}
|
|
7
|
+
export const Card = forwardRef<HTMLDivElement, CardProps & HTMLProps<HTMLDivElement>>((props, ref) => {
|
|
8
|
+
const { children, className, ...rest } = props
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
className={card({ className })}
|
|
12
|
+
ref={ref}
|
|
13
|
+
{...rest}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React, { forwardRef, HTMLProps } from 'react'
|
|
2
|
+
import { hint, HintVariants } from '@tecsinapse/cortex-core'
|
|
3
|
+
|
|
4
|
+
interface HintProps {
|
|
5
|
+
children?: never
|
|
6
|
+
description: string
|
|
7
|
+
variants?: HintVariants
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface HintPropsWithChildrenProps {
|
|
11
|
+
children: JSX.Element
|
|
12
|
+
description?: never
|
|
13
|
+
variants?: HintVariants
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type HintPropsUnion = HintProps | HintPropsWithChildrenProps
|
|
17
|
+
|
|
18
|
+
export const Hint = forwardRef<HTMLDivElement, HintPropsUnion & Omit<HTMLProps<HTMLDivElement>, 'className'>>(
|
|
19
|
+
(props, ref) => {
|
|
20
|
+
const { description, children, variants } = props
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
className={hint(variants)}
|
|
24
|
+
ref={ref}
|
|
25
|
+
>
|
|
26
|
+
{description ? <p>{description}</p> : <></>}
|
|
27
|
+
{children}
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
input,
|
|
4
|
+
InputBaseVariants,
|
|
5
|
+
inputBox,
|
|
6
|
+
labelStyle,
|
|
7
|
+
} from '@tecsinapse/cortex-core';
|
|
8
|
+
import { clsx } from 'clsx';
|
|
9
|
+
|
|
10
|
+
const getValidChildren = (children: React.ReactNode) => {
|
|
11
|
+
return React.Children.toArray(children).filter(el =>
|
|
12
|
+
React.isValidElement(el)
|
|
13
|
+
) as React.ReactElement[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
interface InputPropsBase {
|
|
17
|
+
variants?: InputBaseVariants;
|
|
18
|
+
label?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface InputProps
|
|
22
|
+
extends React.InputHTMLAttributes<HTMLInputElement>,
|
|
23
|
+
InputPropsBase {}
|
|
24
|
+
|
|
25
|
+
export const Box = React.forwardRef<HTMLInputElement, InputProps>(
|
|
26
|
+
({ id, name, variants, label, placeholder, className, ...rest }, ref) => {
|
|
27
|
+
return (
|
|
28
|
+
<div className={'flex w-full flex-col'}>
|
|
29
|
+
<input
|
|
30
|
+
id={id ?? name}
|
|
31
|
+
name={name}
|
|
32
|
+
placeholder={placeholder ?? ' '}
|
|
33
|
+
className={clsx(inputBox(placeholder, label, className))}
|
|
34
|
+
{...rest}
|
|
35
|
+
ref={ref}
|
|
36
|
+
/>
|
|
37
|
+
<label
|
|
38
|
+
htmlFor={id ?? name}
|
|
39
|
+
className={labelStyle({ intent: variants?.intent, placeholder })}
|
|
40
|
+
>
|
|
41
|
+
{label}
|
|
42
|
+
</label>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
type DivBaseProps = React.HTMLAttributes<HTMLDivElement>;
|
|
49
|
+
type InputFaceProps = DivBaseProps & Pick<InputPropsBase, 'variants'>;
|
|
50
|
+
|
|
51
|
+
export const Face = React.forwardRef<HTMLDivElement, InputFaceProps>(
|
|
52
|
+
({ children, variants, className, ...rest }, ref) => {
|
|
53
|
+
const clones = getValidChildren(children).map(el => {
|
|
54
|
+
return React.cloneElement(el, { ...el.props, variants });
|
|
55
|
+
});
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
{...rest}
|
|
59
|
+
className={clsx(input(variants), className)}
|
|
60
|
+
id={'input-face'}
|
|
61
|
+
ref={ref}
|
|
62
|
+
>
|
|
63
|
+
{clones}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export const Root = React.forwardRef<HTMLInputElement, InputProps>(
|
|
70
|
+
({ variants, className, ...rest }, ref) => {
|
|
71
|
+
return (
|
|
72
|
+
<Face variants={variants} className={className}>
|
|
73
|
+
<Box {...rest} ref={ref} />
|
|
74
|
+
</Face>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
type InputElementsProps = DivBaseProps & {
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const Left = React.forwardRef<HTMLDivElement, InputElementsProps>(
|
|
85
|
+
({ children, className, ...rest }, ref) => {
|
|
86
|
+
return (
|
|
87
|
+
<div className={clsx(className, 'mr-2.5')} {...rest} ref={ref}>
|
|
88
|
+
{children}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
export const Right = React.forwardRef<HTMLDivElement, InputElementsProps>(
|
|
95
|
+
({ children, className, ...rest }, ref) => {
|
|
96
|
+
return (
|
|
97
|
+
<div className={clsx(className, 'ml-2.5')} {...rest} ref={ref}>
|
|
98
|
+
{children}
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
export const Input = {
|
|
105
|
+
Root,
|
|
106
|
+
Face,
|
|
107
|
+
Box,
|
|
108
|
+
Left,
|
|
109
|
+
Right,
|
|
110
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { forwardRef, InputHTMLAttributes } from 'react'
|
|
2
|
+
import { modal, overlay } from '@tecsinapse/cortex-core'
|
|
3
|
+
|
|
4
|
+
interface ModalProps {
|
|
5
|
+
open: boolean
|
|
6
|
+
onClose: () => void
|
|
7
|
+
children: JSX.Element
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Modal = forwardRef<HTMLDivElement, ModalProps & InputHTMLAttributes<HTMLInputElement>>((props, ref) => {
|
|
11
|
+
const { open, onClose, children, className } = props
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
ref={ref}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<div
|
|
18
|
+
className={overlay({ show: open })}
|
|
19
|
+
onClick={onClose}
|
|
20
|
+
></div>
|
|
21
|
+
<dialog className={modal({ open, className })}>{children}</dialog>
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
24
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// import { Button, Input, searchInputVariants } from '@web/modules/core'
|
|
2
|
+
import React, { useEffect, useState } from 'react';
|
|
3
|
+
// import CircularLoading from './CircularLoading'
|
|
4
|
+
import { Input, Button } from './';
|
|
5
|
+
import { AiOutlineLoading } from 'react-icons/ai';
|
|
6
|
+
import { IoSearchOutline } from 'react-icons/io5';
|
|
7
|
+
import { useDebouncedState } from '../hooks';
|
|
8
|
+
|
|
9
|
+
interface SearchInputProps {
|
|
10
|
+
label?: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
isSubmitting?: boolean;
|
|
13
|
+
onChange?: (value: string) => void;
|
|
14
|
+
onClick?: (value: string) => void;
|
|
15
|
+
BOUNCE_TIMEOUT?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const inputFace = 'bg-white w-full';
|
|
19
|
+
const inputLeft = 'flex items-center';
|
|
20
|
+
const SearchInput = ({
|
|
21
|
+
label,
|
|
22
|
+
placeholder,
|
|
23
|
+
isSubmitting = false,
|
|
24
|
+
onChange,
|
|
25
|
+
onClick,
|
|
26
|
+
BOUNCE_TIMEOUT = 1000,
|
|
27
|
+
}: SearchInputProps) => {
|
|
28
|
+
const [bouncedText, setBouncedText] = useState<string>('');
|
|
29
|
+
const [searchInput, setSearchInput] = useDebouncedState<string>(
|
|
30
|
+
'',
|
|
31
|
+
setBouncedText,
|
|
32
|
+
BOUNCE_TIMEOUT
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (onChange) {
|
|
37
|
+
onChange(bouncedText);
|
|
38
|
+
}
|
|
39
|
+
}, [bouncedText]);
|
|
40
|
+
|
|
41
|
+
const handleEnterKey = (e: React.KeyboardEvent) => {
|
|
42
|
+
if (e.key === 'Enter' && onClick && searchInput) {
|
|
43
|
+
onClick(searchInput);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="flex flex-row w-full space-x-mili">
|
|
49
|
+
<Input.Face variants={{ className: inputFace }}>
|
|
50
|
+
{!onClick && (
|
|
51
|
+
<Input.Left className={inputLeft}>
|
|
52
|
+
<IoSearchOutline />
|
|
53
|
+
</Input.Left>
|
|
54
|
+
)}
|
|
55
|
+
<Input.Box
|
|
56
|
+
placeholder={placeholder}
|
|
57
|
+
label={label}
|
|
58
|
+
onChange={e => setSearchInput(e.target.value)}
|
|
59
|
+
onKeyDown={handleEnterKey}
|
|
60
|
+
disabled={isSubmitting}
|
|
61
|
+
/>
|
|
62
|
+
</Input.Face>
|
|
63
|
+
{onClick && (
|
|
64
|
+
<Button
|
|
65
|
+
variants={{
|
|
66
|
+
intent: 'primary',
|
|
67
|
+
size: 'square',
|
|
68
|
+
className: 'h-11',
|
|
69
|
+
}}
|
|
70
|
+
onClick={() => onClick(searchInput)}
|
|
71
|
+
disabled={!searchInput || isSubmitting}
|
|
72
|
+
>
|
|
73
|
+
{isSubmitting ? (
|
|
74
|
+
<div className={'animate-spin'}>
|
|
75
|
+
<AiOutlineLoading />
|
|
76
|
+
</div>
|
|
77
|
+
) : (
|
|
78
|
+
<IoSearchOutline />
|
|
79
|
+
)}
|
|
80
|
+
</Button>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export default SearchInput;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { option as styleOption, selectVariants } from '@tecsinapse/cortex-core';
|
|
2
|
+
import React, {
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import { Hint } from './Hint';
|
|
10
|
+
import { IoChevronDownOutline } from 'react-icons/io5';
|
|
11
|
+
import { IoIosCloseCircleOutline } from 'react-icons/io';
|
|
12
|
+
import SearchInput from './SearchInput';
|
|
13
|
+
|
|
14
|
+
interface CommonProps<T> {
|
|
15
|
+
label: string;
|
|
16
|
+
value: T | undefined;
|
|
17
|
+
onSelect: (value: T) => void;
|
|
18
|
+
keyExtractor: (value: T) => string;
|
|
19
|
+
labelExtractor: (value: T) => string;
|
|
20
|
+
onSearch?: (search: string) => void;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
grouped?: boolean;
|
|
23
|
+
variant?: 'error' | 'default';
|
|
24
|
+
hint?: string;
|
|
25
|
+
placeholderSearchInput?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface GroupedProps<T> {
|
|
29
|
+
options?: Map<string, T[]>;
|
|
30
|
+
groupedLabelExtractor: (value: string) => string;
|
|
31
|
+
grouped: true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface DefaultProps<T> {
|
|
35
|
+
options?: T[];
|
|
36
|
+
groupedLabelExtractor?: never;
|
|
37
|
+
grouped?: never;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ConditionalProps<T> = GroupedProps<T> | DefaultProps<T>;
|
|
41
|
+
|
|
42
|
+
type SelectProps<T> = CommonProps<T> & ConditionalProps<T>;
|
|
43
|
+
|
|
44
|
+
const { button, dropdown, groupedTitle, containerGrouped, hintBody } =
|
|
45
|
+
selectVariants();
|
|
46
|
+
|
|
47
|
+
export const Select = <T,>(props: SelectProps<T>) => {
|
|
48
|
+
const {
|
|
49
|
+
label,
|
|
50
|
+
keyExtractor,
|
|
51
|
+
labelExtractor,
|
|
52
|
+
options,
|
|
53
|
+
value,
|
|
54
|
+
onSelect,
|
|
55
|
+
onSearch,
|
|
56
|
+
disabled,
|
|
57
|
+
grouped,
|
|
58
|
+
groupedLabelExtractor,
|
|
59
|
+
hint,
|
|
60
|
+
placeholderSearchInput,
|
|
61
|
+
variant = 'default',
|
|
62
|
+
} = props;
|
|
63
|
+
const [open, setOpen] = useState(false);
|
|
64
|
+
const placeholder = useMemo(
|
|
65
|
+
() => (value ? labelExtractor(value) : label),
|
|
66
|
+
[label, labelExtractor, value]
|
|
67
|
+
);
|
|
68
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
69
|
+
|
|
70
|
+
const handleClickOutside = useCallback((event: any) => {
|
|
71
|
+
if (ref.current && !ref.current.contains(event.target)) {
|
|
72
|
+
setOpen(false);
|
|
73
|
+
}
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
const handleSelect = useCallback(
|
|
77
|
+
(option: T) => {
|
|
78
|
+
onSelect(option);
|
|
79
|
+
setOpen(false);
|
|
80
|
+
},
|
|
81
|
+
[onSelect]
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
document.addEventListener('click', handleClickOutside, true);
|
|
86
|
+
return () => {
|
|
87
|
+
document.removeEventListener('click', handleClickOutside, true);
|
|
88
|
+
};
|
|
89
|
+
}, [handleClickOutside]);
|
|
90
|
+
|
|
91
|
+
const Option = ({ option }: { option: T }) => (
|
|
92
|
+
<li
|
|
93
|
+
onClick={() => handleSelect(option)}
|
|
94
|
+
className={styleOption()}
|
|
95
|
+
role={'option'}
|
|
96
|
+
>
|
|
97
|
+
{labelExtractor(option)}
|
|
98
|
+
</li>
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const GroupedOptions = ({ options }: { options?: Map<string, T[]> }) => (
|
|
102
|
+
<>
|
|
103
|
+
{[...(options ?? [])].map(([key, value]) => (
|
|
104
|
+
<div key={key} className={containerGrouped()}>
|
|
105
|
+
<span className={groupedTitle()}>{groupedLabelExtractor?.(key)}</span>
|
|
106
|
+
{value.map((option: T) => (
|
|
107
|
+
<Option option={option} key={keyExtractor(option)} />
|
|
108
|
+
))}
|
|
109
|
+
</div>
|
|
110
|
+
))}
|
|
111
|
+
</>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const DefaultOptions = ({ options }: { options?: T[] }) => (
|
|
115
|
+
<>
|
|
116
|
+
{(options ?? []).map(option => (
|
|
117
|
+
<Option option={option} key={keyExtractor(option)} />
|
|
118
|
+
))}
|
|
119
|
+
</>
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div className="w-full relative bg-white" ref={ref}>
|
|
124
|
+
<button
|
|
125
|
+
className={button({ disabled, intent: variant })}
|
|
126
|
+
onClick={() => setOpen(prevState => !prevState)}
|
|
127
|
+
disabled={disabled}
|
|
128
|
+
>
|
|
129
|
+
<span>{placeholder}</span>
|
|
130
|
+
<IoChevronDownOutline />
|
|
131
|
+
</button>
|
|
132
|
+
<ul
|
|
133
|
+
role={'select'}
|
|
134
|
+
className={dropdown({
|
|
135
|
+
open,
|
|
136
|
+
})}
|
|
137
|
+
>
|
|
138
|
+
{onSearch ? (
|
|
139
|
+
<div className="m-mili">
|
|
140
|
+
<SearchInput
|
|
141
|
+
placeholder={placeholderSearchInput}
|
|
142
|
+
onChange={onSearch}
|
|
143
|
+
/>
|
|
144
|
+
</div>
|
|
145
|
+
) : (
|
|
146
|
+
<></>
|
|
147
|
+
)}
|
|
148
|
+
{grouped ? (
|
|
149
|
+
<GroupedOptions options={options} />
|
|
150
|
+
) : (
|
|
151
|
+
<DefaultOptions options={options} />
|
|
152
|
+
)}
|
|
153
|
+
</ul>
|
|
154
|
+
{hint && (
|
|
155
|
+
<Hint
|
|
156
|
+
variants={{
|
|
157
|
+
intent: variant,
|
|
158
|
+
}}
|
|
159
|
+
>
|
|
160
|
+
<div className={hintBody()}>
|
|
161
|
+
{variant === 'error' ? <IoIosCloseCircleOutline /> : <></>}
|
|
162
|
+
<span>{hint}</span>
|
|
163
|
+
</div>
|
|
164
|
+
</Hint>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export default Select;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
import { snackbar, SnackbarVariants } from '@tecsinapse/cortex-core'
|
|
3
|
+
|
|
4
|
+
interface SnackbarProps {
|
|
5
|
+
variants?: SnackbarVariants
|
|
6
|
+
children: JSX.Element
|
|
7
|
+
show: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Snackbar = forwardRef<HTMLDivElement, SnackbarProps>((props, ref) => {
|
|
11
|
+
const { children, show, variants } = props
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
{show ? (
|
|
15
|
+
<div
|
|
16
|
+
className={snackbar(variants)}
|
|
17
|
+
ref={ref}
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</div>
|
|
21
|
+
) : (
|
|
22
|
+
<></>
|
|
23
|
+
)}
|
|
24
|
+
</>
|
|
25
|
+
)
|
|
26
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { forwardRef, HTMLProps } from 'react'
|
|
2
|
+
import { tag, TagVariants } from '@tecsinapse/cortex-core'
|
|
3
|
+
|
|
4
|
+
interface TagProps {
|
|
5
|
+
variants?: TagVariants
|
|
6
|
+
label: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const Tag = forwardRef<HTMLDivElement, TagProps & HTMLProps<HTMLDivElement>>((props, ref) => {
|
|
10
|
+
const { label, variants } = props
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
className={tag(variants)}
|
|
14
|
+
ref={ref}
|
|
15
|
+
>
|
|
16
|
+
<p>{label}</p>
|
|
17
|
+
</div>
|
|
18
|
+
)
|
|
19
|
+
})
|