react-artasys-ui 0.1.6 → 0.1.8
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/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/Components/Arrow/Arrow.d.ts +6 -0
- package/lib/Components/Arrow/index.d.ts +2 -0
- package/lib/Dropdown/Dropdown.d.ts +13 -0
- package/lib/Dropdown/Item.d.ts +11 -0
- package/lib/Dropdown/index.d.ts +9 -0
- package/lib/Select/Optgroup.d.ts +8 -0
- package/lib/Select/Option.d.ts +2 -1
- package/lib/Select/Select.d.ts +7 -5
- package/lib/Select/index.d.ts +3 -1
- package/lib/index.d.ts +3 -2
- package/package.json +1 -1
- package/src/Components/Arrow/Arrow.tsx +18 -0
- package/src/Components/Arrow/index.tsx +3 -0
- package/src/Components/Arrow/style.module.css +40 -0
- package/src/Dropdown/Dropdown.tsx +102 -0
- package/src/Dropdown/Item.tsx +42 -0
- package/src/Dropdown/index.tsx +28 -0
- package/src/Dropdown/style.module.css +67 -0
- package/src/Select/Optgroup.tsx +19 -0
- package/src/Select/Option.tsx +6 -3
- package/src/Select/Select.tsx +52 -11
- package/src/Select/index.tsx +8 -2
- package/src/Select/style.module.css +33 -16
- package/src/index.ts +9 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AllHTMLAttributes, FunctionComponentElement } from "react";
|
|
2
|
+
import type { IItem, TChildrenAction } from "./Item";
|
|
3
|
+
export declare const Context: import("react").Context<TChildrenAction>;
|
|
4
|
+
export interface IDropdown extends AllHTMLAttributes<HTMLDivElement> {
|
|
5
|
+
direction?: 'down' | 'up';
|
|
6
|
+
position?: 'left' | 'right';
|
|
7
|
+
split?: boolean;
|
|
8
|
+
hover?: boolean;
|
|
9
|
+
items?: FunctionComponentElement<IItem> | FunctionComponentElement<IItem>[];
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const Dropdown: ({ children, className, items, direction, position, split, disabled, hover, ...props }: IDropdown) => JSX.Element;
|
|
13
|
+
export default Dropdown;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AllHTMLAttributes, ReactElement } from "react";
|
|
2
|
+
export type TChildrenAction = {
|
|
3
|
+
close: () => void;
|
|
4
|
+
};
|
|
5
|
+
export interface IItem extends Omit<AllHTMLAttributes<HTMLLIElement>, 'children'> {
|
|
6
|
+
children?: ((action: TChildrenAction) => ReactElement) | string | ReactElement;
|
|
7
|
+
autoClose?: boolean;
|
|
8
|
+
active?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const Item: ({ children, onClick, autoClose, active, className, ...props }: IItem) => JSX.Element;
|
|
11
|
+
export default Item;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RefAttributes, ForwardRefExoticComponent, FC } from "react";
|
|
2
|
+
import { IDropdown } from "./Dropdown";
|
|
3
|
+
import Item, { IItem } from "./Item";
|
|
4
|
+
interface StaticComponent extends ForwardRefExoticComponent<IDropdown & RefAttributes<HTMLInputElement>> {
|
|
5
|
+
Item: FC<IItem>;
|
|
6
|
+
}
|
|
7
|
+
declare const Dropdown: StaticComponent;
|
|
8
|
+
export { Item as DropdownItem };
|
|
9
|
+
export default Dropdown;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { TOptionElement } from "./Select";
|
|
3
|
+
export interface IOptgroup {
|
|
4
|
+
children?: TOptionElement;
|
|
5
|
+
label?: string | React.ReactElement;
|
|
6
|
+
}
|
|
7
|
+
declare const Optgroup: ({ children, label }: IOptgroup) => JSX.Element;
|
|
8
|
+
export default Optgroup;
|
package/lib/Select/Option.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { LiHTMLAttributes } from "react";
|
|
2
2
|
export interface IOption extends LiHTMLAttributes<HTMLLIElement> {
|
|
3
3
|
value?: string;
|
|
4
|
+
disabled?: boolean;
|
|
4
5
|
children?: string | React.ReactElement;
|
|
5
6
|
}
|
|
6
|
-
declare const Option: ({ children, value, onClick, ...props }: IOption) => JSX.Element;
|
|
7
|
+
declare const Option: ({ children, value, disabled, onClick, ...props }: IOption) => JSX.Element;
|
|
7
8
|
export default Option;
|
package/lib/Select/Select.d.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { FunctionComponentElement } from "react";
|
|
2
2
|
import { IElement } from "../Form/Element";
|
|
3
|
+
import type { IOptgroup } from "./Optgroup";
|
|
3
4
|
import type { IOption } from "./Option";
|
|
4
5
|
export declare const Context: import("react").Context<{
|
|
5
6
|
selected: string;
|
|
6
7
|
emptyValue: import("react").MutableRefObject<boolean>;
|
|
7
8
|
setSelect: (value: string) => void;
|
|
8
9
|
setSelected: (value: string) => void;
|
|
9
|
-
setTitle: (title:
|
|
10
|
+
setTitle: (title: IOption['children']) => void;
|
|
10
11
|
}>;
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export type TOptionElement = FunctionComponentElement<IOption> | FunctionComponentElement<IOption>[];
|
|
13
|
+
export interface ISelect extends Omit<IElement, 'children'> {
|
|
14
|
+
children?: TOptionElement | FunctionComponentElement<IOptgroup> | FunctionComponentElement<IOptgroup>[];
|
|
15
|
+
onChangeSelect?: (value: string) => void;
|
|
14
16
|
}
|
|
15
17
|
declare const Select: import("react").ForwardRefExoticComponent<ISelect & import("react").RefAttributes<HTMLInputElement>>;
|
|
16
18
|
export default Select;
|
package/lib/Select/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ForwardRefExoticComponent, FC, RefAttributes } from "react";
|
|
2
2
|
import { ISelect } from "./Select";
|
|
3
3
|
import Option, { IOption } from "./Option";
|
|
4
|
+
import Optgroup, { IOptgroup } from "./Optgroup";
|
|
4
5
|
interface StaticComponent extends ForwardRefExoticComponent<ISelect & RefAttributes<HTMLInputElement>> {
|
|
5
6
|
Option: FC<IOption>;
|
|
7
|
+
Optgroup: FC<IOptgroup>;
|
|
6
8
|
}
|
|
7
9
|
declare const Select: StaticComponent;
|
|
8
|
-
export { Option as SelectOption };
|
|
10
|
+
export { Option as SelectOption, Optgroup as SelectOptgroup };
|
|
9
11
|
export default Select;
|
package/lib/index.d.ts
CHANGED
|
@@ -8,8 +8,9 @@ import Button from "./Button";
|
|
|
8
8
|
import UploadImages, { IUploadImages, TImageData, IImage } from "./UploadImages";
|
|
9
9
|
import Checkbox from "./Checkbox";
|
|
10
10
|
import Progress from "./Progress";
|
|
11
|
-
import Select, { SelectOption } from "./Select";
|
|
11
|
+
import Select, { SelectOption, SelectOptgroup } from "./Select";
|
|
12
|
+
import Dropdown, { DropdownItem } from "./Dropdown";
|
|
12
13
|
declare const UI: {};
|
|
13
|
-
export { Form, FormElement, Element, useForm, Input, TextArea, Spinner, File, Button, UploadImages, Checkbox, Progress, Select, SelectOption };
|
|
14
|
+
export { Form, FormElement, Element, useForm, Input, TextArea, Spinner, File, Button, UploadImages, Checkbox, Progress, Select, SelectOption, SelectOptgroup, Dropdown, DropdownItem };
|
|
14
15
|
export type { TFileData, TFileMime, IUploadImages, IImage, TImageData, IElement };
|
|
15
16
|
export default UI;
|
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AllHTMLAttributes } from "react";
|
|
2
|
+
import styles from "./style.module.css";
|
|
3
|
+
|
|
4
|
+
interface IArrow extends AllHTMLAttributes<HTMLDivElement> {
|
|
5
|
+
direction?: 'up' | 'down' | 'left' | 'right';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const Arrow = ({className, direction = 'down', ...props}: IArrow) => {
|
|
9
|
+
|
|
10
|
+
const classes = ['ui-component-arrow'];
|
|
11
|
+
classes.push(styles['container']);
|
|
12
|
+
if (direction) classes.push(styles[direction]);
|
|
13
|
+
if (className) classes.push(className);
|
|
14
|
+
|
|
15
|
+
return(<div {...props} className={classes.join(' ')}/>);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default Arrow;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* Arrow Component */
|
|
2
|
+
|
|
3
|
+
.container {
|
|
4
|
+
--ui-arrow-size: 10px;
|
|
5
|
+
--ui-arrow-color: #5EBED6;
|
|
6
|
+
--ui-arrow-max: var(--ui-arrow-size) solid var(--ui-arrow-color);
|
|
7
|
+
--ui-arrow-min: calc(var(--ui-arrow-size) / 2) solid transparent;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.container::after {
|
|
11
|
+
content: "";
|
|
12
|
+
display: block;
|
|
13
|
+
width: 0;
|
|
14
|
+
height: 0;
|
|
15
|
+
transition: rotate 0.1s;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.container.down::after {
|
|
19
|
+
border-left: var(--ui-arrow-min);
|
|
20
|
+
border-right: var(--ui-arrow-min);
|
|
21
|
+
border-top: var(--ui-arrow-max);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.container.up::after {
|
|
25
|
+
border-left: var(--ui-arrow-min);
|
|
26
|
+
border-right: var(--ui-arrow-min);
|
|
27
|
+
border-bottom: var(--ui-arrow-max);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.container.left::after {
|
|
31
|
+
border-top: var(--ui-arrow-min);
|
|
32
|
+
border-right: var(--ui-arrow-max);
|
|
33
|
+
border-bottom: var(--ui-arrow-min);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.container.right::after {
|
|
37
|
+
border-top: var(--ui-arrow-min);
|
|
38
|
+
border-left: var(--ui-arrow-max);
|
|
39
|
+
border-bottom: var(--ui-arrow-min);
|
|
40
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AllHTMLAttributes,
|
|
3
|
+
useRef,
|
|
4
|
+
useState,
|
|
5
|
+
FunctionComponentElement,
|
|
6
|
+
useEffect,
|
|
7
|
+
createContext
|
|
8
|
+
} from "react";
|
|
9
|
+
import styles from "./style.module.css";
|
|
10
|
+
import Arrow from "../Components/Arrow";
|
|
11
|
+
import type {
|
|
12
|
+
IItem,
|
|
13
|
+
TChildrenAction
|
|
14
|
+
} from "./Item";
|
|
15
|
+
|
|
16
|
+
export const Context = createContext<TChildrenAction>({
|
|
17
|
+
close: () => {}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export interface IDropdown extends AllHTMLAttributes<HTMLDivElement> {
|
|
21
|
+
direction?: 'down' | 'up';
|
|
22
|
+
position?: 'left' | 'right';
|
|
23
|
+
split?: boolean;
|
|
24
|
+
hover?: boolean;
|
|
25
|
+
items?: FunctionComponentElement<IItem> | FunctionComponentElement<IItem>[];
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const Dropdown = ({children, className, items, direction = 'down', position = 'right', split = false, disabled, hover = false, ...props}: IDropdown) => {
|
|
30
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
31
|
+
const [isOpen, setOpen] = useState(false);
|
|
32
|
+
|
|
33
|
+
const close = () => {
|
|
34
|
+
setOpen(false);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const toggle = () => {
|
|
38
|
+
setOpen((isOpen) => {
|
|
39
|
+
if (disabled) return false;
|
|
40
|
+
return !isOpen;
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleClickArrow = () => {
|
|
45
|
+
toggle();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleClick = () => {
|
|
49
|
+
if (!split) {
|
|
50
|
+
toggle();
|
|
51
|
+
}
|
|
52
|
+
if (hover) {
|
|
53
|
+
close();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleBlur = (e: React.FocusEvent) => {
|
|
58
|
+
if (e.currentTarget.contains(e.relatedTarget)) return;
|
|
59
|
+
close();
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleMouseEnter = () => {
|
|
63
|
+
if (!hover || isOpen) return;
|
|
64
|
+
toggle();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const element = containerRef.current;
|
|
69
|
+
const classList = element?.classList;
|
|
70
|
+
if (isOpen) {
|
|
71
|
+
classList?.add(styles['opened']);
|
|
72
|
+
element?.focus();
|
|
73
|
+
}else{
|
|
74
|
+
classList?.remove(styles['opened']);
|
|
75
|
+
}
|
|
76
|
+
}, [isOpen]);
|
|
77
|
+
|
|
78
|
+
const classes = ['ui-dropdown'];
|
|
79
|
+
classes.push(styles['container']);
|
|
80
|
+
if (className) classes.push(className);
|
|
81
|
+
if (direction) classes.push(styles[direction]);
|
|
82
|
+
if (position) classes.push(styles[position]);
|
|
83
|
+
|
|
84
|
+
return(<Context.Provider value={{
|
|
85
|
+
close
|
|
86
|
+
}}>
|
|
87
|
+
<div {...props} className={classes.join(' ')} ref={containerRef} onMouseEnter={handleMouseEnter} tabIndex={1} onBlur={handleBlur}>
|
|
88
|
+
{(position === 'left' && !disabled) && <Arrow className={styles['arrow']} onClick={handleClickArrow}/>}
|
|
89
|
+
<div onClick={handleClick}>
|
|
90
|
+
{children}
|
|
91
|
+
</div>
|
|
92
|
+
{(position === 'right' && !disabled) && <Arrow className={styles['arrow']} onClick={handleClickArrow}/>}
|
|
93
|
+
{
|
|
94
|
+
(items && !disabled) && <ul className={styles['dropdown-list']}>
|
|
95
|
+
{items}
|
|
96
|
+
</ul>
|
|
97
|
+
}
|
|
98
|
+
</div>
|
|
99
|
+
</Context.Provider>);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export default Dropdown;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useContext,
|
|
3
|
+
AllHTMLAttributes,
|
|
4
|
+
ReactElement,
|
|
5
|
+
MouseEvent
|
|
6
|
+
} from "react";
|
|
7
|
+
import styles from "./style.module.css";
|
|
8
|
+
import { Context } from "./Dropdown";
|
|
9
|
+
|
|
10
|
+
export type TChildrenAction = {
|
|
11
|
+
close: () => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export interface IItem extends Omit<AllHTMLAttributes<HTMLLIElement>, 'children'> {
|
|
15
|
+
children?: ((action: TChildrenAction) => ReactElement) | string | ReactElement;
|
|
16
|
+
autoClose?: boolean;
|
|
17
|
+
active?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const Item = ({children, onClick, autoClose = true, active, className, ...props}: IItem) => {
|
|
21
|
+
const context = useContext(Context);
|
|
22
|
+
|
|
23
|
+
const handleClick = (e: MouseEvent<HTMLLIElement>) => {
|
|
24
|
+
if (typeof onClick === 'function') {
|
|
25
|
+
onClick(e);
|
|
26
|
+
}
|
|
27
|
+
if (autoClose) {
|
|
28
|
+
context.close();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const classes = ['ui-dropdown-item'];
|
|
33
|
+
classes.push(styles['item']);
|
|
34
|
+
if (active) classes.push(styles['active'], 'active');
|
|
35
|
+
if (className) classes.push(className);
|
|
36
|
+
|
|
37
|
+
return(<li {...props} onClick={handleClick} className={classes.join(' ')}>
|
|
38
|
+
{typeof children === 'function' ? children(context) : children}
|
|
39
|
+
</li>);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default Item;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
RefAttributes,
|
|
4
|
+
ForwardRefExoticComponent,
|
|
5
|
+
FC
|
|
6
|
+
} from "react";
|
|
7
|
+
import {
|
|
8
|
+
default as DropdownUI,
|
|
9
|
+
IDropdown
|
|
10
|
+
} from "./Dropdown";
|
|
11
|
+
import Item,{
|
|
12
|
+
IItem
|
|
13
|
+
} from "./Item";
|
|
14
|
+
|
|
15
|
+
interface StaticComponent extends ForwardRefExoticComponent<IDropdown & RefAttributes<HTMLInputElement>> {
|
|
16
|
+
Item: FC<IItem>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const Dropdown: StaticComponent = {
|
|
20
|
+
...forwardRef<HTMLInputElement, IDropdown>(({...args}, ref): JSX.Element => <DropdownUI {...args}/>),
|
|
21
|
+
Item
|
|
22
|
+
} as StaticComponent;
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
Item as DropdownItem
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default Dropdown;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* Dropdown */
|
|
2
|
+
|
|
3
|
+
.container {
|
|
4
|
+
position: relative;
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
flex-direction: row;
|
|
7
|
+
align-items: center;
|
|
8
|
+
outline: none;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.arrow {
|
|
13
|
+
padding: 5px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.dropdown-list {
|
|
17
|
+
position: absolute;
|
|
18
|
+
padding: 0;
|
|
19
|
+
margin: 0;
|
|
20
|
+
background-color: #FFFFFF;
|
|
21
|
+
border-radius: 2px;
|
|
22
|
+
list-style-type: none;
|
|
23
|
+
box-shadow: 0px 0px 9px 2px rgb(0 0 0 / 10%);
|
|
24
|
+
opacity: 0;
|
|
25
|
+
transform: translateY(-10%);
|
|
26
|
+
visibility: hidden;
|
|
27
|
+
z-index: 1;
|
|
28
|
+
transition: opacity 0.3s, visibility 0.3s, transform 0.3s ease;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.container.down > .dropdown-list {
|
|
32
|
+
top: 100%;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.container.up > .dropdown-list {
|
|
36
|
+
bottom: 100%;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.container.left > .dropdown-list {
|
|
40
|
+
left: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.container.right > .dropdown-list {
|
|
44
|
+
right: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.dropdown-list > li.item {
|
|
48
|
+
padding: 7px;
|
|
49
|
+
font-size: 18px;
|
|
50
|
+
font-weight: normal;
|
|
51
|
+
color: #1D1D1B;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.container.opened > .dropdown-list {
|
|
55
|
+
opacity: 1;
|
|
56
|
+
visibility: visible;
|
|
57
|
+
transform: translateY(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.container.opened > .arrow::after {
|
|
61
|
+
rotate: 180deg;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.dropdown-list > li.item:hover, .dropdown-list > li.item:has(:global(a.active)) {
|
|
65
|
+
background-color: #BED4DB;
|
|
66
|
+
border-radius: inherit;
|
|
67
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import styles from "./style.module.css";
|
|
2
|
+
import type { TOptionElement } from "./Select";
|
|
3
|
+
|
|
4
|
+
export interface IOptgroup {
|
|
5
|
+
children?: TOptionElement;
|
|
6
|
+
label?: string | React.ReactElement;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const Optgroup = ({children, label}: IOptgroup) => {
|
|
10
|
+
|
|
11
|
+
return(<li>
|
|
12
|
+
<ul className={styles['optgpoup']}>
|
|
13
|
+
{label && <li className={styles['label']}>{label}</li>}
|
|
14
|
+
{children}
|
|
15
|
+
</ul>
|
|
16
|
+
</li>);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default Optgroup;
|
package/src/Select/Option.tsx
CHANGED
|
@@ -9,14 +9,15 @@ import styles from "./style.module.css";
|
|
|
9
9
|
|
|
10
10
|
export interface IOption extends LiHTMLAttributes<HTMLLIElement> {
|
|
11
11
|
value?: string;
|
|
12
|
+
disabled?: boolean;
|
|
12
13
|
children?: string | React.ReactElement;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
|
-
const Option = ({children, value, onClick, ...props}: IOption) => {
|
|
16
|
+
const Option = ({children, value, disabled, onClick, ...props}: IOption) => {
|
|
16
17
|
const context = useContext(Context);
|
|
17
18
|
|
|
18
19
|
const handleClick = (e: MouseEvent<HTMLLIElement>) => {
|
|
19
|
-
if (typeof value === 'undefined') return;
|
|
20
|
+
if (typeof value === 'undefined' || disabled) return;
|
|
20
21
|
context.setSelect(value);
|
|
21
22
|
if (typeof onClick === 'function') {
|
|
22
23
|
onClick(e);
|
|
@@ -25,7 +26,7 @@ const Option = ({children, value, onClick, ...props}: IOption) => {
|
|
|
25
26
|
|
|
26
27
|
useEffect(() => {
|
|
27
28
|
if (children && (value === context.selected || !context.emptyValue.current)) {
|
|
28
|
-
context.setTitle(children
|
|
29
|
+
context.setTitle(children);
|
|
29
30
|
if (!context.emptyValue.current && value) {
|
|
30
31
|
context.setSelected(value);
|
|
31
32
|
}
|
|
@@ -34,7 +35,9 @@ const Option = ({children, value, onClick, ...props}: IOption) => {
|
|
|
34
35
|
}, [context.selected]);
|
|
35
36
|
|
|
36
37
|
const classes = ['ui-select-option'];
|
|
38
|
+
classes.push(styles['option']);
|
|
37
39
|
if (context.selected === value) classes.push(styles['active'], 'active');
|
|
40
|
+
if (disabled) classes.push(styles['disabled'], 'disabled');
|
|
38
41
|
|
|
39
42
|
return(<li {...props} onClick={handleClick} className={classes.join(' ')}>{children}</li>);
|
|
40
43
|
};
|
package/src/Select/Select.tsx
CHANGED
|
@@ -3,12 +3,17 @@ import {
|
|
|
3
3
|
createContext,
|
|
4
4
|
useState,
|
|
5
5
|
useEffect,
|
|
6
|
-
useRef
|
|
6
|
+
useRef,
|
|
7
|
+
ChangeEvent,
|
|
8
|
+
useImperativeHandle,
|
|
9
|
+
FunctionComponentElement
|
|
7
10
|
} from "react";
|
|
8
11
|
import Element,{
|
|
9
12
|
IElement
|
|
10
13
|
} from "../Form/Element";
|
|
14
|
+
import type { IOptgroup } from "./Optgroup";
|
|
11
15
|
import type { IOption } from "./Option";
|
|
16
|
+
import Arrow from "../Components/Arrow";
|
|
12
17
|
import styles from "./style.module.css";
|
|
13
18
|
|
|
14
19
|
export const Context = createContext({
|
|
@@ -16,21 +21,24 @@ export const Context = createContext({
|
|
|
16
21
|
emptyValue: {current:{}} as React.MutableRefObject<boolean>,
|
|
17
22
|
setSelect: (value: string) => {},
|
|
18
23
|
setSelected: (value: string) => {},
|
|
19
|
-
setTitle: (title:
|
|
24
|
+
setTitle: (title: IOption['children']) => {},
|
|
20
25
|
});
|
|
21
26
|
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
export type TOptionElement = FunctionComponentElement<IOption> | FunctionComponentElement<IOption>[];
|
|
28
|
+
|
|
29
|
+
export interface ISelect extends Omit<IElement, 'children'> {
|
|
30
|
+
children?: TOptionElement | FunctionComponentElement<IOptgroup> | FunctionComponentElement<IOptgroup>[];
|
|
31
|
+
onChangeSelect?: (value: string) => void;
|
|
25
32
|
};
|
|
26
33
|
|
|
27
|
-
const Select = forwardRef<HTMLInputElement, ISelect>(({children,
|
|
34
|
+
const Select = forwardRef<HTMLInputElement, ISelect>(({children, onChangeSelect, value, ...props}, ref) => {
|
|
28
35
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
36
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
29
37
|
const emptyValue = useRef(false);
|
|
30
38
|
|
|
31
39
|
const [isOpen, setOpen] = useState(false);
|
|
32
40
|
const [selected, setSelected] = useState('');
|
|
33
|
-
const [title, setTitle] = useState<
|
|
41
|
+
const [title, setTitle] = useState<IOption['children']>();
|
|
34
42
|
|
|
35
43
|
const open = () => {
|
|
36
44
|
if (props.disabled) return;
|
|
@@ -41,14 +49,44 @@ const Select = forwardRef<HTMLInputElement, ISelect>(({children, onChange, value
|
|
|
41
49
|
setOpen(false);
|
|
42
50
|
};
|
|
43
51
|
|
|
52
|
+
const handleClick = () => {
|
|
53
|
+
isOpen ? close() : open();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const triggerNativeEvent = (value: string) => {
|
|
57
|
+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
58
|
+
nativeInputValueSetter?.call(inputRef.current, value);
|
|
59
|
+
|
|
60
|
+
const event = new Event('input', { bubbles: true});
|
|
61
|
+
inputRef.current!.dispatchEvent(event);
|
|
62
|
+
};
|
|
63
|
+
|
|
44
64
|
const setSelect = (value: string) => {
|
|
45
|
-
if (typeof
|
|
46
|
-
|
|
65
|
+
if (typeof onChangeSelect === 'function') {
|
|
66
|
+
onChangeSelect(value);
|
|
47
67
|
}
|
|
68
|
+
|
|
48
69
|
setSelected(value);
|
|
49
70
|
close();
|
|
50
71
|
};
|
|
51
72
|
|
|
73
|
+
const handleInput = (e: ChangeEvent<HTMLInputElement>) => {
|
|
74
|
+
if (props.disabled) return;
|
|
75
|
+
if (typeof props.onInput === 'function') {
|
|
76
|
+
props.onInput(e);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (typeof props.onChange === 'function') {
|
|
80
|
+
props.onChange(e);
|
|
81
|
+
}
|
|
82
|
+
setSelected(e.target.value);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (!selected) return;
|
|
87
|
+
triggerNativeEvent(selected);
|
|
88
|
+
}, [selected]);
|
|
89
|
+
|
|
52
90
|
useEffect(() => {
|
|
53
91
|
if (typeof value === 'undefined') return;
|
|
54
92
|
setSelected(String(value));
|
|
@@ -74,6 +112,8 @@ const Select = forwardRef<HTMLInputElement, ISelect>(({children, onChange, value
|
|
|
74
112
|
}
|
|
75
113
|
}, [isOpen]);
|
|
76
114
|
|
|
115
|
+
useImperativeHandle(ref, () => inputRef.current as HTMLInputElement, []);
|
|
116
|
+
|
|
77
117
|
const classes = [''];
|
|
78
118
|
classes.push(styles['container'], styles['hidden']);
|
|
79
119
|
|
|
@@ -85,10 +125,11 @@ const Select = forwardRef<HTMLInputElement, ISelect>(({children, onChange, value
|
|
|
85
125
|
setSelected,
|
|
86
126
|
setTitle
|
|
87
127
|
}}>
|
|
88
|
-
<input {...props} type="hidden" value={selected} ref={
|
|
128
|
+
<input {...props} type="hidden" value={selected} onInput={handleInput} ref={inputRef}/>
|
|
89
129
|
<div className={classes.join(' ')} ref={containerRef} tabIndex={1} onBlur={close}>
|
|
90
|
-
<div className={styles['select']} onClick={
|
|
130
|
+
<div className={styles['select']} onClick={handleClick}>
|
|
91
131
|
<span className={styles['title']}>{title}</span>
|
|
132
|
+
<Arrow className={styles['arrow']}/>
|
|
92
133
|
</div>
|
|
93
134
|
<ul className={styles['select-list']}>
|
|
94
135
|
{children}
|
package/src/Select/index.tsx
CHANGED
|
@@ -11,17 +11,23 @@ import {
|
|
|
11
11
|
import Option,{
|
|
12
12
|
IOption
|
|
13
13
|
} from "./Option";
|
|
14
|
+
import Optgroup,{
|
|
15
|
+
IOptgroup
|
|
16
|
+
} from "./Optgroup";
|
|
14
17
|
|
|
15
18
|
interface StaticComponent extends ForwardRefExoticComponent<ISelect & RefAttributes<HTMLInputElement>> {
|
|
16
19
|
Option: FC<IOption>;
|
|
20
|
+
Optgroup: FC<IOptgroup>;
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
const Select: StaticComponent = {
|
|
20
24
|
...forwardRef<HTMLInputElement, ISelect>(({...args}, ref): JSX.Element => <SelectUI {...args} ref={ref}/>),
|
|
21
|
-
Option
|
|
25
|
+
Option,
|
|
26
|
+
Optgroup
|
|
22
27
|
} as StaticComponent;
|
|
23
28
|
|
|
24
29
|
export {
|
|
25
|
-
Option as SelectOption
|
|
30
|
+
Option as SelectOption,
|
|
31
|
+
Optgroup as SelectOptgroup
|
|
26
32
|
};
|
|
27
33
|
export default Select;
|