@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.
Files changed (128) hide show
  1. package/dist/index.css +1 -0
  2. package/dist/index.es.js +1853 -0
  3. package/dist/index.es.js.map +1 -0
  4. package/dist/index.umd.js +8 -0
  5. package/dist/index.umd.js.map +1 -0
  6. package/dist/types/App.d.ts +2 -0
  7. package/dist/types/components/blackdrop/index.d.ts +4 -0
  8. package/dist/types/components/blackdrop/index.type.d.ts +6 -0
  9. package/dist/types/components/button/index.d.ts +4 -0
  10. package/dist/types/components/button/index.type.d.ts +12 -0
  11. package/dist/types/components/chip/index.d.ts +4 -0
  12. package/dist/types/components/chip/index.type.d.ts +9 -0
  13. package/dist/types/components/context.d.ts +8 -0
  14. package/dist/types/components/divider/index.d.ts +3 -0
  15. package/dist/types/components/index.d.ts +41 -0
  16. package/dist/types/components/input/input-auto-complete/index.d.ts +4 -0
  17. package/dist/types/components/input/input-auto-complete/index.type.d.ts +14 -0
  18. package/dist/types/components/input/input-base/index.d.ts +4 -0
  19. package/dist/types/components/input/input-base/index.type.d.ts +11 -0
  20. package/dist/types/components/input/input-basic/index.d.ts +4 -0
  21. package/dist/types/components/input/input-basic/index.type.d.ts +10 -0
  22. package/dist/types/components/input/input-checkbox/index.d.ts +4 -0
  23. package/dist/types/components/input/input-checkbox/index.type.d.ts +13 -0
  24. package/dist/types/components/input/input-date/index.d.ts +22 -0
  25. package/dist/types/components/input/input-date/index.type.d.ts +13 -0
  26. package/dist/types/components/input/input-date-range/index.d.ts +4 -0
  27. package/dist/types/components/input/input-date-range/index.type.d.ts +13 -0
  28. package/dist/types/components/input/input-date-time/index.d.ts +4 -0
  29. package/dist/types/components/input/input-date-time/index.type.d.ts +13 -0
  30. package/dist/types/components/input/input-number/index.d.ts +4 -0
  31. package/dist/types/components/input/input-number/index.type.d.ts +12 -0
  32. package/dist/types/components/input/input-password/index.d.ts +4 -0
  33. package/dist/types/components/input/input-password/index.type.d.ts +10 -0
  34. package/dist/types/components/input/input-radio/index.d.ts +4 -0
  35. package/dist/types/components/input/input-radio/index.type.d.ts +14 -0
  36. package/dist/types/components/input/input-select/index.d.ts +4 -0
  37. package/dist/types/components/input/input-select/index.type.d.ts +16 -0
  38. package/dist/types/components/input/input-switch/index.d.ts +4 -0
  39. package/dist/types/components/input/input-switch/index.type.d.ts +6 -0
  40. package/dist/types/components/input/input-textarea/index.d.ts +4 -0
  41. package/dist/types/components/input/input-textarea/index.type.d.ts +12 -0
  42. package/dist/types/components/menu/index.d.ts +4 -0
  43. package/dist/types/components/menu/index.type.d.ts +11 -0
  44. package/dist/types/components/modal/index.d.ts +4 -0
  45. package/dist/types/components/modal/index.type.d.ts +7 -0
  46. package/dist/types/index.d.ts +41 -0
  47. package/dist/types/main.d.ts +1 -0
  48. package/package.json +5 -1
  49. package/.prettierrc +0 -8
  50. package/.vscode/extensions.json +0 -6
  51. package/declaration.d.ts +0 -10
  52. package/docker-compose.yml +0 -20
  53. package/eslint.config.js +0 -23
  54. package/index.html +0 -13
  55. package/src/App.tsx +0 -370
  56. package/src/components/blackdrop/index.tsx +0 -18
  57. package/src/components/blackdrop/index.type.ts +0 -7
  58. package/src/components/button/index.tsx +0 -44
  59. package/src/components/button/index.type.ts +0 -13
  60. package/src/components/chip/index.tsx +0 -39
  61. package/src/components/chip/index.type.ts +0 -12
  62. package/src/components/context.tsx +0 -26
  63. package/src/components/divider/index.tsx +0 -13
  64. package/src/components/index.ts +0 -62
  65. package/src/components/input/input-auto-complete/index.tsx +0 -140
  66. package/src/components/input/input-auto-complete/index.type.tsx +0 -13
  67. package/src/components/input/input-base/index.tsx +0 -39
  68. package/src/components/input/input-base/index.type.tsx +0 -13
  69. package/src/components/input/input-basic/index.tsx +0 -47
  70. package/src/components/input/input-basic/index.type.tsx +0 -8
  71. package/src/components/input/input-checkbox/index.tsx +0 -69
  72. package/src/components/input/input-checkbox/index.type.tsx +0 -11
  73. package/src/components/input/input-date/index.tsx +0 -354
  74. package/src/components/input/input-date/index.type.tsx +0 -11
  75. package/src/components/input/input-date-range/index.tsx +0 -284
  76. package/src/components/input/input-date-range/index.type.tsx +0 -11
  77. package/src/components/input/input-date-time/index.tsx +0 -367
  78. package/src/components/input/input-date-time/index.type.tsx +0 -11
  79. package/src/components/input/input-number/index.tsx +0 -118
  80. package/src/components/input/input-number/index.type.tsx +0 -11
  81. package/src/components/input/input-password/index.tsx +0 -60
  82. package/src/components/input/input-password/index.type.tsx +0 -8
  83. package/src/components/input/input-radio/index.tsx +0 -72
  84. package/src/components/input/input-radio/index.type.tsx +0 -12
  85. package/src/components/input/input-select/index.tsx +0 -113
  86. package/src/components/input/input-select/index.type.tsx +0 -15
  87. package/src/components/input/input-switch/index.tsx +0 -44
  88. package/src/components/input/input-switch/index.type.tsx +0 -4
  89. package/src/components/input/input-textarea/index.tsx +0 -48
  90. package/src/components/input/input-textarea/index.type.tsx +0 -10
  91. package/src/components/menu/index.tsx +0 -136
  92. package/src/components/menu/index.type.ts +0 -8
  93. package/src/components/modal/index.tsx +0 -99
  94. package/src/components/modal/index.type.tsx +0 -8
  95. package/src/index.scss +0 -44
  96. package/src/index.ts +0 -62
  97. package/src/logoDownload.svg +0 -3
  98. package/src/main.tsx +0 -9
  99. package/tsconfig.app.json +0 -28
  100. package/tsconfig.json +0 -42
  101. package/tsconfig.node.json +0 -29
  102. package/vite.config.d.ts +0 -2
  103. package/vite.config.ts +0 -35
  104. /package/{src → dist}/components/assets/closed.svg +0 -0
  105. /package/{src → dist}/components/assets/expand-arrow.svg +0 -0
  106. /package/{src → dist}/components/assets/visibility-off.svg +0 -0
  107. /package/{src → dist}/components/assets/visibility.svg +0 -0
  108. /package/{src → dist}/components/blackdrop/index.scss +0 -0
  109. /package/{src → dist}/components/button/index.scss +0 -0
  110. /package/{src → dist}/components/chip/index.scss +0 -0
  111. /package/{src → dist}/components/divider/index.scss +0 -0
  112. /package/{src → dist}/components/input/extend.scss +0 -0
  113. /package/{src → dist}/components/input/input-auto-complete/index.scss +0 -0
  114. /package/{src → dist}/components/input/input-base/index.scss +0 -0
  115. /package/{src → dist}/components/input/input-basic/index.scss +0 -0
  116. /package/{src → dist}/components/input/input-checkbox/index.scss +0 -0
  117. /package/{src → dist}/components/input/input-date/index.scss +0 -0
  118. /package/{src → dist}/components/input/input-date-range/index.scss +0 -0
  119. /package/{src → dist}/components/input/input-date-time/index.scss +0 -0
  120. /package/{src → dist}/components/input/input-number/index.scss +0 -0
  121. /package/{src → dist}/components/input/input-password/index.scss +0 -0
  122. /package/{src → dist}/components/input/input-radio/index.scss +0 -0
  123. /package/{src → dist}/components/input/input-select/index.scss +0 -0
  124. /package/{src → dist}/components/input/input-switch/index.scss +0 -0
  125. /package/{src → dist}/components/input/input-textarea/index.scss +0 -0
  126. /package/{src → dist}/components/menu/index.scss +0 -0
  127. /package/{src → dist}/components/modal/index.scss +0 -0
  128. /package/{public → dist}/vite.svg +0 -0
