react-artasys-ui 0.1.4 → 0.1.6

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.
@@ -10,5 +10,5 @@ export interface IElement<T = any> extends Omit<AllHTMLAttributes<T>, 'children'
10
10
  afterElement?: React.ReactElement;
11
11
  hiddenContainer?: boolean;
12
12
  }
13
- declare const Element: ({ children, beforeElement, afterElement, error, placeholder, disabled, styleContainer, classNameContainer, hiddenContainer, ...props }: IElement) => JSX.Element;
13
+ declare const Element: ({ children, beforeElement, afterElement, error, placeholder, styleContainer, classNameContainer, hiddenContainer, ...props }: IElement) => JSX.Element;
14
14
  export default Element;
@@ -3,7 +3,9 @@ import { TSpinner } from '../Spinner';
3
3
  interface IForm extends FormHTMLAttributes<HTMLFormElement> {
4
4
  children: ReactNode;
5
5
  wait?: boolean;
6
+ progress?: number;
7
+ progressRadius?: boolean;
6
8
  spinnerColor?: TSpinner['color'];
7
9
  }
8
- declare const Form: ({ children, wait, className, spinnerColor, onSubmit, ...props }: IForm) => JSX.Element;
10
+ declare const Form: ({ children, wait, progress, progressRadius, className, spinnerColor, onSubmit, ...props }: IForm) => JSX.Element;
9
11
  export default Form;
@@ -0,0 +1,7 @@
1
+ interface IProgress {
2
+ value?: number | string;
3
+ size?: 'small' | 'middle' | 'large';
4
+ radius?: boolean;
5
+ }
6
+ declare const Progress: ({ value, size, radius }: IProgress) => JSX.Element;
7
+ export default Progress;
@@ -0,0 +1,2 @@
1
+ import Progress from "./Progress";
2
+ export default Progress;
@@ -0,0 +1,7 @@
1
+ import { LiHTMLAttributes } from "react";
2
+ export interface IOption extends LiHTMLAttributes<HTMLLIElement> {
3
+ value?: string;
4
+ children?: string | React.ReactElement;
5
+ }
6
+ declare const Option: ({ children, value, onClick, ...props }: IOption) => JSX.Element;
7
+ export default Option;
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import { IElement } from "../Form/Element";
3
+ import type { IOption } from "./Option";
4
+ export declare const Context: import("react").Context<{
5
+ selected: string;
6
+ emptyValue: import("react").MutableRefObject<boolean>;
7
+ setSelect: (value: string) => void;
8
+ setSelected: (value: string) => void;
9
+ setTitle: (title: string) => void;
10
+ }>;
11
+ export interface ISelect extends Omit<IElement, 'children' | 'onChange'> {
12
+ children?: React.FunctionComponentElement<IOption>[];
13
+ onChange?: (value: string) => void;
14
+ }
15
+ declare const Select: import("react").ForwardRefExoticComponent<ISelect & import("react").RefAttributes<HTMLInputElement>>;
16
+ export default Select;
@@ -0,0 +1,9 @@
1
+ import { ForwardRefExoticComponent, FC, RefAttributes } from "react";
2
+ import { ISelect } from "./Select";
3
+ import Option, { IOption } from "./Option";
4
+ interface StaticComponent extends ForwardRefExoticComponent<ISelect & RefAttributes<HTMLInputElement>> {
5
+ Option: FC<IOption>;
6
+ }
7
+ declare const Select: StaticComponent;
8
+ export { Option as SelectOption };
9
+ export default Select;
package/lib/index.d.ts CHANGED
@@ -7,7 +7,9 @@ import File, { TFileData, TFileMime } from "./File";
7
7
  import Button from "./Button";
8
8
  import UploadImages, { IUploadImages, TImageData, IImage } from "./UploadImages";
9
9
  import Checkbox from "./Checkbox";
10
+ import Progress from "./Progress";
11
+ import Select, { SelectOption } from "./Select";
10
12
  declare const UI: {};
11
- export { Form, FormElement, Element, useForm, Input, TextArea, Spinner, File, Button, UploadImages, Checkbox };
13
+ export { Form, FormElement, Element, useForm, Input, TextArea, Spinner, File, Button, UploadImages, Checkbox, Progress, Select, SelectOption };
12
14
  export type { TFileData, TFileMime, IUploadImages, IImage, TImageData, IElement };
