wini-web-components 2.8.2 → 2.8.5
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.js +10 -10
- package/dist/index.js.mjs +198 -185
- package/package.json +6 -2
- package/src/component/button/button.module.css +210 -0
- package/src/component/button/button.tsx +57 -0
- package/src/component/calendar/calendar.module.css +153 -0
- package/src/component/calendar/calendar.tsx +389 -0
- package/src/component/carousel/carousel.css +622 -0
- package/src/component/carousel/carousel.tsx +91 -0
- package/src/component/checkbox/checkbox.module.css +48 -0
- package/src/component/checkbox/checkbox.tsx +80 -0
- package/src/component/ck-editor/ck-editor.css +206 -0
- package/src/component/ck-editor/ckeditor.tsx +522 -0
- package/src/component/component-status.tsx +53 -0
- package/src/component/date-time-picker/date-time-picker.module.css +94 -0
- package/src/component/date-time-picker/date-time-picker.tsx +663 -0
- package/src/component/dialog/dialog.module.css +111 -0
- package/src/component/dialog/dialog.tsx +109 -0
- package/src/component/import-file/import-file.module.css +83 -0
- package/src/component/import-file/import-file.tsx +174 -0
- package/src/component/infinite-scroll/infinite-scroll.module.css +34 -0
- package/src/component/infinite-scroll/infinite-scroll.tsx +35 -0
- package/src/component/input-multi-select/input-multi-select.module.css +121 -0
- package/src/component/input-multi-select/input-multi-select.tsx +263 -0
- package/src/component/input-otp/input-otp.module.css +41 -0
- package/src/component/input-otp/input-otp.tsx +110 -0
- package/src/component/number-picker/number-picker.module.css +137 -0
- package/src/component/number-picker/number-picker.tsx +107 -0
- package/src/component/pagination/pagination.module.css +48 -0
- package/src/component/pagination/pagination.tsx +88 -0
- package/src/component/popup/popup.css +136 -0
- package/src/component/popup/popup.tsx +125 -0
- package/src/component/progress-bar/progress-bar.module.css +42 -0
- package/src/component/progress-bar/progress-bar.tsx +33 -0
- package/src/component/progress-circle/progress-circle.css +0 -0
- package/src/component/progress-circle/progress-circle.tsx +25 -0
- package/src/component/radio-button/radio-button.module.css +51 -0
- package/src/component/radio-button/radio-button.tsx +60 -0
- package/src/component/rating/rating.module.css +11 -0
- package/src/component/rating/rating.tsx +65 -0
- package/src/component/select1/select1.module.css +108 -0
- package/src/component/select1/select1.tsx +271 -0
- package/src/component/switch/switch.module.css +53 -0
- package/src/component/switch/switch.tsx +68 -0
- package/src/component/table/table.css +74 -0
- package/src/component/table/table.tsx +108 -0
- package/src/component/tag/tag.module.css +108 -0
- package/src/component/tag/tag.tsx +31 -0
- package/src/component/text/text.css +27 -0
- package/src/component/text/text.tsx +24 -0
- package/src/component/text-area/text-area.module.css +57 -0
- package/src/component/text-area/text-area.tsx +65 -0
- package/src/component/text-field/text-field.module.css +71 -0
- package/src/component/text-field/text-field.tsx +102 -0
- package/src/component/toast-noti/toast-noti.css +866 -0
- package/src/component/toast-noti/toast-noti.tsx +22 -0
- package/src/component/wini-icon/winicon.module.css +110 -0
- package/src/component/wini-icon/winicon.tsx +9424 -0
- package/src/form/login/view.module.css +80 -0
- package/src/form/login/view.tsx +138 -0
- package/src/index.tsx +66 -0
- package/src/language/i18n.tsx +143 -0
- package/src/skin/layout.css +649 -0
- package/src/skin/root.css +294 -0
- package/src/skin/typography.css +314 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React, { CSSProperties } from "react"
|
|
2
|
+
import styles from './rating.module.css'
|
|
3
|
+
|
|
4
|
+
interface RatingProps {
|
|
5
|
+
id?: string,
|
|
6
|
+
/**
|
|
7
|
+
value: 0-5
|
|
8
|
+
*/
|
|
9
|
+
value?: number,
|
|
10
|
+
size?: number | string,
|
|
11
|
+
onChange?: (e: number) => void
|
|
12
|
+
className?: string,
|
|
13
|
+
style?: CSSProperties,
|
|
14
|
+
strokeColor?: string,
|
|
15
|
+
fillColor?: string,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface RatingState {
|
|
19
|
+
value: number,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const autoKeyId = () => window.crypto.randomUUID().replace(/-/g, '')
|
|
23
|
+
|
|
24
|
+
export class Rating extends React.Component<RatingProps, RatingState> {
|
|
25
|
+
state: Readonly<RatingState> = {
|
|
26
|
+
value: this.props.value ?? 0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
componentDidUpdate(prevProps: Readonly<RatingProps>): void {
|
|
30
|
+
if (prevProps.value !== this.props.value) {
|
|
31
|
+
this.setState({ value: this.props.value ?? 0 })
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
render(): React.ReactNode {
|
|
35
|
+
return <div id={this.props.id} className={`row ${styles['rating-container']} ${this.props.className ?? ''}`} style={this.props.style}>
|
|
36
|
+
{Array.from({ length: 5 }).map((_, i) => {
|
|
37
|
+
let uniqueId = 'rating-star-grad-0'
|
|
38
|
+
let stopValue = 0
|
|
39
|
+
if (this.state.value >= 5) {
|
|
40
|
+
uniqueId = 'rating-star-grad-5'
|
|
41
|
+
stopValue = 100
|
|
42
|
+
} else if (this.state.value >= i) {
|
|
43
|
+
uniqueId = autoKeyId()
|
|
44
|
+
stopValue = (this.state.value - i) * 100
|
|
45
|
+
}
|
|
46
|
+
return <svg onClick={() => {
|
|
47
|
+
if (this.props.onChange) {
|
|
48
|
+
this.setState({ value: i + 1 })
|
|
49
|
+
this.props.onChange(i + 1)
|
|
50
|
+
}
|
|
51
|
+
}} key={'rate-' + i} width={"100%"} height={"100%"} style={{ width: this.props.size ?? '2rem', height: this.props.size ?? '2rem' }} viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
52
|
+
<defs>
|
|
53
|
+
<linearGradient id={uniqueId} x1="0%" x2="100%" y1="0%" y2="0%">
|
|
54
|
+
<stop offset="0%" style={{ stopColor: this.props.fillColor ?? 'var(--secondary3-main-color,#FAAD1E)' }} />
|
|
55
|
+
<stop offset={`${stopValue}%`} style={{ stopColor: this.props.fillColor ?? 'var(--secondary3-main-color,#FAAD1E)' }} />
|
|
56
|
+
<stop offset={`${stopValue}%`} style={{ stopColor: '#00000000' }} />
|
|
57
|
+
</linearGradient>
|
|
58
|
+
</defs>
|
|
59
|
+
<path fillRule="evenodd" clipRule="evenodd" d="M10 1.66667C10.2884 1.66667 10.5518 1.82993 10.6794 2.0878L12.844 6.46194L17.6847 7.16325C17.97 7.20459 18.2071 7.4039 18.2962 7.67736C18.3853 7.95082 18.311 8.25101 18.1045 8.45172L14.6018 11.8563L15.4285 16.6636C15.4772 16.947 15.3604 17.2334 15.127 17.4024C14.8937 17.5714 14.5844 17.5937 14.3292 17.4599L10 15.1897L5.67081 17.4599C5.41557 17.5937 5.10627 17.5714 4.87295 17.4024C4.63964 17.2334 4.52278 16.947 4.57151 16.6636L5.39815 11.8563L1.89545 8.45172C1.68896 8.25101 1.61465 7.95082 1.70377 7.67736C1.79288 7.4039 2.02996 7.20459 2.31533 7.16325L7.15599 6.46194L9.32063 2.0878C9.44825 1.82993 9.71162 1.66667 10 1.66667ZM10 4.12915L8.33846 7.48665C8.22811 7.70963 8.01479 7.86418 7.76802 7.89993L4.05223 8.43827L6.74094 11.0517C6.91947 11.2252 7.00094 11.4752 6.95881 11.7203L6.3243 15.4102L9.64738 13.6676C9.86813 13.5519 10.1319 13.5519 10.3526 13.6676L13.6757 15.4102L13.0412 11.7203C12.9991 11.4752 13.0805 11.2252 13.2591 11.0517L15.9478 8.43827L12.232 7.89993C11.9852 7.86418 11.7719 7.70963 11.6615 7.48665L10 4.12915Z" style={{ fill: this.props.strokeColor ?? 'var(--neutral-text-placeholder-color,#878792)' }} />
|
|
60
|
+
<path d="M17.738 7.18949L12.8212 6.47499L10.6249 2.02268C10.5611 1.91426 10.47 1.82438 10.3608 1.76194C10.2515 1.6995 10.1279 1.66666 10.0021 1.66666C9.87623 1.66666 9.75259 1.6995 9.64335 1.76194C9.53411 1.82438 9.44306 1.91426 9.37921 2.02268L7.17875 6.47499L2.26191 7.18949C2.13368 7.208 2.0132 7.26201 1.91406 7.34542C1.81493 7.42882 1.74111 7.5383 1.70095 7.66147C1.66078 7.78463 1.65588 7.91658 1.68678 8.04239C1.71769 8.1682 1.78317 8.28286 1.87583 8.3734L5.43449 11.8411L4.59499 16.7385C4.57311 16.8662 4.58739 16.9975 4.63622 17.1175C4.68505 17.2375 4.76648 17.3414 4.8713 17.4175C4.97612 17.4937 5.10016 17.539 5.22938 17.5483C5.3586 17.5577 5.48785 17.5306 5.60252 17.4704L9.99998 15.1588L14.3974 17.4704C14.5121 17.5306 14.6414 17.5577 14.7706 17.5483C14.8998 17.539 15.0238 17.4937 15.1286 17.4175C15.2335 17.3414 15.3149 17.2375 15.3637 17.1175C15.4126 16.9975 15.4268 16.8662 15.405 16.7385L14.5655 11.8411L18.1241 8.3734C18.2168 8.28295 18.2823 8.16841 18.3132 8.0427C18.3442 7.91699 18.3394 7.78512 18.2994 7.66199C18.2594 7.53886 18.1858 7.42937 18.0868 7.34587C17.9879 7.26238 17.8675 7.20822 17.7394 7.18949H17.738Z" fill={`url(#${uniqueId})`} />
|
|
61
|
+
</svg>
|
|
62
|
+
})}
|
|
63
|
+
</div>
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
.select1-container {
|
|
2
|
+
border-radius: 0.8rem;
|
|
3
|
+
width: 100%;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
padding: 0.8rem 1.6rem;
|
|
6
|
+
border: var(--neutral-bolder-border);
|
|
7
|
+
border-radius: 0.8rem;
|
|
8
|
+
gap: 0.8rem;
|
|
9
|
+
position: relative;
|
|
10
|
+
cursor: context-menu;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.select1-container:focus-within {
|
|
14
|
+
border-color: var(--primary-main-color);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.select1-container.disabled {
|
|
18
|
+
background-color: var(--neutral-disable-background-color) !important;
|
|
19
|
+
pointer-events: none !important;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.select1-container.helper-text {
|
|
23
|
+
overflow: visible !important;
|
|
24
|
+
border-color: var(--helper-text-color) !important;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.select1-container.helper-text::after {
|
|
28
|
+
content: attr(helper-text);
|
|
29
|
+
color: var(--helper-text-color);
|
|
30
|
+
position: absolute;
|
|
31
|
+
left: 0;
|
|
32
|
+
bottom: -0.4rem;
|
|
33
|
+
width: max-content;
|
|
34
|
+
font-size: 1.2rem;
|
|
35
|
+
line-height: 1.6rem;
|
|
36
|
+
font-family: inherit;
|
|
37
|
+
transform: translateY(100%);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.select1-container>input {
|
|
41
|
+
flex: 1;
|
|
42
|
+
width: 100%;
|
|
43
|
+
border: none;
|
|
44
|
+
outline: none;
|
|
45
|
+
padding: 0;
|
|
46
|
+
background-color: transparent !important;
|
|
47
|
+
font: inherit;
|
|
48
|
+
color: inherit;
|
|
49
|
+
font-size: inherit;
|
|
50
|
+
font-family: inherit;
|
|
51
|
+
font-weight: inherit;
|
|
52
|
+
line-height: inherit;
|
|
53
|
+
text-align: inherit;
|
|
54
|
+
text-overflow: inherit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.select1-container input:read-only {
|
|
58
|
+
cursor: context-menu;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.select1-popup {
|
|
62
|
+
position: absolute;
|
|
63
|
+
z-index: 10;
|
|
64
|
+
background-color: var(--neutral-absolute-background-color);
|
|
65
|
+
border-radius: 0.8rem;
|
|
66
|
+
border: var(--neutral-main-border);
|
|
67
|
+
height: fit-content;
|
|
68
|
+
box-shadow: 0 0 12px 0 #00204d1f;
|
|
69
|
+
align-items: center;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.select1-popup>.select-body {
|
|
73
|
+
max-height: 100%;
|
|
74
|
+
flex: 1;
|
|
75
|
+
align-items: start;
|
|
76
|
+
max-height: 28rem;
|
|
77
|
+
min-height: 8rem;
|
|
78
|
+
width: 100%;
|
|
79
|
+
padding: 0.4rem 0;
|
|
80
|
+
overflow: hidden auto;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.select1-popup>.select-body .select-tile {
|
|
84
|
+
justify-content: start;
|
|
85
|
+
align-items: center;
|
|
86
|
+
padding: 0.8rem 1.6rem;
|
|
87
|
+
gap: 0.8rem;
|
|
88
|
+
width: 100%;
|
|
89
|
+
cursor: context-menu;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.select1-popup>.select-body .select-tile:hover {
|
|
93
|
+
background-color: var(--neutral-hover-background-color);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.select1-popup>.select-body .select-tile.disabled {
|
|
97
|
+
background-color: var(--neutral-disable-background-color) !important;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.select1-popup>.select-body .select-tile.disabled * {
|
|
101
|
+
color: var(--neutral-text-disabled-color) !important;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.no-results-found {
|
|
105
|
+
padding: 0.8rem;
|
|
106
|
+
font: 400 1.4rem/2rem "Inter";
|
|
107
|
+
color: var(--neutral-text-title-reverse-color);
|
|
108
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import styles from './select1.module.css'
|
|
2
|
+
import React, { createRef, CSSProperties, ReactNode, useState } from 'react'
|
|
3
|
+
import { Winicon } from '../wini-icon/winicon'
|
|
4
|
+
import { Text } from '../text/text'
|
|
5
|
+
import { WithTranslation, withTranslation } from 'react-i18next';
|
|
6
|
+
import { PopupOverlay } from '../popup/popup'
|
|
7
|
+
|
|
8
|
+
export interface OptionsItem {
|
|
9
|
+
id: string | number,
|
|
10
|
+
parentId?: string,
|
|
11
|
+
name: string | ReactNode,
|
|
12
|
+
title?: string | ((onSelect: (e: OptionsItem) => void) => ReactNode),
|
|
13
|
+
disabled?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface Select1Props extends WithTranslation {
|
|
17
|
+
id?: string,
|
|
18
|
+
value?: string | number,
|
|
19
|
+
options: Required<Array<OptionsItem>>,
|
|
20
|
+
onChange?: (v?: OptionsItem) => void,
|
|
21
|
+
placeholder?: string,
|
|
22
|
+
disabled?: boolean,
|
|
23
|
+
className?: string,
|
|
24
|
+
helperText?: string,
|
|
25
|
+
helperTextColor?: string,
|
|
26
|
+
style?: CSSProperties,
|
|
27
|
+
handleSearch?: (e: string) => Promise<Array<OptionsItem>>,
|
|
28
|
+
handleLoadmore?: (onLoadMore: boolean, ev: React.UIEvent<HTMLDivElement, UIEvent>) => void,
|
|
29
|
+
handleLoadChildren?: () => {}
|
|
30
|
+
readOnly?: boolean,
|
|
31
|
+
popupClassName?: string,
|
|
32
|
+
prefix?: ReactNode,
|
|
33
|
+
suffix?: ReactNode,
|
|
34
|
+
onOpenOptions?: (popupRef: HTMLDivElement) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Select1State {
|
|
38
|
+
value?: string | number,
|
|
39
|
+
options: Required<Array<OptionsItem>>,
|
|
40
|
+
offset: DOMRect,
|
|
41
|
+
isOpen: boolean,
|
|
42
|
+
onSelect: any,
|
|
43
|
+
selected?: string | number,
|
|
44
|
+
search?: Array<OptionsItem>,
|
|
45
|
+
style?: Object
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
class TSelect1 extends React.Component<Select1Props, Select1State> {
|
|
49
|
+
private containerRef = createRef<HTMLDivElement>()
|
|
50
|
+
private inputRef = createRef<HTMLInputElement>()
|
|
51
|
+
constructor(props: Select1Props) {
|
|
52
|
+
super(props)
|
|
53
|
+
this.state = {
|
|
54
|
+
value: props.value,
|
|
55
|
+
options: props.options,
|
|
56
|
+
offset: {
|
|
57
|
+
x: 0,
|
|
58
|
+
y: 0,
|
|
59
|
+
height: 0,
|
|
60
|
+
width: 0,
|
|
61
|
+
bottom: 0,
|
|
62
|
+
left: 0,
|
|
63
|
+
right: 0,
|
|
64
|
+
top: 0,
|
|
65
|
+
toJSON: function () {
|
|
66
|
+
throw new Error('Function not implemented.')
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
isOpen: false,
|
|
70
|
+
onSelect: null,
|
|
71
|
+
}
|
|
72
|
+
this.search = this.search.bind(this)
|
|
73
|
+
this.onSelect = this.onSelect.bind(this)
|
|
74
|
+
this.onKeyDown = this.onKeyDown.bind(this)
|
|
75
|
+
if (this.inputRef.current) this.inputRef.current.value = `${this.state.options.find(e => e.id === this.state.value)?.name ?? ""}`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private async search(ev: React.ChangeEvent<HTMLInputElement>) {
|
|
79
|
+
if (ev.target.value.trim().length) {
|
|
80
|
+
if (this.props?.handleSearch) {
|
|
81
|
+
const res = await this.props.handleSearch(ev.target.value.trim())
|
|
82
|
+
this.setState({ ...this.state, search: res })
|
|
83
|
+
} else {
|
|
84
|
+
this.setState({
|
|
85
|
+
...this.state,
|
|
86
|
+
search: this.props.options.filter(e => typeof e.name === "string" && e.name.toLowerCase().includes(ev.target.value.trim().toLowerCase()))
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
this.setState({ ...this.state, search: undefined })
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private onSelect(item: OptionsItem) {
|
|
95
|
+
if (item.disabled) {
|
|
96
|
+
this.setState({ ...this.state, isOpen: false, onSelect: undefined, selected: undefined })
|
|
97
|
+
this.inputRef.current?.blur()
|
|
98
|
+
} else {
|
|
99
|
+
let newState = { ...this.state, isOpen: false, value: item.id, onSelect: undefined, selected: undefined }
|
|
100
|
+
if (!newState.options.some(e => e.id === item.id)) newState.options.push(item)
|
|
101
|
+
this.setState(newState)
|
|
102
|
+
this.inputRef.current?.blur()
|
|
103
|
+
}
|
|
104
|
+
if (this.props.onChange) this.props.onChange(item)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private onKeyDown = (ev: React.KeyboardEvent<HTMLInputElement>) => {
|
|
108
|
+
if ((this.state.options?.length || this.state.search?.length) && this.state.isOpen) {
|
|
109
|
+
switch (ev.key.toLowerCase()) {
|
|
110
|
+
case "enter":
|
|
111
|
+
ev.preventDefault()
|
|
112
|
+
const _selectItem = (this.state.search ?? this.state.options).find(e => e.id === this.state.selected)
|
|
113
|
+
if (_selectItem) this.onSelect(_selectItem)
|
|
114
|
+
break;
|
|
115
|
+
case "arrowup":
|
|
116
|
+
ev.preventDefault()
|
|
117
|
+
if (this.state.selected) {
|
|
118
|
+
let _index = (this.state.search ?? this.state.options).findIndex((e) => e.id === this.state.selected)
|
|
119
|
+
_index = ((_index === 0) ? this.props.options.length : _index) - 1
|
|
120
|
+
this.setState({ ...this.state, selected: this.props.options[_index]?.id })
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
case "arrowdown":
|
|
124
|
+
ev.preventDefault()
|
|
125
|
+
if (this.state.selected) {
|
|
126
|
+
let _index = (this.state.search ?? this.state.options).findIndex((e) => e.id === this.state.selected)
|
|
127
|
+
_index = ((_index + 1 === this.props.options.length) ? -1 : _index) + 1
|
|
128
|
+
this.setState({ ...this.state, selected: this.props.options[_index]?.id })
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
default:
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
componentDidUpdate(prevProps: Select1Props, prevState: Select1State) {
|
|
138
|
+
if (prevProps.options !== this.props.options) {
|
|
139
|
+
this.setState({ ...this.state, options: this.props.options })
|
|
140
|
+
if (this.inputRef.current) this.inputRef.current.value = `${this.props.options.find(e => e.id === this.state.value)?.name ?? ""}`
|
|
141
|
+
}
|
|
142
|
+
if (prevProps.value !== this.props.value) this.setState({ ...this.state, value: this.props.value })
|
|
143
|
+
if (prevState.value !== this.state.value && this.inputRef.current) this.inputRef.current.value = `${this.state.options.find(e => e.id === this.state.value)?.name ?? ""}`
|
|
144
|
+
//
|
|
145
|
+
if (this.state.isOpen && prevState.isOpen !== this.state.isOpen) {
|
|
146
|
+
const thisPopupRect = this.containerRef.current!.querySelector(`.select1-popup`)?.getBoundingClientRect()
|
|
147
|
+
if (thisPopupRect) {
|
|
148
|
+
let style: { top?: string, left?: string, right?: string, bottom?: string, width?: string, height?: string } | undefined;
|
|
149
|
+
if (thisPopupRect.right > document.body.offsetWidth) {
|
|
150
|
+
style = {
|
|
151
|
+
top: this.state.offset.y + this.state.offset.height + 2 + 'px',
|
|
152
|
+
right: document.body.offsetWidth - this.state.offset.right + 'px'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
let _bottom = thisPopupRect.bottom - 8
|
|
156
|
+
const thisContainerRect = this.containerRef.current?.getBoundingClientRect()
|
|
157
|
+
if (thisContainerRect) {
|
|
158
|
+
if (_bottom > document.body.offsetHeight) {
|
|
159
|
+
style = { ...(style ?? {}), top: `${thisContainerRect.y - 2 - thisPopupRect.height}px` }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (style) {
|
|
163
|
+
style.left ??= (style.right ? undefined : `${this.state.offset.x}px`)
|
|
164
|
+
style.width ??= `${this.state.offset.width}px`
|
|
165
|
+
this.setState({ ...this.state, style: style })
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
componentDidMount(): void {
|
|
172
|
+
if (this.inputRef.current) this.inputRef.current.value = `${this.state.options.find(e => e.id === this.state.value)?.name ?? ""}`
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
render() {
|
|
176
|
+
const { t } = this.props;
|
|
177
|
+
const _value = this.state.options.find(e => e.id === this.state.value)
|
|
178
|
+
return <div
|
|
179
|
+
id={this.props.id}
|
|
180
|
+
ref={this.containerRef}
|
|
181
|
+
className={`${styles['select1-container']} row ${this.props.disabled ? styles['disabled'] : ''} ${this.props.helperText?.length && styles['helper-text']} ${this.props.className ?? 'body-3'}`}
|
|
182
|
+
helper-text={this.props.helperText}
|
|
183
|
+
style={this.props.style ? { ...({ '--helper-text-color': this.props.helperTextColor ?? '#e14337' } as CSSProperties), ...this.props.style } : ({ '--helper-text-color': this.props.helperTextColor ?? '#e14337' } as CSSProperties)}
|
|
184
|
+
onClick={() => {
|
|
185
|
+
if (!this.state.isOpen) {
|
|
186
|
+
this.setState({
|
|
187
|
+
...this.state,
|
|
188
|
+
isOpen: true,
|
|
189
|
+
style: undefined,
|
|
190
|
+
offset: this.containerRef?.current?.getBoundingClientRect() as any,
|
|
191
|
+
})
|
|
192
|
+
this.inputRef.current?.focus()
|
|
193
|
+
}
|
|
194
|
+
}}
|
|
195
|
+
>
|
|
196
|
+
{this.props.prefix}
|
|
197
|
+
{(!_value || typeof _value.name === "string" || typeof _value.name === "number") ? <input ref={this.inputRef} readOnly={this.props.readOnly} onChange={this.search} placeholder={this.props.placeholder}
|
|
198
|
+
onBlur={ev => {
|
|
199
|
+
if (this.state.onSelect && !this.props.readOnly) ev.target.focus()
|
|
200
|
+
}}
|
|
201
|
+
/> : _value.name}
|
|
202
|
+
{this.props.suffix ?? <div ref={iconRef => {
|
|
203
|
+
if (iconRef?.parentElement && iconRef.parentElement.getBoundingClientRect().width < 88) iconRef.style.display = "none"
|
|
204
|
+
}} className='row' >
|
|
205
|
+
<Winicon src={this.state.isOpen ? "fill/arrows/up-arrow" : "fill/arrows/down-arrow"} size={"1.2rem"} />
|
|
206
|
+
</div>}
|
|
207
|
+
{this.state.isOpen && <PopupOverlay
|
|
208
|
+
onOpen={this.props.onOpenOptions}
|
|
209
|
+
className={`hidden-overlay`}
|
|
210
|
+
onClose={(ev) => {
|
|
211
|
+
if (ev.target !== this.inputRef.current) this.setState({ ...this.state, isOpen: false })
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
<div className={`${styles['select1-popup']} select1-popup col ${this.props.popupClassName ?? ""}`} style={this.state.style ?? {
|
|
215
|
+
top: this.state.offset.y + this.state.offset.height + 2 + 'px',
|
|
216
|
+
left: this.state.offset.x + 'px',
|
|
217
|
+
width: this.state.offset.width,
|
|
218
|
+
}}>
|
|
219
|
+
<div className={`col ${styles['select-body']}`} onScroll={this.props.handleLoadmore ? (ev) => {
|
|
220
|
+
if (this.props.handleLoadmore) {
|
|
221
|
+
let scrollElement = ev.target as HTMLDivElement
|
|
222
|
+
this.props.handleLoadmore(Math.round(scrollElement.offsetHeight + scrollElement.scrollTop) >= (scrollElement.scrollHeight - 1), ev)
|
|
223
|
+
}
|
|
224
|
+
} : undefined}>
|
|
225
|
+
{(this.state.search ?? this.state.options).filter(e => !e.parentId).map(item => {
|
|
226
|
+
return <OptionsItemTile
|
|
227
|
+
key={item.id}
|
|
228
|
+
item={item}
|
|
229
|
+
children={(this.state.search ?? this.state.options).filter(e => e.parentId === item.id)}
|
|
230
|
+
selected={this.state.selected === item.id}
|
|
231
|
+
onClick={this.onSelect}
|
|
232
|
+
treeData={(this.state.search ?? this.state.options).some(e => e.parentId)}
|
|
233
|
+
/>
|
|
234
|
+
})}
|
|
235
|
+
{(!this.state.search?.length && !this.props.options?.length) && (
|
|
236
|
+
<div className={styles['no-results-found']}>{t("noResultFound")}</div>
|
|
237
|
+
)}
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
</PopupOverlay>}
|
|
241
|
+
</div>
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface OptionTileProps {
|
|
246
|
+
item: OptionsItem,
|
|
247
|
+
children?: Array<OptionsItem>,
|
|
248
|
+
selected?: boolean,
|
|
249
|
+
onClick: (e: OptionsItem) => void,
|
|
250
|
+
treeData?: boolean
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function OptionsItemTile({ item, children, selected, onClick, treeData }: OptionTileProps) {
|
|
254
|
+
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
255
|
+
|
|
256
|
+
return item.title && typeof item.title !== "string" ? <>{item.title(onClick)}</> : <div className='col' style={{ width: '100%' }}>
|
|
257
|
+
<div className={`${styles['select-tile']} row ${item.disabled ? styles["disabled"] : ""}`} style={{ paddingLeft: item.parentId ? '4.4rem' : undefined, backgroundColor: selected ? "var(--neutral-selected-background-color)" : undefined }} onClick={() => {
|
|
258
|
+
if (children?.length) {
|
|
259
|
+
setIsOpen(!isOpen)
|
|
260
|
+
} else onClick(item)
|
|
261
|
+
}}>
|
|
262
|
+
{treeData ? <div className='row' style={{ width: '1.4rem', height: '1.4rem' }}>
|
|
263
|
+
{children?.length ? <Winicon src={isOpen ? "fill/arrows/triangle-down" : "fill/arrows/triangle-right"} size={"1.2rem"} /> : null}
|
|
264
|
+
</div> : undefined}
|
|
265
|
+
{((item.title && typeof item.title === "string") || typeof item.name === "string") ? <Text className='body-3'>{item.title && typeof item.title === "string" ? item.title : item.name}</Text> : item.name}
|
|
266
|
+
</div>
|
|
267
|
+
{children?.length ? <div className='col' style={{ display: isOpen ? "flex" : "none", width: '100%' }}>{children.map(e => <OptionsItemTile key={e.id} item={e} onClick={onClick} />)}</div> : undefined}
|
|
268
|
+
</div>
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export const Select1 = withTranslation()(TSelect1)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.switch-container {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
background-color: var(--off-bg) !important;
|
|
5
|
+
border-radius: 50vw !important;
|
|
6
|
+
border: none;
|
|
7
|
+
outline: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.switch-container>input {
|
|
11
|
+
opacity: 0;
|
|
12
|
+
width: 0;
|
|
13
|
+
height: 0;
|
|
14
|
+
border: none;
|
|
15
|
+
outline: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.switch-container>.slider {
|
|
19
|
+
font-size: var(--size);
|
|
20
|
+
position: absolute;
|
|
21
|
+
height: calc(100% - 0.2em);
|
|
22
|
+
aspect-ratio: 1 / 1;
|
|
23
|
+
left: 0.1em;
|
|
24
|
+
top: 0.1em;
|
|
25
|
+
background-color: var(--dot-color);
|
|
26
|
+
transition: 0.4s;
|
|
27
|
+
border-radius: 50%;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.switch-container>input:checked+.slider {
|
|
31
|
+
-webkit-transform: translateX(calc(0.8 * (100% + 0.2em)));
|
|
32
|
+
-ms-transform: translateX(calc(0.8 * (100% + 0.2em)));
|
|
33
|
+
transform: translateX(calc(0.8 * (100% + 0.2em)));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.switch-container:has(> input:checked) {
|
|
37
|
+
background-color: var(--on-bg) !important;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.switch-container:has(> input:disabled:not(*:checked)) {
|
|
41
|
+
pointer-events: none;
|
|
42
|
+
border: var(--neutral-bolder-border);
|
|
43
|
+
background-color: var(--neutral-disable-background-color) !important;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.switch-container:has(> input:disabled:not(*:checked)) .slider {
|
|
47
|
+
background-color: var(--neutral-text-disabled-color) !important;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.switch-container:has(> input:disabled:checked) {
|
|
51
|
+
pointer-events: none;
|
|
52
|
+
background-color: var(--primary-lighter-color) !important;
|
|
53
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
import styles from './switch.module.css';
|
|
3
|
+
|
|
4
|
+
interface SwitchProps {
|
|
5
|
+
id?: string,
|
|
6
|
+
onChange?: (value: boolean) => void,
|
|
7
|
+
value?: boolean,
|
|
8
|
+
disabled?: boolean,
|
|
9
|
+
className?: string,
|
|
10
|
+
style?: CSSProperties,
|
|
11
|
+
size?: number | string,
|
|
12
|
+
dotColor?: string,
|
|
13
|
+
onBackground?: string,
|
|
14
|
+
offBackground?: string,
|
|
15
|
+
name?: string,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface SwitchState {
|
|
19
|
+
value?: boolean,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class Switch extends React.Component<SwitchProps, SwitchState> {
|
|
23
|
+
state: Readonly<SwitchState> = {
|
|
24
|
+
value: this.props.value ?? false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
componentDidUpdate(prevProps: Readonly<SwitchProps>): void {
|
|
28
|
+
if (prevProps.value !== this.props.value) {
|
|
29
|
+
this.setState({ value: this.props.value })
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
render() {
|
|
34
|
+
const propStyle = {
|
|
35
|
+
'--off-bg': this.props.offBackground ?? 'var(--neutral-main-background-color)',
|
|
36
|
+
'--on-bg': this.props.onBackground ?? 'var(--primary-main-color)',
|
|
37
|
+
'--dot-color': this.props.dotColor ?? '#ffffff',
|
|
38
|
+
'--size': this.props.size ? (typeof this.props.size === 'number') ? `${this.props.size}px` : this.props.size : '2rem'
|
|
39
|
+
}
|
|
40
|
+
let convertStyle: CSSProperties = {
|
|
41
|
+
height: this.props.size ?? '2rem',
|
|
42
|
+
width: `calc(${this.props.size ? (typeof this.props.size === 'number') ? `${this.props.size}px` : this.props.size : '2rem'} * 9 / 5)`,
|
|
43
|
+
...propStyle
|
|
44
|
+
}
|
|
45
|
+
if (this.props.style) {
|
|
46
|
+
delete this.props.style.width
|
|
47
|
+
delete this.props.style.minWidth
|
|
48
|
+
delete this.props.style.maxWidth
|
|
49
|
+
delete this.props.style.height
|
|
50
|
+
delete this.props.style.minHeight
|
|
51
|
+
delete this.props.style.maxHeight
|
|
52
|
+
convertStyle = {
|
|
53
|
+
...this.props.style,
|
|
54
|
+
...convertStyle,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return <label id={this.props.id} className={`${styles['switch-container']} row ${this.props.className ?? ''}`} style={convertStyle} >
|
|
58
|
+
<input type="checkbox" checked={this.state.value} name={this.props.name} disabled={this.props.disabled}
|
|
59
|
+
onChange={() => {
|
|
60
|
+
const newValue = !this.state.value
|
|
61
|
+
this.setState({ value: newValue })
|
|
62
|
+
if (this.props.onChange) this.props.onChange(newValue)
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
<span className={styles['slider']}></span>
|
|
66
|
+
</label>
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
.custom-table {
|
|
2
|
+
border: none;
|
|
3
|
+
min-width: 100%;
|
|
4
|
+
border-collapse: collapse;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.custom-table>.tb-header {
|
|
8
|
+
top: -1px;
|
|
9
|
+
z-index: 4;
|
|
10
|
+
position: sticky;
|
|
11
|
+
background-color: #f9fafb;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.custom-table>.tb-header>tr {
|
|
15
|
+
border-top: var(--neutral-bolder-border);
|
|
16
|
+
border-bottom: var(--neutral-bolder-border);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.custom-table .tb-cell {
|
|
20
|
+
height: 4.4rem;
|
|
21
|
+
text-align: left;
|
|
22
|
+
padding: 0 2.4rem;
|
|
23
|
+
font: 400 1.4rem/2.2rem 'Inter';
|
|
24
|
+
color: #00204DCC;
|
|
25
|
+
vertical-align: middle;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.custom-table tr>td {
|
|
29
|
+
background-color: #ffffff;
|
|
30
|
+
overflow: hidden;
|
|
31
|
+
text-overflow: ellipsis;
|
|
32
|
+
max-width: 52rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.custom-table>.tb-header>tr>td {
|
|
36
|
+
font: 600 1.2rem/2rem 'Inter';
|
|
37
|
+
white-space: nowrap;
|
|
38
|
+
color: #00204D99;
|
|
39
|
+
background-color: #f9fafb;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.custom-table tr.selected {
|
|
43
|
+
background-color: #f5f7fa;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.custom-table tr.selected>td {
|
|
47
|
+
background-color: #f5f7fa;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.tb-row>.tb-cell.tb-cell-fixed {
|
|
51
|
+
z-index: 2;
|
|
52
|
+
position: sticky;
|
|
53
|
+
/* box-shadow: 1px 0px 6px 0px rgba(45, 50, 57, 0.06); */
|
|
54
|
+
background-color: #ffffff;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.tb-header .tb-cell.tb-cell-fixed {
|
|
58
|
+
z-index: 2;
|
|
59
|
+
position: sticky;
|
|
60
|
+
/* box-shadow: 1px 0px 6px 0px rgba(45, 50, 57, 0.06); */
|
|
61
|
+
background-color: #f9fafb;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.tb-cell[align-cell='start'] {
|
|
65
|
+
text-align: start;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tb-cell[align-cell='center'] {
|
|
69
|
+
text-align: center;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.tb-cell[align-cell='end'] {
|
|
73
|
+
text-align: end;
|
|
74
|
+
}
|