notionsoft-ui 1.0.20 → 1.0.21
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/package.json +2 -1
- package/src/notion-ui/button/button.tsx +1 -1
- package/src/notion-ui/date-picker/DatePicker.stories.tsx +99 -0
- package/src/notion-ui/date-picker/date-picker.tsx +273 -0
- package/src/notion-ui/date-picker/index.ts +3 -0
- package/src/notion-ui/input/input.tsx +19 -12
- package/src/notion-ui/multi-date-picker/MultiDatePicker.stories.tsx +94 -0
- package/src/notion-ui/multi-date-picker/index.ts +3 -0
- package/src/notion-ui/multi-date-picker/multi-date-picker.tsx +265 -0
- package/src/notion-ui/multi-select-input/multi-select-input.tsx +202 -54
- package/src/notion-ui/password-input/password-input.tsx +39 -34
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { CalendarDays } from "lucide-react";
|
|
3
|
+
import DatePanel from "react-multi-date-picker/plugins/date_panel";
|
|
4
|
+
import AnimatedItem from "../animated-item";
|
|
5
|
+
import type { Calendar, Locale } from "react-date-object";
|
|
6
|
+
import type DateObject from "react-date-object";
|
|
7
|
+
import { Calendar as Calendars } from "react-multi-date-picker";
|
|
8
|
+
import gregorian from "react-date-object/calendars/gregorian";
|
|
9
|
+
import gregorian_en from "react-date-object/locales/gregorian_en";
|
|
10
|
+
import { cn } from "../../utils/cn";
|
|
11
|
+
|
|
12
|
+
export type MultiDatePickerSize = "sm" | "md" | "lg";
|
|
13
|
+
|
|
14
|
+
interface MultiDatePickerText {
|
|
15
|
+
label?: string;
|
|
16
|
+
requiredHint?: string;
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
to?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface MultiDatePickerProps {
|
|
21
|
+
dateOnComplete: (selectedDates: DateObject[]) => void;
|
|
22
|
+
value: DateObject[];
|
|
23
|
+
className?: string;
|
|
24
|
+
measurement?: MultiDatePickerSize;
|
|
25
|
+
classNames?: {
|
|
26
|
+
rootDivClassName?: string;
|
|
27
|
+
};
|
|
28
|
+
errorMessage?: string;
|
|
29
|
+
readOnly?: boolean;
|
|
30
|
+
text?: MultiDatePickerText;
|
|
31
|
+
startContent?: React.ReactNode;
|
|
32
|
+
endContent?: React.ReactNode;
|
|
33
|
+
getLocalizations?: () => {
|
|
34
|
+
calendar?: Calendar;
|
|
35
|
+
locale?: Locale;
|
|
36
|
+
months?: string[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default function MultiDatePicker(props: MultiDatePickerProps) {
|
|
41
|
+
const {
|
|
42
|
+
dateOnComplete,
|
|
43
|
+
value,
|
|
44
|
+
className,
|
|
45
|
+
measurement = "sm",
|
|
46
|
+
classNames,
|
|
47
|
+
errorMessage,
|
|
48
|
+
readOnly,
|
|
49
|
+
startContent,
|
|
50
|
+
endContent,
|
|
51
|
+
getLocalizations,
|
|
52
|
+
text,
|
|
53
|
+
} = props;
|
|
54
|
+
const { requiredHint, label, placeholder, to } = text || {};
|
|
55
|
+
const { rootDivClassName } = classNames || {};
|
|
56
|
+
const [visible, setVisible] = useState(false);
|
|
57
|
+
const [selectedDates, setSelectedDates] = useState<DateObject[]>(value);
|
|
58
|
+
const calendarRef = useRef<any>(null);
|
|
59
|
+
const hasError = !!errorMessage;
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
// Add event listener for clicks outside
|
|
63
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
64
|
+
return () => {
|
|
65
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
66
|
+
};
|
|
67
|
+
}, []);
|
|
68
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
69
|
+
if (
|
|
70
|
+
calendarRef.current &&
|
|
71
|
+
!calendarRef.current.contains(event.target as Node)
|
|
72
|
+
) {
|
|
73
|
+
setVisible(false);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const handleDateChange = (selectedDates: DateObject[]) => {
|
|
78
|
+
// let object = { date, format };
|
|
79
|
+
// const gre = new DateObject(object)
|
|
80
|
+
// .convert(gregorian, gregorian_en)
|
|
81
|
+
// .format();
|
|
82
|
+
dateOnComplete(selectedDates);
|
|
83
|
+
setSelectedDates(selectedDates);
|
|
84
|
+
};
|
|
85
|
+
const onVisibilityChange = () => {
|
|
86
|
+
if (!readOnly) setVisible(!visible);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const heightStyle = useMemo(
|
|
90
|
+
() =>
|
|
91
|
+
measurement == "lg"
|
|
92
|
+
? {
|
|
93
|
+
height: "50px",
|
|
94
|
+
paddingBottom: "pb-[3px]",
|
|
95
|
+
endContent: label
|
|
96
|
+
? "ltr:top-[48px] rtl:top-[54px]-translate-y-1/2"
|
|
97
|
+
: "top-[26px] -translate-y-1/2",
|
|
98
|
+
startContent: label
|
|
99
|
+
? "ltr:top-[48px] rtl:top-[54px] -translate-y-1/2"
|
|
100
|
+
: "top-[26px] -translate-y-1/2",
|
|
101
|
+
required: label ? "ltr:top-[4px] rtl:top-[12px]" : "top-[-19px]",
|
|
102
|
+
}
|
|
103
|
+
: measurement == "md"
|
|
104
|
+
? {
|
|
105
|
+
height: "44px",
|
|
106
|
+
paddingBottom: "pb-[2px]",
|
|
107
|
+
endContent: label
|
|
108
|
+
? "ltr:top-[45px] rtl:top-[51px] -translate-y-1/2"
|
|
109
|
+
: "top-[22px] -translate-y-1/2",
|
|
110
|
+
startContent: label
|
|
111
|
+
? "ltr:top-[45px] rtl:top-[51px] -translate-y-1/2"
|
|
112
|
+
: "top-[22px] -translate-y-1/2",
|
|
113
|
+
required: label ? "ltr:top-[4px] rtl:top-[12px]" : "top-[-19px]",
|
|
114
|
+
}
|
|
115
|
+
: {
|
|
116
|
+
height: "40px",
|
|
117
|
+
paddingBottom: "pb-[2px]",
|
|
118
|
+
endContent: label
|
|
119
|
+
? "ltr:top-[44px] rtl:top-[50px] -translate-y-1/2"
|
|
120
|
+
: "top-[20px] -translate-y-1/2",
|
|
121
|
+
startContent: label
|
|
122
|
+
? "ltr:top-[44px] rtl:top-[50px] -translate-y-1/2"
|
|
123
|
+
: "top-[20px] -translate-y-1/2",
|
|
124
|
+
required: label ? "ltr:top-[4px] rtl:top-[12px]" : "top-[-19px]",
|
|
125
|
+
},
|
|
126
|
+
[measurement, label]
|
|
127
|
+
);
|
|
128
|
+
const readOnlyStyle = readOnly && "opacity-40";
|
|
129
|
+
const localizations = getLocalizations
|
|
130
|
+
? getLocalizations()
|
|
131
|
+
: {
|
|
132
|
+
calendar: gregorian,
|
|
133
|
+
locale: gregorian_en,
|
|
134
|
+
months: [],
|
|
135
|
+
};
|
|
136
|
+
return (
|
|
137
|
+
<div
|
|
138
|
+
className={cn(
|
|
139
|
+
rootDivClassName,
|
|
140
|
+
"relative flex w-full flex-col justify-end",
|
|
141
|
+
readOnlyStyle
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
{visible && (
|
|
145
|
+
<Calendars
|
|
146
|
+
value={selectedDates}
|
|
147
|
+
ref={calendarRef}
|
|
148
|
+
className="absolute font-segoe top-10"
|
|
149
|
+
onChange={handleDateChange}
|
|
150
|
+
range
|
|
151
|
+
plugins={[<DatePanel position="top" className="h-28" />]}
|
|
152
|
+
months={localizations.months}
|
|
153
|
+
calendar={localizations.calendar}
|
|
154
|
+
locale={localizations.locale}
|
|
155
|
+
/>
|
|
156
|
+
)}
|
|
157
|
+
{/* Start Content */}
|
|
158
|
+
{startContent && (
|
|
159
|
+
<span
|
|
160
|
+
className={cn(
|
|
161
|
+
"absolute flex items-center ltr:left-3 rtl:right-3",
|
|
162
|
+
heightStyle.startContent
|
|
163
|
+
)}
|
|
164
|
+
>
|
|
165
|
+
{startContent}
|
|
166
|
+
</span>
|
|
167
|
+
)}
|
|
168
|
+
|
|
169
|
+
{/* End Content */}
|
|
170
|
+
{endContent && (
|
|
171
|
+
<span
|
|
172
|
+
className={cn(
|
|
173
|
+
"absolute flex items-center ltr:right-[5px] rtl:left-[5px]",
|
|
174
|
+
heightStyle.endContent
|
|
175
|
+
)}
|
|
176
|
+
>
|
|
177
|
+
{endContent}
|
|
178
|
+
</span>
|
|
179
|
+
)}
|
|
180
|
+
|
|
181
|
+
{/* Required Hint */}
|
|
182
|
+
{requiredHint && (
|
|
183
|
+
<span
|
|
184
|
+
className={cn(
|
|
185
|
+
"absolute font-semibold text-red-600 rtl:text-[13px] ltr:text-[11px] ltr:right-2.5 rtl:left-2.5",
|
|
186
|
+
heightStyle.required
|
|
187
|
+
)}
|
|
188
|
+
>
|
|
189
|
+
{requiredHint}
|
|
190
|
+
</span>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
{/* Label */}
|
|
194
|
+
{label && (
|
|
195
|
+
<label
|
|
196
|
+
htmlFor={label}
|
|
197
|
+
className={cn(
|
|
198
|
+
"font-semibold rtl:text-xl-rtl ltr:text-lg-ltr inline-block pb-1"
|
|
199
|
+
)}
|
|
200
|
+
>
|
|
201
|
+
{label}
|
|
202
|
+
</label>
|
|
203
|
+
)}
|
|
204
|
+
<div
|
|
205
|
+
style={{
|
|
206
|
+
height: heightStyle.height,
|
|
207
|
+
}}
|
|
208
|
+
className={cn(
|
|
209
|
+
"relative flex items-center text-start px-3 border select-none rounded-sm rtl:text-lg-rtl ltr:text-lg-ltr",
|
|
210
|
+
className
|
|
211
|
+
)}
|
|
212
|
+
onClick={onVisibilityChange}
|
|
213
|
+
>
|
|
214
|
+
{selectedDates && selectedDates.length > 0 ? (
|
|
215
|
+
<div className="flex items-center gap-x-2 text-ellipsis rtl:text-lg-rtl ltr:text-lg-ltr text-primary/80 text-nowrap">
|
|
216
|
+
<CalendarDays className="size-4 inline-block text-tertiary rtl:ml-2 rtl:mr-2" />
|
|
217
|
+
{selectedDates.map((date: DateObject, index: number) => (
|
|
218
|
+
<div key={index} className="flex gap-x-2">
|
|
219
|
+
{index % 2 == 1 && (
|
|
220
|
+
<h1 className="text-tertiary font-semibold">{to}</h1>
|
|
221
|
+
)}
|
|
222
|
+
<h1>
|
|
223
|
+
{date
|
|
224
|
+
.convert(localizations.calendar, localizations.locale)
|
|
225
|
+
.format()}
|
|
226
|
+
</h1>
|
|
227
|
+
{/* <h1>{formatHijriDate(date)}</h1> */}
|
|
228
|
+
</div>
|
|
229
|
+
))}
|
|
230
|
+
</div>
|
|
231
|
+
) : (
|
|
232
|
+
<h1 className="flex items-center gap-x-2 text-ellipsis rtl:text-lg-rtl ltr:text-lg-ltr text-primary/80 text-nowrap">
|
|
233
|
+
<CalendarDays className="size-4 inline-block text-tertiary" />
|
|
234
|
+
{placeholder}
|
|
235
|
+
</h1>
|
|
236
|
+
)}
|
|
237
|
+
</div>
|
|
238
|
+
{/* Error Message */}
|
|
239
|
+
{hasError && (
|
|
240
|
+
<AnimatedItem
|
|
241
|
+
springProps={{
|
|
242
|
+
from: {
|
|
243
|
+
opacity: 0,
|
|
244
|
+
transform: "translateY(-8px)",
|
|
245
|
+
},
|
|
246
|
+
config: {
|
|
247
|
+
mass: 1,
|
|
248
|
+
tension: 210,
|
|
249
|
+
friction: 20,
|
|
250
|
+
},
|
|
251
|
+
to: {
|
|
252
|
+
opacity: 1,
|
|
253
|
+
transform: "translateY(0px)",
|
|
254
|
+
},
|
|
255
|
+
}}
|
|
256
|
+
intersectionArgs={{ once: true, rootMargin: "-5% 0%" }}
|
|
257
|
+
>
|
|
258
|
+
<h1 className="text-red-400 text-start capitalize rtl:text-sm rtl:font-medium ltr:text-sm-ltr">
|
|
259
|
+
{errorMessage}
|
|
260
|
+
</h1>
|
|
261
|
+
</AnimatedItem>
|
|
262
|
+
)}
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
}
|