13
15
  export default UI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-artasys-ui",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -19,7 +19,7 @@ export interface IElement<T = any> extends Omit<AllHTMLAttributes<T>, 'children'
19
19
  hiddenContainer?: boolean;
20
20
  }
21
21
 
22
- const Element = ({children, beforeElement, afterElement, error, placeholder, disabled, styleContainer, classNameContainer, hiddenContainer, ...props}: IElement) => {
22
+ const Element = ({children, beforeElement, afterElement, error, placeholder, styleContainer, classNameContainer, hiddenContainer, ...props}: IElement) => {
23
23
  const [currentError, setCurrentError] = useState('');
24
24
 
25
25
  useEffect(() => {
@@ -30,7 +30,7 @@ const Element = ({children, beforeElement, afterElement, error, placeholder, dis
30
30
 
31
31
  classes.push(styles['container']);
32
32
  if (currentError) classes.push(styles['error']);
33
- if (disabled) classes.push(styles['disabled']);
33
+ if (props.disabled) classes.push(styles['disabled']);
34
34
  if (hiddenContainer) classes.push(styles['hidden']);
35
35
  if (classNameContainer) classes.push(classNameContainer);
36
36
 
@@ -59,7 +59,7 @@
59
59
  margin-left: 5px;
60
60
  height: 100%;
61
61
  color: #7A7A73;
62
- font-size: 1.2em;
62
+ font-size: 1.2rem;
63
63
  z-index: -1;
64
64
  user-select: none;
65
65
  transition: transform 0.3s;
package/src/Form/Form.tsx CHANGED
@@ -4,14 +4,17 @@ import styles from './style.module.css';
4
4
  import Spinner,{
5
5
  TSpinner
6
6
  } from '../Spinner';
7
+ import Progress from '../Progress';
7
8
 
8
9
  interface IForm extends FormHTMLAttributes<HTMLFormElement> {
9
10
  children: ReactNode;
10
11
  wait?: boolean;
12
+ progress?: number;
13
+ progressRadius?: boolean;
11
14
  spinnerColor?: TSpinner['color'];
12
15
  }
13
16
 
14
- const Form = ({children, wait, className, spinnerColor, onSubmit, ...props}: IForm) => {
17
+ const Form = ({children, wait, progress, progressRadius = true, className, spinnerColor, onSubmit, ...props}: IForm) => {
15
18
 
16
19
  const submit = (e: FormEvent<HTMLFormElement>) => {
17
20
  e.preventDefault();
@@ -29,7 +32,7 @@ const Form = ({children, wait, className, spinnerColor, onSubmit, ...props}: IFo
29
32
  return(<form {...props} onSubmit={submit} className={classes.join(' ')}>
30
33
  {children}
31
34
  <div className={styles['wait-indicator']}>
32
- <Spinner color={spinnerColor}/>
35
+ {typeof progress === 'number' ? <Progress radius={progressRadius} value={progress}/> : <Spinner color={spinnerColor}/>}
33
36
  </div>
34
37
  </form>);
35
38
  };
@@ -27,6 +27,7 @@ const Input = forwardRef<HTMLInputElement, IInput>(({onChange, onInput, onChange
27
27
  };
28
28
 
29
29
  const handleInput = (e: ChangeEvent<HTMLInputElement>) => {
30
+ if (props.disabled) return;
30
31
  if (typeof onInput === 'function') {
31
32
  onInput(e);
32
33
  }
@@ -0,0 +1,28 @@
1
+ import styles from "./style.module.css";
2
+
3
+ interface IProgress {
4
+ value?: number | string;
5
+ size?: 'small' | 'middle' | 'large';
6
+ radius?: boolean;
7
+ };
8
+
9
+ const Progress = ({value = 0, size, radius = false}: IProgress) => {
10
+ value = Math.ceil(Number(value) * 10) / 10;
11
+ if (value > 100) {
12
+ value = 100;
13
+ }
14
+ if (value < 0) {
15
+ value = 0;
16
+ }
17
+
18
+ const progress = radius ? (360 / 100 * value) + 'deg' : value + '%';
19
+
20
+ const classes = ['ui-progress'];
21
+ classes.push(styles['container']);
22
+ if (size) classes.push(styles[size]);
23
+ if (radius) classes.push(styles['radius']);
24
+
25
+ return(<div className={classes.join(' ')} data-progress={value} style={{'--progress': progress} as React.CSSProperties}/>);
26
+ };
27
+
28
+ export default Progress;
@@ -0,0 +1,3 @@
1
+ import Progress from "./Progress";
2
+
3
+ export default Progress;
@@ -0,0 +1,72 @@
1
+ /* Progress */
2
+
3
+ .container {
4
+ --size: 150px;
5
+ --color-rgb: 94, 190, 214;
6
+ position: relative;
7
+ display: flex;
8
+ justify-content: center;
9
+ align-items: center;
10
+ width: 100%;
11
+ min-width: var(--size);
12
+ max-width: var(--size);
13
+ box-sizing: content-box !important;
14
+ aspect-ratio: 10/1;
15
+ border-radius: 2px;
16
+ padding: 5px 0;
17
+ overflow: hidden;
18
+ }
19
+
20
+ .container::before {
21
+ content: "";
22
+ position: absolute;
23
+ display: block;
24
+ width: 100%;
25
+ height: 100%;
26
+ max-width: 100%;
27
+ max-height: 100%;
28
+ background: linear-gradient(to right, #5EBED6 var(--progress), #BED4DB 0);
29
+ }
30
+
31
+ .container.radius {
32
+ aspect-ratio: 1/1;
33
+ border-radius: 50%;
34
+ padding: unset;
35
+ }
36
+
37
+ .container.radius::before {
38
+ --border-width: clamp(0.2em, 10%, 0.5em);
39
+ border-radius: 50%;
40
+ aspect-ratio: 1/1;
41
+ mask: radial-gradient(
42
+ farthest-side,
43
+ transparent calc(100% - var(--border-width) - 0.5px),
44
+ #000 calc(100% - var(--border-width) + 0.5px)
45
+ );
46
+ background: conic-gradient(#5EBED6 var(--progress), #BED4DB 0deg);
47
+ }
48
+
49
+ .container::after {
50
+ content: attr(data-progress) '%';
51
+ font-size: 1.5em;
52
+ color: #FFFFFF;
53
+ mix-blend-mode: lighten;
54
+ z-index: 1;
55
+ }
56
+
57
+ .container.radius::after {
58
+ mix-blend-mode: unset;
59
+ color: #1D1D1B;
60
+ }
61
+
62
+ .container.small {
63
+ --size: 30px;
64
+ }
65
+
66
+ .container.middle {
67
+ --size: 60px;
68
+ }
69
+
70
+ .container.large {
71
+ --size: 120px;
72
+ }
@@ -0,0 +1,42 @@
1
+ import {
2
+ LiHTMLAttributes,
3
+ MouseEvent,
4
+ useContext,
5
+ useEffect
6
+ } from "react";
7
+ import { Context } from "./Select";
8
+ import styles from "./style.module.css";
9
+
10
+ export interface IOption extends LiHTMLAttributes<HTMLLIElement> {
11
+ value?: string;
12
+ children?: string | React.ReactElement;
13
+ };
14
+
15
+ const Option = ({children, value, onClick, ...props}: IOption) => {
16
+ const context = useContext(Context);
17
+
18
+ const handleClick = (e: MouseEvent<HTMLLIElement>) => {
19
+ if (typeof value === 'undefined') return;
20
+ context.setSelect(value);
21
+ if (typeof onClick === 'function') {
22
+ onClick(e);
23
+ }
24
+ };
25
+
26
+ useEffect(() => {
27
+ if (children && (value === context.selected || !context.emptyValue.current)) {
28
+ context.setTitle(children?.toString());
29
+ if (!context.emptyValue.current && value) {
30
+ context.setSelected(value);
31
+ }
32
+ context.emptyValue.current = true;
33
+ }
34
+ }, [context.selected]);
35
+
36
+ const classes = ['ui-select-option'];
37
+ if (context.selected === value) classes.push(styles['active'], 'active');
38
+
39
+ return(<li {...props} onClick={handleClick} className={classes.join(' ')}>{children}</li>);
40
+ };
41
+
42
+ export default Option;
@@ -0,0 +1,101 @@
1
+ import {
2
+ forwardRef,
3
+ createContext,
4
+ useState,
5
+ useEffect,
6
+ useRef
7
+ } from "react";
8
+ import Element,{
9
+ IElement
10
+ } from "../Form/Element";
11
+ import type { IOption } from "./Option";
12
+ import styles from "./style.module.css";
13
+
14
+ export const Context = createContext({
15
+ selected: '',
16
+ emptyValue: {current:{}} as React.MutableRefObject<boolean>,
17
+ setSelect: (value: string) => {},
18
+ setSelected: (value: string) => {},
19
+ setTitle: (title: string) => {},
20
+ });
21
+
22
+ export interface ISelect extends Omit<IElement, 'children' | 'onChange'> {
23
+ children?: React.FunctionComponentElement<IOption>[];
24
+ onChange?: (value: string) => void;
25
+ };
26
+
27
+ const Select = forwardRef<HTMLInputElement, ISelect>(({children, onChange, value, ...props}, ref) => {
28
+ const containerRef = useRef<HTMLDivElement>(null);
29
+ const emptyValue = useRef(false);
30
+
31
+ const [isOpen, setOpen] = useState(false);
32
+ const [selected, setSelected] = useState('');
33
+ const [title, setTitle] = useState<string>();
34
+
35
+ const open = () => {
36
+ if (props.disabled) return;
37
+ setOpen(true);
38
+ };
39
+
40
+ const close = () => {
41
+ setOpen(false);
42
+ };
43
+
44
+ const setSelect = (value: string) => {
45
+ if (typeof onChange === 'function') {
46
+ onChange(value);
47
+ }
48
+ setSelected(value);
49
+ close();
50
+ };
51
+
52
+ useEffect(() => {
53
+ if (typeof value === 'undefined') return;
54
+ setSelected(String(value));
55
+ }, [value]);
56
+
57
+ useEffect(() => {
58
+ const element = containerRef.current;
59
+ const classList = element!.classList;
60
+ if (isOpen) {
61
+ classList.remove(styles['hidden']);
62
+ requestAnimationFrame(() => {
63
+ classList.add(styles['opened']);
64
+ element?.focus();
65
+ });
66
+ }else{
67
+ if (classList.contains(styles['opened'])) {
68
+ element!.ontransitionend = () => {
69
+ classList.add(styles['hidden']);
70
+ element!.ontransitionend = null;
71
+ };
72
+ }
73
+ classList.remove(styles['opened']);
74
+ }
75
+ }, [isOpen]);
76
+
77
+ const classes = [''];
78
+ classes.push(styles['container'], styles['hidden']);
79
+
80
+ return(<Element {...props} classNameContainer={styles['container-element']}>
81
+ { (props) => <Context.Provider value={{
82
+ selected,
83
+ emptyValue: emptyValue,
84
+ setSelect,
85
+ setSelected,
86
+ setTitle
87
+ }}>
88
+ <input {...props} type="hidden" value={selected} ref={ref}/>
89
+ <div className={classes.join(' ')} ref={containerRef} tabIndex={1} onBlur={close}>
90
+ <div className={styles['select']} onClick={open}>
91
+ <span className={styles['title']}>{title}</span>
92
+ </div>
93
+ <ul className={styles['select-list']}>
94
+ {children}
95
+ </ul>
96
+ </div>
97
+ </Context.Provider> }
98
+ </Element>);
99
+ });
100
+
101
+ export default Select;
@@ -0,0 +1,27 @@
1
+ import {
2
+ forwardRef,
3
+ ForwardRefExoticComponent,
4
+ FC,
5
+ RefAttributes
6
+ } from "react";
7
+ import {
8
+ default as SelectUI,
9
+ ISelect
10
+ } from "./Select";
11
+ import Option,{
12
+ IOption
13
+ } from "./Option";
14
+
15
+ interface StaticComponent extends ForwardRefExoticComponent<ISelect & RefAttributes<HTMLInputElement>> {
16
+ Option: FC<IOption>;
17
+ };
18
+
19
+ const Select: StaticComponent = {
20
+ ...forwardRef<HTMLInputElement, ISelect>(({...args}, ref): JSX.Element => <SelectUI {...args} ref={ref}/>),
21
+ Option
22
+ } as StaticComponent;
23
+
24
+ export {
25
+ Option as SelectOption
26
+ };
27
+ export default Select;
@@ -0,0 +1,93 @@
1
+ /* Select */
2
+
3
+ .container-element {
4
+ z-index: 1;
5
+ }
6
+
7
+ .container {
8
+ position: relative;
9
+ display: flex;
10
+ flex-direction: column;
11
+ justify-content: center;
12
+ min-height: 25px;
13
+ cursor: pointer;
14
+ }
15
+
16
+ .select {
17
+ display: flex;
18
+ flex-direction: row;
19
+ align-items: center;
20
+ min-height: 45px;
21
+ box-sizing: border-box;
22
+ padding: 10px;
23
+ }
24
+
25
+ .select::after {
26
+ content: "";
27
+ display: block;
28
+ width: 0;
29
+ height: 0;
30
+ border-left: 5px solid transparent;
31
+ border-right: 5px solid transparent;
32
+ border-top: 10px solid #5EBED6;
33
+ transition: rotate 0.3s;
34
+ }
35
+
36
+ .container-element:has(input[type="hidden"]:disabled) .select::after {
37
+ border-top-color: #CCCCCC;
38
+ }
39
+
40
+ .container.opened > .select::after {
41
+ rotate: 180deg;
42
+ }
43
+
44
+ .select-list {
45
+ position: absolute;
46
+ display: flex;
47
+ flex-direction: column;
48
+ width: 100%;
49
+ max-height: 40vh;
50
+ max-height: 40dvh;
51
+ top: calc(100% - 1px);
52
+ left: -1px;
53
+ margin: 0;
54
+ padding: 0;
55
+ list-style-type: none;
56
+ background-color: #FFFFFF;
57
+ box-shadow: 0px 4px 5px 0px rgb(0 0 0 / 10%);
58
+ border: 1px solid #CCCCCC;
59
+ overflow: auto;
60
+ border-top: 0;
61
+ opacity: 0;
62
+ visibility: hidden;
63
+ transform: translateY(-10%);
64
+ transition: transform 0.3s ease-in-out, opacity 0.3s, visibility 0.3s;
65
+ }
66
+
67
+ .container.hidden > .select-list {
68
+ display: none;
69
+ }
70
+
71
+ .container.opened > .select-list {
72
+ opacity: 1;
73
+ transform: translateY(0);
74
+ visibility: visible;
75
+ }
76
+
77
+ .title, .select-list > li {
78
+ font-size: 20px;
79
+ color: #1D1D1B;
80
+ }
81
+
82
+ .title {
83
+ flex: 1;
84
+ }
85
+
86
+ .select-list > li {
87
+ padding: 5px;
88
+ cursor: pointer;
89
+ }
90
+
91
+ .select-list > li:hover, .select-list > li.active {
92
+ background-color: #BED4DB;
93
+ }
@@ -12,11 +12,11 @@
12
12
  }
13
13
 
14
14
  .spinner::before {
15
- content: '';
15
+ content: "";
16
16
  display: inline-block;
17
17
  width: 100%;
18
- max-width: 100%;
19
- max-height: 100%;
18
+ max-width: 90%;
19
+ max-height: 90%;
20
20
  --border-width: clamp(0.2em, 10%, 0.5em);
21
21
  border-radius: 50%;
22
22
  aspect-ratio: 1/1;
package/src/index.ts CHANGED
@@ -19,6 +19,10 @@ import UploadImages,{
19
19
  IImage
20
20
  } from "./UploadImages";
21
21
  import Checkbox from "./Checkbox";
22
+ import Progress from "./Progress";
23
+ import Select,{
24
+ SelectOption
25
+ } from "./Select";
22
26
 
23
27
  const UI = {
24
28
 
@@ -35,7 +39,10 @@ export {
35
39
  File,
36
40
  Button,
37
41
  UploadImages,
38
- Checkbox
42
+ Checkbox,
43
+ Progress,
44
+ Select,
45
+ SelectOption
39
46
  };
40
47
  export type {
41
48
  TFileData,