@@ -1,140 +0,0 @@
1
- // Lib
2
- import React, { useState } from "react"
3
- import { Controller, useFormContext } from "react-hook-form"
4
-
5
- // Images
6
- import closedSVG from "../../assets/closed.svg"
7
-
8
- // Include in project
9
- import "./index.scss"
10
- import InputBase from "../input-base"
11
- import Menu from "../../menu"
12
- import { Chip, type TValueOption } from "../.."
13
- import type { PropsInputAutoComplete } from "./index.type"
14
-
15
- const InputAutoComplete: React.FC<PropsInputAutoComplete> = ({
16
- name,
17
- label,
18
- placeholder,
19
- disabled = false,
20
- require = false,
21
- fullWidth = false,
22
- options,
23
- isMultiple = false,
24
- isInModal = false,
25
- }) => {
26
- const { control } = useFormContext()
27
- const [searchText, setSearchText] = useState("")
28
-
29
- return (
30
- <Controller
31
- name={name}
32
- control={control}
33
- render={({ field, fieldState }) => {
34
- const value: TValueOption[] = field.value ?? []
35
- const { onChange } = field
36
- const { invalid, error } = fieldState
37
-
38
- const suggestions = options.filter((opt) => opt.label.toLowerCase().includes(searchText.toLowerCase()))
39
-
40
- const handleSelect = (val: TValueOption, close: () => void) => {
41
- setSearchText("")
42
- close()
43
-
44
- if (isMultiple) {
45
- onChange([...value, val])
46
- } else {
47
- onChange([val])
48
- }
49
- }
50
-
51
- const handleSearchChange = (val: string) => {
52
- setSearchText(val)
53
- if (!isMultiple) {
54
- onChange([val])
55
- }
56
- }
57
-
58
- const handleClearChip = (e: React.MouseEvent<HTMLImageElement>, target: TValueOption) => {
59
- e.stopPropagation()
60
- setSearchText("")
61
- onChange(value.filter((v) => v !== target))
62
- }
63
-
64
- const selectedValue = value[0] || searchText
65
- const selectedOption = options.find((o) => o.label === selectedValue || o.value === selectedValue)
66
-
67
- return (
68
- <InputBase
69
- name={name}
70
- label={label}
71
- require={require}
72
- fullWidth={fullWidth}
73
- isInvalid={invalid}
74
- errorMessage={error?.message}
75
- >
76
- <Menu
77
- isInModal={isInModal}
78
- disabled={disabled}
79
- trigger={() => (
80
- <div className="DBui-wrapInputAutoComplete" data-invalid={invalid} data-disabled={disabled}>
81
- {isMultiple &&
82
- value.map((v, index) => {
83
- const selected = options.find((o) => o.value === v)
84
- if (!selected) return null
85
-
86
- if (disabled) {
87
- return <Chip key={index} label={selected.label} />
88
- }
89
-
90
- return (
91
- <div key={index} className="DBui-wrapSelectValueInputAutoComplete">
92
- <p>
93
- <small>{selected.label}</small>
94
- </p>
95
- <img
96
- src={closedSVG}
97
- className="DBui-iconInputAutoComplete"
98
- onClick={(e) => handleClearChip(e, v)}
99
- />
100
- </div>
101
- )
102
- })}
103
-
104
- <input
105
- className="DBui-inputAutoComplete"
106
- autoComplete="off"
107
- type="text"
108
- placeholder={!value.length ? placeholder : ""}
109
- disabled={disabled}
110
- value={isMultiple ? searchText : selectedOption?.label || value[0] || ""}
111
- onChange={(e) => handleSearchChange(e.target.value)}
112
- />
113
- </div>
114
- )}
115
- >
116
- {({ close }) =>
117
- suggestions.map((opt, index) => {
118
- const isChecked = value.includes(opt.value)
119
-
120
- return (
121
- <p
122
- key={index}
123
- className="DBui-menuItemInputAutoComplete"
124
- data-checked={isChecked}
125
- onClick={() => !isChecked && handleSelect(opt.value, close)}
126
- >
127
- {opt.label}
128
- </p>
129
- )
130
- })
131
- }
132
- </Menu>
133
- </InputBase>
134
- )
135
- }}
136
- />
137
- )
138
- }
139
-
140
- export default InputAutoComplete
@@ -1,13 +0,0 @@
1
- import type { TOption } from "../.."
2
-
3
- export type PropsInputAutoComplete = {
4
- name: string
5
- label?: string
6
- placeholder?: string
7
- disabled?: boolean
8
- require?: boolean
9
- fullWidth?: boolean
10
- options: TOption[]
11
- isMultiple?: boolean
12
- isInModal?: boolean
13
- }
@@ -1,39 +0,0 @@
1
- // Lib
2
- import React from "react"
3
-
4
- // Include in project
5
- import "./index.scss"
6
- import type { PropsInputBase } from "./index.type"
7
-
8
- const InputBase: React.FC<PropsInputBase> = ({
9
- label,
10
- require = false,
11
- fullWidth = false,
12
- children,
13
- isInvalid,
14
- errorMessage,
15
- }) => {
16
- const styleDiv = {
17
- width: !fullWidth ? "fit-content" : "100%",
18
- }
19
-
20
- return (
21
- <div className="DBui-inputBase" style={styleDiv} data-invalid={isInvalid}>
22
- {label && (
23
- <p className="DBui-inputLabel">
24
- <small>{label}</small> {require && <span className="DBui-dataInvalid">*</span>}
25
- </p>
26
- )}
27
-
28
- {children}
29
-
30
- {isInvalid && errorMessage && (
31
- <p className="DBui-dataInvalid">
32
- <small>{errorMessage.toString()}</small>
33
- </p>
34
- )}
35
- </div>
36
- )
37
- }
38
-
39
- export default InputBase
@@ -1,13 +0,0 @@
1
- import type { JSX } from "react"
2
- import type { FieldError, FieldErrorsImpl, Merge } from "react-hook-form"
3
-
4
- export type PropsInputBase = {
5
- name: string
6
- label?: string
7
- require?: boolean
8
- fullWidth?: boolean
9
- children: JSX.Element | JSX.Element[]
10
- isInvalid: boolean
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- errorMessage: string | FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined
13
- }
@@ -1,47 +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 { PropsInputBasic } from "./index.type"
9
-
10
- const Input: React.FC<PropsInputBasic> = ({
11
- name,
12
- label,
13
- placeholder,
14
- disabled = false,
15
- require = false,
16
- fullWidth = false,
17
- }) => {
18
- const { register, control } = useFormContext()
19
- const { errors } = useFormState({
20
- control,
21
- name,
22
- })
23
-
24
- const error = errors?.[name]
25
- const isInvalid = Boolean(error)
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
- <input
36
- {...register(name)}
37
- className="DBui-inputBasic"
38
- type="text"
39
- placeholder={placeholder}
40
- disabled={disabled}
41
- data-invalid={isInvalid}
42
- />
43
- </InputBase>
44
- )
45
- }
46
-
47
- export default Input
@@ -1,8 +0,0 @@
1
- export type PropsInputBasic = {
2
- name: string
3
- label?: string
4
- placeholder?: string
5
- disabled?: boolean
6
- require?: boolean
7
- fullWidth?: boolean
8
- }
@@ -1,69 +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 { PropsInputCheckbox } from "./index.type"
9
-
10
- const InputCheckbox: React.FC<PropsInputCheckbox> = ({
11
- name,
12
- label,
13
- disabled = false,
14
- require = false,
15
- fullWidth = false,
16
- options,
17
- }) => {
18
- const { control } = useFormContext()
19
-
20
- return (
21
- <Controller
22
- name={name}
23
- control={control}
24
- render={({ field, fieldState }) => {
25
- const value: (string | number)[] = field.value ?? []
26
- const { onChange } = field
27
- const { error, invalid } = fieldState
28
-
29
- const toggleValue = (checkedValue: string | number) => {
30
- if (value.includes(checkedValue)) {
31
- onChange(value.filter((v) => v !== checkedValue))
32
- } else {
33
- onChange([...value, checkedValue])
34
- }
35
- }
36
-
37
- return (
38
- <InputBase
39
- name={name}
40
- label={label}
41
- require={require}
42
- fullWidth={fullWidth}
43
- isInvalid={invalid}
44
- errorMessage={error?.message}
45
- >
46
- <div className="DBui-wrapInputCheckboxList">
47
- {options.map((data, index) => (
48
- <div key={index} className="DBui-wrapInputCheckbox">
49
- <input
50
- className="DBui-inputCheckbox"
51
- type="checkbox"
52
- disabled={disabled}
53
- checked={value.includes(data.value)}
54
- onChange={() => toggleValue(data.value)}
55
- />
56
- <p className="DBui-labelCheckbox" data-invalid={invalid}>
57
- <small>{data.label}</small>
58
- </p>
59
- </div>
60
- ))}
61
- </div>
62
- </InputBase>
63
- )
64
- }}
65
- />
66
- )
67
- }
68
-
69
- export default InputCheckbox
@@ -1,11 +0,0 @@
1
- export type PropsInputCheckbox = {
2
- name: string
3
- label?: string
4
- disabled?: boolean
5
- require?: boolean
6
- fullWidth?: boolean
7
- options: {
8
- label: string
9
- value: string | number
10
- }[]
11
- }
@@ -1,354 +0,0 @@
1
- /* eslint-disable react-refresh/only-export-components */
2
- // Lib
3
- import React, { useEffect, useState } from "react"
4
- import { Controller, useFormContext } from "react-hook-form"
5
-
6
- // Images
7
- import expandArrowSVG from "../../assets/expand-arrow.svg"
8
- import closedSVG from "../../assets/closed.svg"
9
-
10
- // Include in project
11
- import "./index.scss"
12
- import InputBase from "../input-base"
13
- import type { PropsInputDate } from "./index.type"
14
- import Menu from "../../menu"
15
- import Modal from "../../modal"
16
- import { createPortal } from "react-dom"
17
-
18
- // 2025-09-01
19
- const InputDate: React.FC<PropsInputDate> = ({
20
- name,
21
- label,
22
- placeholder,
23
- disabled = false,
24
- require = false,
25
- fullWidth = false,
26
- isHideClearIcon = true,
27
- minYear,
28
- maxYear,
29
- }) => {
30
- const { control } = useFormContext()
31
-
32
- const [showDay, setShowDay] = useState(getDateNow())
33
- const [isOpenModal, setIsOpenModal] = useState(false)
34
-
35
- const [mounted, setMounted] = useState(false)
36
- useEffect(() => {
37
- setMounted(true)
38
- return () => setMounted(false)
39
- }, [])
40
-
41
- const yearOption = generateYearOptions(minYear, maxYear)
42
- const monthOption = generateMonthOptions()
43
-
44
- const portalRoot =
45
- (document.getElementById("root") as HTMLElement) ||
46
- (document.getElementById("__next") as HTMLElement) ||
47
- document.body
48
-
49
- return (
50
- <Controller
51
- name={name}
52
- control={control}
53
- render={({ field, fieldState }) => {
54
- const value: string = field.value || ""
55
- const { onChange } = field
56
- const { invalid, error } = fieldState
57
-
58
- // sync showDay เมื่อเปิด modal หรือค่าเปลี่ยน
59
- // eslint-disable-next-line react-hooks/rules-of-hooks
60
- useEffect(() => {
61
- if (!isOpenModal) return
62
- setShowDay(value || getDateNow())
63
- }, [isOpenModal])
64
-
65
- function CalendarRow({ year, month }: { year: number; month: string }) {
66
- const days = getDaysInMonthWithWeekday(year, month)
67
-
68
- const mapToThaiWeek = (dayIndex: number) => dayIndex % 7
69
- const firstDayThaiIndex = mapToThaiWeek(new Date(`${year}-${month}-01`).getDay())
70
- const emptyStartDays = Array(firstDayThaiIndex).fill(null)
71
-
72
- const allDays = [...emptyStartDays, ...days.map((d) => d.date.split("-")[2])]
73
-
74
- while (allDays.length < 42) allDays.push(null)
75
-
76
- const weeks: Array<Array<string | null>> = []
77
- for (let i = 0; i < allDays.length; i += 7) weeks.push(allDays.slice(i, i + 7))
78
-
79
- return (
80
- <>
81
- {weeks.map((week, rowIndex) => (
82
- <div key={rowIndex} className="DBui-inputDateRowDay">
83
- {week.map((day, i) => (
84
- <p
85
- key={i}
86
- className="DBui-inputDateDay"
87
- onClick={() => {
88
- if (!day) return
89
- const next = `${getYearInDateString(showDay)}-${getMonthInDateString(showDay)}-${day}`
90
- onChange(next)
91
- setIsOpenModal(false)
92
- }}
93
- data-checked={
94
- `${getYearInDateString(value || showDay)}-${getMonthInDateString(value || showDay)}-${getDayInDateString(
95
- value || showDay,
96
- )}` === `${getYearInDateString(showDay)}-${getMonthInDateString(showDay)}-${day}`
97
- }
98
- data-hidden-hover={!day}
99
- >
100
- {day || ""}
101
- </p>
102
- ))}
103
- </div>
104
- ))}
105
- </>
106
- )
107
- }
108
-
109
- const handleClear = (e: React.MouseEvent<HTMLImageElement>) => {
110
- e.stopPropagation()
111
- onChange("")
112
- }
113
-
114
- return (
115
- <InputBase
116
- name={name}
117
- label={label}
118
- require={require}
119
- fullWidth={fullWidth}
120
- isInvalid={invalid}
121
- errorMessage={error?.message}
122
- >
123
- <>
124
- <div
125
- className="DBui-inputDate"
126
- onClick={() => (disabled ? null : setIsOpenModal(true))}
127
- data-invalid={invalid}
128
- data-disabled={disabled}
129
- >
130
- <p>{value ? value : placeholder}</p>
131
-
132
- <img
133
- src={closedSVG}
134
- className="DBui-clearIconInputDate"
135
- onClick={handleClear}
136
- data-hidden={value === "" || disabled || isHideClearIcon}
137
- />
138
- </div>
139
-
140
- {mounted &&
141
- createPortal(
142
- <Modal id="modalInputDate" open={isOpenModal} onClose={() => setIsOpenModal(false)}>
143
- <div className="DBui-inputDateWrapperCalendar">
144
- <div className="DBui-inputDateRowMonthYear">
145
- <img
146
- src={expandArrowSVG}
147
- className="DBui-inputDateRowMonthYearSelected"
148
- style={{ transform: "rotate(90deg)" }}
149
- onClick={() => {
150
- setShowDay(
151
- updateMonthInDateString(
152
- showDay,
153
- String(Number(showDay.split("-")[1]) - 1).padStart(2, "0"),
154
- ),
155
- )
156
- }}
157
- />
158
-
159
- <Menu
160
- isInModal
161
- trigger={() => <h4 className="DBui-inputDateRowMonthYearSelected">{showDay.slice(0, 4)}</h4>}
162
- >
163
- {({ close }) =>
164
- yearOption.map((y, index) => (
165
- <p
166
- key={index}
167
- className="DBui-inputDateRowMonthYearOption"
168
- onClick={() => {
169
- setShowDay(updateYearInDateString(showDay, y.value))
170
- close()
171
- }}
172
- data-checked={getYearInDateString(showDay) === y.value}
173
- >
174
- {y.label}
175
- </p>
176
- ))
177
- }
178
- </Menu>
179
-
180
- <Menu
181
- isInModal
182
- trigger={() => (
183
- <h4 className="DBui-inputDateRowMonthYearSelected" style={{ width: "7rem" }}>
184
- {monthOption.find((e) => e.value === showDay.slice(5, 7))?.label}
185
- </h4>
186
- )}
187
- >
188
- {({ close }) =>
189
- monthOption.map((m, index) => (
190
- <p
191
- key={index}
192
- className="DBui-inputDateRowMonthYearOption"
193
- onClick={() => {
194
- setShowDay(updateMonthInDateString(showDay, m.value))
195
- close()
196
- }}
197
- data-checked={getMonthInDateString(showDay) === m.value}
198
- >
199
- {m.label}
200
- </p>
201
- ))
202
- }
203
- </Menu>
204
-
205
- <img
206
- src={expandArrowSVG}
207
- className="DBui-inputDateRowMonthYearSelected"
208
- style={{ transform: "rotate(-90deg)" }}
209
- onClick={() => {
210
- setShowDay(
211
- updateMonthInDateString(
212
- showDay,
213
- String(Number(showDay.split("-")[1]) + 1).padStart(2, "0"),
214
- ),
215
- )
216
- }}
217
- />
218
- </div>
219
-
220
- <div>
221
- <div className="DBui-inputDateRowHeaderDay">
222
- <p className="DBui-inputDateHeader">Sun</p>
223
- <p className="DBui-inputDateHeader">Mon</p>
224
- <p className="DBui-inputDateHeader">Tue</p>
225
- <p className="DBui-inputDateHeader">Wed</p>
226
- <p className="DBui-inputDateHeader">Thu</p>
227
- <p className="DBui-inputDateHeader">Fri</p>
228
- <p className="DBui-inputDateHeader">Sat</p>
229
- </div>
230
-
231
- <CalendarRow year={getYearInDateString(showDay)} month={getMonthInDateString(showDay)} />
232
- </div>
233
- </div>
234
- </Modal>,
235
- portalRoot,
236
- )}
237
- {!mounted && (
238
- <Modal id="modalInputDate" open={isOpenModal} onClose={() => setIsOpenModal(false)}>
239
- <div className="DBui-inputDateWrapperCalendar"></div>
240
- </Modal>
241
- )}
242
- </>
243
- </InputBase>
244
- )
245
- }}
246
- />
247
- )
248
- }
249
-
250
- export default InputDate
251
-
252
- export function generateYearOptions(minYear?: number, maxYear?: number): { label: string; value: number }[] {
253
- const currentYear = new Date().getFullYear()
254
-
255
- // Default values ถ้าไม่ส่งมา
256
- const finalMax = maxYear ?? currentYear
257
- const finalMin = minYear ?? currentYear - 100
258
-
259
- const years = []
260
-
261
- // ไล่ปีแบบมาก -> น้อย
262
- for (let year = finalMax; year >= finalMin; year--) {
263
- years.push({ label: String(year), value: year })
264
- }
265
-
266
- return years
267
- }
268
-
269
- export function generateMonthOptions(): { label: string; value: string }[] {
270
- const monthNames = [
271
- "January",
272
- "February",
273
- "March",
274
- "April",
275
- "May",
276
- "June",
277
- "July",
278
- "August",
279
- "September",
280
- "October",
281
- "November",
282
- "December",
283
- ]
284
-
285
- return monthNames.map((name, index) => ({
286
- label: name,
287
- value: String(index + 1).padStart(2, "0"),
288
- }))
289
- }
290
-
291
- export function updateYearInDateString(dateStr: string, newYear: number): string {
292
- const newDateStr = dateStr ? dateStr : new Date().toISOString().split("T")[0]
293
- const [, month, day] = newDateStr.split("-")
294
-
295
- return `${newYear}-${month}-${day}`
296
- }
297
-
298
- export function updateMonthInDateString(dateStr: string, newMonth: string): string {
299
- const newDateStr = dateStr || new Date().toISOString().split("T")[0]
300
- const [yearStr, , dayStr] = newDateStr.split("-")
301
-
302
- let year = parseInt(yearStr, 10)
303
- let month = parseInt(newMonth, 10)
304
-
305
- // Handle overflow/underflow
306
- year += Math.floor((month - 1) / 12)
307
- month = ((((month - 1) % 12) + 12) % 12) + 1 // Wrap to 1–12
308
-
309
- const monthStr = String(month).padStart(2, "0")
310
- return `${year}-${monthStr}-${dayStr}`
311
- }
312
-
313
- export function getYearInDateString(dateStr: string): number {
314
- const [year] = dateStr.split("-")
315
- return Number(year)
316
- }
317
-
318
- export function getMonthInDateString(dateStr: string): string {
319
- const [, month] = dateStr.split("-")
320
- return month
321
- }
322
-
323
- export function getDayInDateString(dateStr: string): string {
324
- const [, , day] = dateStr.split("-")
325
- return day
326
- }
327
-
328
- export function getDaysInMonthWithWeekday(year: number, month: string): { date: string; weekday: string }[] {
329
- const days: { date: string; weekday: string }[] = []
330
- const monthIndex = parseInt(month, 10) - 1 // JavaScript months are 0-based
331
-
332
- const date = new Date(year, monthIndex, 1)
333
- const weekdayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
334
-
335
- while (date.getMonth() === monthIndex) {
336
- const day = String(date.getDate()).padStart(2, "0")
337
- const weekday = weekdayNames[date.getDay()]
338
- const formattedDate = `${year}-${month}-${day}`
339
-
340
- days.push({ date: formattedDate, weekday })
341
- date.setDate(date.getDate() + 1)
342
- }
343
-
344
- return days
345
- }
346
-
347
- export function getDateNow(): string {
348
- const dateNow = new Date()
349
-
350
- const year = dateNow.getFullYear()
351
- const month = `${dateNow.getMonth() + 1}`.padStart(2, "0")
352
- const date = `${dateNow.getDate()}`.padStart(2, "0")
353
- return `${year}-${month}-${date}`
354
- }