@datability/8ui 1.1.0 → 1.1.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/dist/index.css +1 -0
- package/dist/index.es.js +1853 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +8 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types/App.d.ts +2 -0
- package/dist/types/components/blackdrop/index.d.ts +4 -0
- package/dist/types/components/blackdrop/index.type.d.ts +6 -0
- package/dist/types/components/button/index.d.ts +4 -0
- package/dist/types/components/button/index.type.d.ts +12 -0
- package/dist/types/components/chip/index.d.ts +4 -0
- package/dist/types/components/chip/index.type.d.ts +9 -0
- package/dist/types/components/context.d.ts +8 -0
- package/dist/types/components/divider/index.d.ts +3 -0
- package/dist/types/components/index.d.ts +41 -0
- package/dist/types/components/input/input-auto-complete/index.d.ts +4 -0
- package/dist/types/components/input/input-auto-complete/index.type.d.ts +14 -0
- package/dist/types/components/input/input-base/index.d.ts +4 -0
- package/dist/types/components/input/input-base/index.type.d.ts +11 -0
- package/dist/types/components/input/input-basic/index.d.ts +4 -0
- package/dist/types/components/input/input-basic/index.type.d.ts +10 -0
- package/dist/types/components/input/input-checkbox/index.d.ts +4 -0
- package/dist/types/components/input/input-checkbox/index.type.d.ts +13 -0
- package/dist/types/components/input/input-date/index.d.ts +22 -0
- package/dist/types/components/input/input-date/index.type.d.ts +13 -0
- package/dist/types/components/input/input-date-range/index.d.ts +4 -0
- package/dist/types/components/input/input-date-range/index.type.d.ts +13 -0
- package/dist/types/components/input/input-date-time/index.d.ts +4 -0
- package/dist/types/components/input/input-date-time/index.type.d.ts +13 -0
- package/dist/types/components/input/input-number/index.d.ts +4 -0
- package/dist/types/components/input/input-number/index.type.d.ts +12 -0
- package/dist/types/components/input/input-password/index.d.ts +4 -0
- package/dist/types/components/input/input-password/index.type.d.ts +10 -0
- package/dist/types/components/input/input-radio/index.d.ts +4 -0
- package/dist/types/components/input/input-radio/index.type.d.ts +14 -0
- package/dist/types/components/input/input-select/index.d.ts +4 -0
- package/dist/types/components/input/input-select/index.type.d.ts +16 -0
- package/dist/types/components/input/input-switch/index.d.ts +4 -0
- package/dist/types/components/input/input-switch/index.type.d.ts +6 -0
- package/dist/types/components/input/input-textarea/index.d.ts +4 -0
- package/dist/types/components/input/input-textarea/index.type.d.ts +12 -0
- package/dist/types/components/menu/index.d.ts +4 -0
- package/dist/types/components/menu/index.type.d.ts +11 -0
- package/dist/types/components/modal/index.d.ts +4 -0
- package/dist/types/components/modal/index.type.d.ts +7 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/main.d.ts +1 -0
- package/package.json +5 -1
- package/.prettierrc +0 -8
- package/.vscode/extensions.json +0 -6
- package/declaration.d.ts +0 -10
- package/docker-compose.yml +0 -20
- package/eslint.config.js +0 -23
- package/index.html +0 -13
- package/src/App.tsx +0 -370
- package/src/components/blackdrop/index.tsx +0 -18
- package/src/components/blackdrop/index.type.ts +0 -7
- package/src/components/button/index.tsx +0 -44
- package/src/components/button/index.type.ts +0 -13
- package/src/components/chip/index.tsx +0 -39
- package/src/components/chip/index.type.ts +0 -12
- package/src/components/context.tsx +0 -26
- package/src/components/divider/index.tsx +0 -13
- package/src/components/index.ts +0 -62
- package/src/components/input/input-auto-complete/index.tsx +0 -140
- package/src/components/input/input-auto-complete/index.type.tsx +0 -13
- package/src/components/input/input-base/index.tsx +0 -39
- package/src/components/input/input-base/index.type.tsx +0 -13
- package/src/components/input/input-basic/index.tsx +0 -47
- package/src/components/input/input-basic/index.type.tsx +0 -8
- package/src/components/input/input-checkbox/index.tsx +0 -69
- package/src/components/input/input-checkbox/index.type.tsx +0 -11
- package/src/components/input/input-date/index.tsx +0 -354
- package/src/components/input/input-date/index.type.tsx +0 -11
- package/src/components/input/input-date-range/index.tsx +0 -284
- package/src/components/input/input-date-range/index.type.tsx +0 -11
- package/src/components/input/input-date-time/index.tsx +0 -367
- package/src/components/input/input-date-time/index.type.tsx +0 -11
- package/src/components/input/input-number/index.tsx +0 -118
- package/src/components/input/input-number/index.type.tsx +0 -11
- package/src/components/input/input-password/index.tsx +0 -60
- package/src/components/input/input-password/index.type.tsx +0 -8
- package/src/components/input/input-radio/index.tsx +0 -72
- package/src/components/input/input-radio/index.type.tsx +0 -12
- package/src/components/input/input-select/index.tsx +0 -113
- package/src/components/input/input-select/index.type.tsx +0 -15
- package/src/components/input/input-switch/index.tsx +0 -44
- package/src/components/input/input-switch/index.type.tsx +0 -4
- package/src/components/input/input-textarea/index.tsx +0 -48
- package/src/components/input/input-textarea/index.type.tsx +0 -10
- package/src/components/menu/index.tsx +0 -136
- package/src/components/menu/index.type.ts +0 -8
- package/src/components/modal/index.tsx +0 -99
- package/src/components/modal/index.type.tsx +0 -8
- package/src/index.scss +0 -44
- package/src/index.ts +0 -62
- package/src/logoDownload.svg +0 -3
- package/src/main.tsx +0 -9
- package/tsconfig.app.json +0 -28
- package/tsconfig.json +0 -42
- package/tsconfig.node.json +0 -29
- package/vite.config.d.ts +0 -2
- package/vite.config.ts +0 -35
- /package/{src → dist}/components/assets/closed.svg +0 -0
- /package/{src → dist}/components/assets/expand-arrow.svg +0 -0
- /package/{src → dist}/components/assets/visibility-off.svg +0 -0
- /package/{src → dist}/components/assets/visibility.svg +0 -0
- /package/{src → dist}/components/blackdrop/index.scss +0 -0
- /package/{src → dist}/components/button/index.scss +0 -0
- /package/{src → dist}/components/chip/index.scss +0 -0
- /package/{src → dist}/components/divider/index.scss +0 -0
- /package/{src → dist}/components/input/extend.scss +0 -0
- /package/{src → dist}/components/input/input-auto-complete/index.scss +0 -0
- /package/{src → dist}/components/input/input-base/index.scss +0 -0
- /package/{src → dist}/components/input/input-basic/index.scss +0 -0
- /package/{src → dist}/components/input/input-checkbox/index.scss +0 -0
- /package/{src → dist}/components/input/input-date/index.scss +0 -0
- /package/{src → dist}/components/input/input-date-range/index.scss +0 -0
- /package/{src → dist}/components/input/input-date-time/index.scss +0 -0
- /package/{src → dist}/components/input/input-number/index.scss +0 -0
- /package/{src → dist}/components/input/input-password/index.scss +0 -0
- /package/{src → dist}/components/input/input-radio/index.scss +0 -0
- /package/{src → dist}/components/input/input-select/index.scss +0 -0
- /package/{src → dist}/components/input/input-switch/index.scss +0 -0
- /package/{src → dist}/components/input/input-textarea/index.scss +0 -0
- /package/{src → dist}/components/menu/index.scss +0 -0
- /package/{src → dist}/components/modal/index.scss +0 -0
- /package/{public → dist}/vite.svg +0 -0
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React, { useEffect, useState } from "react"
|
|
3
|
-
import { useFormContext, Controller } from "react-hook-form"
|
|
4
|
-
|
|
5
|
-
// Include in project
|
|
6
|
-
import "./index.scss"
|
|
7
|
-
import InputBase from "../input-base"
|
|
8
|
-
import type { PropsInputNumber } from "./index.type"
|
|
9
|
-
|
|
10
|
-
const InputNumber: React.FC<PropsInputNumber> = ({
|
|
11
|
-
name,
|
|
12
|
-
label,
|
|
13
|
-
placeholder,
|
|
14
|
-
disabled = false,
|
|
15
|
-
require = false,
|
|
16
|
-
fullWidth = false,
|
|
17
|
-
isPhoneNumber = false,
|
|
18
|
-
isAvailableMinus = false,
|
|
19
|
-
}) => {
|
|
20
|
-
const { control } = useFormContext()
|
|
21
|
-
const [showValue, setShowValue] = useState<string>("")
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<Controller
|
|
25
|
-
name={name}
|
|
26
|
-
control={control}
|
|
27
|
-
render={({ field, fieldState }) => {
|
|
28
|
-
const { value, onChange } = field
|
|
29
|
-
const { error, invalid } = fieldState
|
|
30
|
-
|
|
31
|
-
// sync RHF value → showValue
|
|
32
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
if (!isPhoneNumber && typeof value === "number" && !isNaN(value)) {
|
|
35
|
-
setShowValue(value.toLocaleString("en-US"))
|
|
36
|
-
} else if (typeof value === "string") {
|
|
37
|
-
setShowValue(value)
|
|
38
|
-
} else {
|
|
39
|
-
setShowValue(value ?? "")
|
|
40
|
-
}
|
|
41
|
-
}, [value])
|
|
42
|
-
|
|
43
|
-
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
44
|
-
const input = event.target.value
|
|
45
|
-
|
|
46
|
-
// ล้างช่อง
|
|
47
|
-
if (input === "") {
|
|
48
|
-
if (isPhoneNumber) {
|
|
49
|
-
onChange("")
|
|
50
|
-
setShowValue("")
|
|
51
|
-
} else {
|
|
52
|
-
onChange(0)
|
|
53
|
-
setShowValue("0")
|
|
54
|
-
}
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// phone number
|
|
59
|
-
if (isPhoneNumber) {
|
|
60
|
-
onChange(input)
|
|
61
|
-
setShowValue(input)
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const rawValue = input.replace(/,/g, "")
|
|
66
|
-
const regex = isAvailableMinus ? /^-?[0-9]*\.?[0-9]*$/ : /^[0-9]*\.?[0-9]*$/
|
|
67
|
-
|
|
68
|
-
if (!regex.test(rawValue)) return
|
|
69
|
-
|
|
70
|
-
if (rawValue === "-" || rawValue.endsWith(".")) {
|
|
71
|
-
setShowValue(formatWithComma(rawValue))
|
|
72
|
-
onChange(rawValue)
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const numericValue = Number(rawValue)
|
|
77
|
-
if (isNaN(numericValue)) return
|
|
78
|
-
|
|
79
|
-
onChange(numericValue)
|
|
80
|
-
setShowValue(formatWithComma(rawValue))
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<InputBase
|
|
85
|
-
name={name}
|
|
86
|
-
label={label}
|
|
87
|
-
require={require}
|
|
88
|
-
fullWidth={fullWidth}
|
|
89
|
-
isInvalid={invalid}
|
|
90
|
-
errorMessage={error?.message}
|
|
91
|
-
>
|
|
92
|
-
<input
|
|
93
|
-
className="DBui-inputNumber"
|
|
94
|
-
type="text"
|
|
95
|
-
placeholder={placeholder}
|
|
96
|
-
disabled={disabled}
|
|
97
|
-
value={showValue}
|
|
98
|
-
onChange={handleChange}
|
|
99
|
-
inputMode="decimal"
|
|
100
|
-
pattern="-?[0-9,]*\.?[0-9]*"
|
|
101
|
-
data-invalid={invalid}
|
|
102
|
-
/>
|
|
103
|
-
</InputBase>
|
|
104
|
-
)
|
|
105
|
-
}}
|
|
106
|
-
/>
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export default InputNumber
|
|
111
|
-
|
|
112
|
-
const formatWithComma = (val: string): string => {
|
|
113
|
-
if (val === "" || val === "-" || val === "." || val === "-.") return val
|
|
114
|
-
|
|
115
|
-
const [intPart, decPart] = val.split(".")
|
|
116
|
-
const formattedInt = intPart ? Number(intPart).toLocaleString("en-US") : ""
|
|
117
|
-
return decPart !== undefined ? `${formattedInt}.${decPart}` : formattedInt
|
|
118
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type PropsInputNumber = {
|
|
2
|
-
name: string
|
|
3
|
-
label?: string
|
|
4
|
-
placeholder?: string
|
|
5
|
-
disabled?: boolean
|
|
6
|
-
require?: boolean
|
|
7
|
-
fullWidth?: boolean
|
|
8
|
-
isPhoneNumber?: boolean // If isPhoneNumber === true type will be string, else type number
|
|
9
|
-
isAvailableMinus?: boolean
|
|
10
|
-
}
|
|
11
|
-
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React, { useState } from "react"
|
|
3
|
-
import { useFormContext, useFormState } from "react-hook-form"
|
|
4
|
-
|
|
5
|
-
// Images
|
|
6
|
-
import visibilitySVG from "../../assets/visibility.svg"
|
|
7
|
-
import visibilityOffSVG from "../../assets/visibility-off.svg"
|
|
8
|
-
|
|
9
|
-
// Include in project
|
|
10
|
-
import "./index.scss"
|
|
11
|
-
import InputBase from "../input-base"
|
|
12
|
-
import type { PropsInputPassword } from "./index.type"
|
|
13
|
-
|
|
14
|
-
const InputPassword: React.FC<PropsInputPassword> = ({
|
|
15
|
-
name,
|
|
16
|
-
label,
|
|
17
|
-
placeholder,
|
|
18
|
-
disabled = false,
|
|
19
|
-
require = false,
|
|
20
|
-
fullWidth = false,
|
|
21
|
-
}) => {
|
|
22
|
-
const { register, control } = useFormContext()
|
|
23
|
-
const { errors } = useFormState({ control, name })
|
|
24
|
-
|
|
25
|
-
const error = errors?.[name]
|
|
26
|
-
const isInvalid = Boolean(error)
|
|
27
|
-
|
|
28
|
-
const [isShow, setIsShow] = useState(false)
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<InputBase
|
|
32
|
-
name={name}
|
|
33
|
-
label={label}
|
|
34
|
-
require={require}
|
|
35
|
-
fullWidth={fullWidth}
|
|
36
|
-
isInvalid={isInvalid}
|
|
37
|
-
errorMessage={error?.message}
|
|
38
|
-
>
|
|
39
|
-
<div className="DBui-wrapInputPassword">
|
|
40
|
-
<input
|
|
41
|
-
{...register(name)}
|
|
42
|
-
className="DBui-inputPassword"
|
|
43
|
-
type={isShow ? "text" : "password"}
|
|
44
|
-
placeholder={placeholder}
|
|
45
|
-
disabled={disabled}
|
|
46
|
-
data-invalid={isInvalid}
|
|
47
|
-
/>
|
|
48
|
-
|
|
49
|
-
<img
|
|
50
|
-
className="DBui-inputPasswordIcon"
|
|
51
|
-
src={isShow ? visibilitySVG : visibilityOffSVG}
|
|
52
|
-
alt="toggle visibility"
|
|
53
|
-
onClick={() => setIsShow((s) => !s)}
|
|
54
|
-
/>
|
|
55
|
-
</div>
|
|
56
|
-
</InputBase>
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export default InputPassword
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React from "react"
|
|
3
|
-
import { Controller, useFormContext } from "react-hook-form"
|
|
4
|
-
|
|
5
|
-
// Include in project
|
|
6
|
-
import "./index.scss"
|
|
7
|
-
import InputBase from "../input-base"
|
|
8
|
-
import type { PropsInputRadio } from "./index.type"
|
|
9
|
-
|
|
10
|
-
const InputRadio: React.FC<PropsInputRadio> = ({
|
|
11
|
-
name,
|
|
12
|
-
label,
|
|
13
|
-
disabled = false,
|
|
14
|
-
require = false,
|
|
15
|
-
fullWidth = false,
|
|
16
|
-
isVertical = false,
|
|
17
|
-
options,
|
|
18
|
-
}) => {
|
|
19
|
-
const { control } = useFormContext()
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<Controller
|
|
23
|
-
name={name}
|
|
24
|
-
control={control}
|
|
25
|
-
render={({ field, fieldState }) => {
|
|
26
|
-
const { value, onChange } = field
|
|
27
|
-
const { invalid, error } = fieldState
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<InputBase
|
|
31
|
-
name={name}
|
|
32
|
-
label={label}
|
|
33
|
-
require={require}
|
|
34
|
-
fullWidth={fullWidth}
|
|
35
|
-
isInvalid={invalid}
|
|
36
|
-
errorMessage={error?.message}
|
|
37
|
-
>
|
|
38
|
-
<div className="DBui-wrapInputRadioList" data-vertical={isVertical}>
|
|
39
|
-
{options.map((data, index) => {
|
|
40
|
-
const isChecked = value === data.value
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div key={index} className="DBui-wrapInputRadio">
|
|
44
|
-
<input
|
|
45
|
-
className="DBui-inputRadio"
|
|
46
|
-
type="radio"
|
|
47
|
-
disabled={disabled}
|
|
48
|
-
checked={isChecked}
|
|
49
|
-
onClick={() => {
|
|
50
|
-
// คลิกซ้ำ = uncheck
|
|
51
|
-
if (isChecked) {
|
|
52
|
-
onChange("")
|
|
53
|
-
} else {
|
|
54
|
-
onChange(data.value)
|
|
55
|
-
}
|
|
56
|
-
}}
|
|
57
|
-
/>
|
|
58
|
-
<p className="DBui-labelRadio" data-invalid={invalid}>
|
|
59
|
-
<small>{data.label}</small>
|
|
60
|
-
</p>
|
|
61
|
-
</div>
|
|
62
|
-
)
|
|
63
|
-
})}
|
|
64
|
-
</div>
|
|
65
|
-
</InputBase>
|
|
66
|
-
)
|
|
67
|
-
}}
|
|
68
|
-
/>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export default InputRadio
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React from "react"
|
|
3
|
-
import { Controller, useFormContext } from "react-hook-form"
|
|
4
|
-
|
|
5
|
-
// Images
|
|
6
|
-
import expandArrowSVG from "../../assets/expand-arrow.svg"
|
|
7
|
-
import closedSVG from "../../assets/closed.svg"
|
|
8
|
-
|
|
9
|
-
// Include in project
|
|
10
|
-
import "./index.scss"
|
|
11
|
-
import InputBase from "../input-base"
|
|
12
|
-
import Menu from "../../menu"
|
|
13
|
-
import type { TOption, TValueOption } from "../.."
|
|
14
|
-
import type { PropsInputSelect } from "./index.type"
|
|
15
|
-
|
|
16
|
-
const InputSelect: React.FC<PropsInputSelect> = ({
|
|
17
|
-
name,
|
|
18
|
-
label,
|
|
19
|
-
disabled = false,
|
|
20
|
-
require = false,
|
|
21
|
-
fullWidth = false,
|
|
22
|
-
options,
|
|
23
|
-
onChange,
|
|
24
|
-
isHideClearIcon = true,
|
|
25
|
-
placeholder,
|
|
26
|
-
isInModal = false,
|
|
27
|
-
}) => {
|
|
28
|
-
const { control } = useFormContext()
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<Controller
|
|
32
|
-
name={name}
|
|
33
|
-
control={control}
|
|
34
|
-
render={({ field, fieldState }) => {
|
|
35
|
-
const { value, onChange: setValue } = field
|
|
36
|
-
const { invalid, error } = fieldState
|
|
37
|
-
|
|
38
|
-
const selected = options?.find((e) => e.value === value) as TOption | undefined
|
|
39
|
-
|
|
40
|
-
const handleSelect = (val: TValueOption, close: () => void) => {
|
|
41
|
-
setValue(val)
|
|
42
|
-
onChange?.(val)
|
|
43
|
-
close()
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handleClear = (e: React.MouseEvent<HTMLImageElement>) => {
|
|
47
|
-
e.stopPropagation()
|
|
48
|
-
setValue(null)
|
|
49
|
-
onChange?.(null)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<InputBase
|
|
54
|
-
name={name}
|
|
55
|
-
label={label}
|
|
56
|
-
require={require}
|
|
57
|
-
fullWidth={fullWidth}
|
|
58
|
-
isInvalid={invalid}
|
|
59
|
-
errorMessage={error?.message}
|
|
60
|
-
>
|
|
61
|
-
<Menu
|
|
62
|
-
isInModal={isInModal}
|
|
63
|
-
disabled={disabled}
|
|
64
|
-
trigger={({ isOpen }) => (
|
|
65
|
-
<div className="DBui-wrapperInputSelect" data-invalid={invalid} data-disabled={disabled}>
|
|
66
|
-
<div className="DBui-wrapperLabelInputSelect">
|
|
67
|
-
{selected?.label ? (
|
|
68
|
-
<p className="DBui-wrapperLabel">
|
|
69
|
-
<small>{selected.label}</small>
|
|
70
|
-
</p>
|
|
71
|
-
) : (
|
|
72
|
-
<p className="DBui-placeholder">
|
|
73
|
-
<small>{placeholder}</small>
|
|
74
|
-
</p>
|
|
75
|
-
)}
|
|
76
|
-
|
|
77
|
-
<img
|
|
78
|
-
src={closedSVG}
|
|
79
|
-
className="DBui-clearIconInputSelect"
|
|
80
|
-
onClick={handleClear}
|
|
81
|
-
data-hidden={!value || disabled || isHideClearIcon}
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<img
|
|
86
|
-
src={expandArrowSVG}
|
|
87
|
-
className="DBui-arrowIconInputSelect"
|
|
88
|
-
data-checked={disabled ? true : !isOpen}
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
91
|
-
)}
|
|
92
|
-
>
|
|
93
|
-
{({ close }) =>
|
|
94
|
-
options.map((data, index) => (
|
|
95
|
-
<p
|
|
96
|
-
key={index}
|
|
97
|
-
className="DBui-menuItemInputSelect"
|
|
98
|
-
onClick={() => handleSelect(data.value, close)}
|
|
99
|
-
data-checked={value === data.value}
|
|
100
|
-
>
|
|
101
|
-
{data.label}
|
|
102
|
-
</p>
|
|
103
|
-
))
|
|
104
|
-
}
|
|
105
|
-
</Menu>
|
|
106
|
-
</InputBase>
|
|
107
|
-
)
|
|
108
|
-
}}
|
|
109
|
-
/>
|
|
110
|
-
)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export default InputSelect
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { TOption, TValueOption } from "../.."
|
|
2
|
-
|
|
3
|
-
export type PropsInputSelect = {
|
|
4
|
-
name: string
|
|
5
|
-
label?: string
|
|
6
|
-
placeholder?: string
|
|
7
|
-
disabled?: boolean
|
|
8
|
-
require?: boolean
|
|
9
|
-
fullWidth?: boolean
|
|
10
|
-
options: TOption[]
|
|
11
|
-
onChange?: (value: TValueOption | null) => void
|
|
12
|
-
value?: string
|
|
13
|
-
isHideClearIcon?: boolean
|
|
14
|
-
isInModal?: boolean
|
|
15
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React from "react"
|
|
3
|
-
import { Controller, useFormContext } from "react-hook-form"
|
|
4
|
-
|
|
5
|
-
// Include in project
|
|
6
|
-
import "./index.scss"
|
|
7
|
-
import type { PropsInputSwitch } from "./index.type"
|
|
8
|
-
|
|
9
|
-
const InputSwitch: React.FC<PropsInputSwitch> = ({ name, disabled }) => {
|
|
10
|
-
const { control } = useFormContext()
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<Controller
|
|
14
|
-
name={name}
|
|
15
|
-
control={control}
|
|
16
|
-
render={({ field }) => {
|
|
17
|
-
const { value, onChange } = field
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div className="DBui-wrapInputList" data-disabled={disabled}>
|
|
21
|
-
<label className="DBui-switch">
|
|
22
|
-
<span className="DBui-minus"></span>
|
|
23
|
-
<span className="DBui-miniCircle"></span>
|
|
24
|
-
|
|
25
|
-
<input
|
|
26
|
-
type="checkbox"
|
|
27
|
-
checked={Boolean(value)}
|
|
28
|
-
disabled={disabled}
|
|
29
|
-
onChange={(e) => {
|
|
30
|
-
e.stopPropagation()
|
|
31
|
-
onChange(!value)
|
|
32
|
-
}}
|
|
33
|
-
/>
|
|
34
|
-
|
|
35
|
-
<span className="DBui-slider"></span>
|
|
36
|
-
</label>
|
|
37
|
-
</div>
|
|
38
|
-
)
|
|
39
|
-
}}
|
|
40
|
-
/>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export default InputSwitch
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React from "react"
|
|
3
|
-
import { useFormContext, useFormState } from "react-hook-form"
|
|
4
|
-
|
|
5
|
-
// Include in project
|
|
6
|
-
import "./index.scss"
|
|
7
|
-
import InputBase from "../input-base"
|
|
8
|
-
import type { PropsInputTextarea } from "./index.type"
|
|
9
|
-
|
|
10
|
-
const InputTextarea: React.FC<PropsInputTextarea> = ({
|
|
11
|
-
name,
|
|
12
|
-
label,
|
|
13
|
-
placeholder,
|
|
14
|
-
disabled = false,
|
|
15
|
-
require = false,
|
|
16
|
-
fullWidth = false,
|
|
17
|
-
rows = 2,
|
|
18
|
-
cols = 50,
|
|
19
|
-
}) => {
|
|
20
|
-
const { register, control } = useFormContext()
|
|
21
|
-
const { errors } = useFormState({ control, name })
|
|
22
|
-
|
|
23
|
-
const error = errors?.[name]
|
|
24
|
-
const isInvalid = Boolean(error)
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<InputBase
|
|
28
|
-
name={name}
|
|
29
|
-
label={label}
|
|
30
|
-
require={require}
|
|
31
|
-
fullWidth={fullWidth}
|
|
32
|
-
isInvalid={isInvalid}
|
|
33
|
-
errorMessage={error?.message}
|
|
34
|
-
>
|
|
35
|
-
<textarea
|
|
36
|
-
{...register(name)}
|
|
37
|
-
className="DBui-inputTextarea"
|
|
38
|
-
placeholder={placeholder}
|
|
39
|
-
disabled={disabled}
|
|
40
|
-
rows={rows}
|
|
41
|
-
cols={cols}
|
|
42
|
-
data-invalid={isInvalid}
|
|
43
|
-
/>
|
|
44
|
-
</InputBase>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export default InputTextarea
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
// Lib
|
|
2
|
-
import React, { useEffect, useRef, useState } from "react"
|
|
3
|
-
import { createPortal } from "react-dom"
|
|
4
|
-
import "./index.scss"
|
|
5
|
-
import type { PropsMenu } from "./index.type"
|
|
6
|
-
|
|
7
|
-
const Menu: React.FC<PropsMenu> = ({ children, trigger, disabled, isInModal = false }) => {
|
|
8
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
9
|
-
const [menuStyle, setMenuStyle] = useState({})
|
|
10
|
-
|
|
11
|
-
const triggerRef = useRef<HTMLDivElement>(null)
|
|
12
|
-
const menuRef = useRef<HTMLDivElement>(null)
|
|
13
|
-
|
|
14
|
-
// Toggle dropdown
|
|
15
|
-
const toggleMenu = () => {
|
|
16
|
-
if (!disabled) setIsOpen((prev) => !prev)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// ------------ MAIN POSITIONING FUNCTION ------------
|
|
20
|
-
const calculateMenuPosition = () => {
|
|
21
|
-
if (!triggerRef.current || !menuRef.current) return
|
|
22
|
-
|
|
23
|
-
const triggerRect = triggerRef.current.getBoundingClientRect()
|
|
24
|
-
const menu = menuRef.current
|
|
25
|
-
|
|
26
|
-
const viewportH = window.innerHeight
|
|
27
|
-
const viewportW = window.innerWidth
|
|
28
|
-
const menuWidth = menu.offsetWidth
|
|
29
|
-
|
|
30
|
-
const spaceAbove = triggerRect.top
|
|
31
|
-
const spaceBelow = viewportH - triggerRect.bottom
|
|
32
|
-
|
|
33
|
-
// วางล่างถ้าพื้นที่ล่างมากกว่า
|
|
34
|
-
const placeBottom = spaceBelow >= spaceAbove
|
|
35
|
-
|
|
36
|
-
let top = placeBottom
|
|
37
|
-
? triggerRect.bottom // show below
|
|
38
|
-
: triggerRect.top - menu.offsetHeight // show above (height กำหนดจาก CSS max-height)
|
|
39
|
-
|
|
40
|
-
// เปลี่ยน logic ตรงนี้ → กันเมนูล้นจอจาก CSS max-height
|
|
41
|
-
// ถ้าด้านบนพื้นที่ไม่พอ ให้ clamp
|
|
42
|
-
if (!placeBottom) {
|
|
43
|
-
const minTop = 8
|
|
44
|
-
if (top < minTop) top = minTop
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let left = triggerRect.left
|
|
48
|
-
if (left + menuWidth > viewportW - 8) {
|
|
49
|
-
left = viewportW - menuWidth - 8
|
|
50
|
-
}
|
|
51
|
-
if (left < 8) left = 8
|
|
52
|
-
|
|
53
|
-
setMenuStyle({
|
|
54
|
-
position: "fixed",
|
|
55
|
-
top,
|
|
56
|
-
left,
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ------------ Double RAF (ให้ DOM render ก่อน 100%) ------------
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
if (!isOpen) return
|
|
63
|
-
|
|
64
|
-
requestAnimationFrame(() => {
|
|
65
|
-
requestAnimationFrame(() => {
|
|
66
|
-
calculateMenuPosition()
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
}, [isOpen, children])
|
|
70
|
-
|
|
71
|
-
// ------------ Reposition when scroll/resize/orientation ------------
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
if (!isOpen) return
|
|
74
|
-
|
|
75
|
-
const handler = () => calculateMenuPosition()
|
|
76
|
-
|
|
77
|
-
window.addEventListener("scroll", handler, true)
|
|
78
|
-
window.addEventListener("resize", handler)
|
|
79
|
-
window.addEventListener("orientationchange", handler)
|
|
80
|
-
|
|
81
|
-
return () => {
|
|
82
|
-
window.removeEventListener("scroll", handler, true)
|
|
83
|
-
window.removeEventListener("resize", handler)
|
|
84
|
-
window.removeEventListener("orientationchange", handler)
|
|
85
|
-
}
|
|
86
|
-
}, [isOpen, children])
|
|
87
|
-
|
|
88
|
-
// ------------ Close On Click Outside ------------
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
if (!isOpen) return
|
|
91
|
-
|
|
92
|
-
const handleClick = (e: MouseEvent) => {
|
|
93
|
-
const t = triggerRef.current
|
|
94
|
-
const m = menuRef.current
|
|
95
|
-
if (!t || !m) return
|
|
96
|
-
|
|
97
|
-
if (!t.contains(e.target as Node) && !m.contains(e.target as Node)) {
|
|
98
|
-
setIsOpen(false)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
document.addEventListener("mousedown", handleClick)
|
|
103
|
-
return () => document.removeEventListener("mousedown", handleClick)
|
|
104
|
-
}, [isOpen])
|
|
105
|
-
|
|
106
|
-
// Portal root
|
|
107
|
-
const portalRoot = document.getElementById("root") || document.getElementById("__next") || document.body
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<>
|
|
111
|
-
<div ref={triggerRef} className="DBui-wrapperMenu" onClick={toggleMenu}>
|
|
112
|
-
{trigger({ isOpen })}
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
{isOpen &&
|
|
116
|
-
createPortal(
|
|
117
|
-
<div
|
|
118
|
-
ref={menuRef}
|
|
119
|
-
className="DBui-wrapperMenuItem"
|
|
120
|
-
style={menuStyle}
|
|
121
|
-
data-hidden={!isOpen}
|
|
122
|
-
data-is-in-modal={isInModal}
|
|
123
|
-
>
|
|
124
|
-
{typeof children === "function"
|
|
125
|
-
? children({
|
|
126
|
-
close: () => setIsOpen(false),
|
|
127
|
-
})
|
|
128
|
-
: children}
|
|
129
|
-
</div>,
|
|
130
|
-
portalRoot,
|
|
131
|
-
)}
|
|
132
|
-
</>
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export default Menu
|