ml-ui-lib 1.0.0
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/components/Alert/Alert.d.ts +9 -0
- package/dist/components/Alert/Alert.js +11 -0
- package/dist/components/Button/Button.d.ts +8 -0
- package/dist/components/Button/Button.js +5 -0
- package/dist/components/DatePicker/DatePicker.d.ts +16 -0
- package/dist/components/DatePicker/DatePicker.js +44 -0
- package/dist/components/DatePicker2/DatePicker2.d.ts +13 -0
- package/dist/components/DatePicker2/DatePicker2.js +71 -0
- package/dist/components/Dropdown/Dropdown.d.ts +13 -0
- package/dist/components/Dropdown/Dropdown.js +21 -0
- package/dist/components/Input/Input.d.ts +7 -0
- package/dist/components/Input/Input.js +5 -0
- package/dist/components/Modal/Modal.d.ts +11 -0
- package/dist/components/Modal/Modal.js +23 -0
- package/dist/components/PhoneInput/PhoneInput.d.ts +10 -0
- package/dist/components/PhoneInput/PhoneInput.js +59 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +9 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +25 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./Alert.css";
|
|
3
|
+
export type AlertVariant = "info" | "error" | "warning" | "success";
|
|
4
|
+
export interface AlertProps {
|
|
5
|
+
variant?: AlertVariant;
|
|
6
|
+
title?: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const Alert: React.FC<AlertProps>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "./Alert.css";
|
|
3
|
+
export const Alert = ({ variant = "info", title, message, }) => {
|
|
4
|
+
const icons = {
|
|
5
|
+
info: "https://cdn-icons-png.flaticon.com/512/11086/11086161.png",
|
|
6
|
+
success: "https://cdn-icons-png.flaticon.com/512/845/845646.png",
|
|
7
|
+
warning: "https://cdn-icons-png.flaticon.com/512/595/595067.png",
|
|
8
|
+
error: "https://cdn-icons-png.flaticon.com/512/463/463612.png",
|
|
9
|
+
};
|
|
10
|
+
return (_jsxs("div", { className: `alert alert-${variant}`, children: [_jsx("img", { src: icons[variant], alt: variant, className: "alert-icon" }), _jsxs("div", { className: "alert-content", children: [title && _jsx("strong", { className: "alert-title", children: title }), _jsx("p", { className: "alert-message", children: message })] })] }));
|
|
11
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./DatePicker.css";
|
|
3
|
+
export interface DatePickerValue {
|
|
4
|
+
day: number;
|
|
5
|
+
month: number;
|
|
6
|
+
year: number;
|
|
7
|
+
}
|
|
8
|
+
export interface DatePickerProps {
|
|
9
|
+
value?: DatePickerValue;
|
|
10
|
+
onChange?: (value: DatePickerValue) => void;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const DatePicker: React.FC<DatePickerProps>;
|
|
16
|
+
export default DatePicker;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef, useEffect } from "react";
|
|
4
|
+
import "./DatePicker.css";
|
|
5
|
+
export const DatePicker = ({ value, onChange, placeholder = "Select date", className = "", error, }) => {
|
|
6
|
+
const [open, setOpen] = useState(false);
|
|
7
|
+
const [selectedDate, setSelectedDate] = useState(value || null);
|
|
8
|
+
const today = new Date();
|
|
9
|
+
const [currentMonth, setCurrentMonth] = useState(value?.month ? value.month - 1 : today.getMonth());
|
|
10
|
+
const [currentYear, setCurrentYear] = useState(value?.year || today.getFullYear());
|
|
11
|
+
const wrapperRef = useRef(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const handleClickOutside = (e) => {
|
|
14
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
|
|
15
|
+
setOpen(false);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
19
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
20
|
+
}, []);
|
|
21
|
+
const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
|
|
22
|
+
const firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
|
|
23
|
+
const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
24
|
+
const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
25
|
+
const handleDayClick = (day) => {
|
|
26
|
+
const newDate = { day, month: currentMonth + 1, year: currentYear };
|
|
27
|
+
setSelectedDate(newDate);
|
|
28
|
+
onChange?.(newDate);
|
|
29
|
+
setOpen(false);
|
|
30
|
+
};
|
|
31
|
+
return (_jsxs("div", { className: `datepicker-wrapper ${className} ${error ? "has-error" : ""}`, ref: wrapperRef, children: [_jsxs("div", { className: "datepicker-input-wrapper", onClick: () => setOpen(!open), children: [_jsx("input", { readOnly: true, value: selectedDate
|
|
32
|
+
? `${String(selectedDate.day).padStart(2, "0")}/${String(selectedDate.month).padStart(2, "0")}/${selectedDate.year}`
|
|
33
|
+
: "", placeholder: placeholder, className: "datepicker-input" }), _jsxs("svg", { className: "datepicker-icon", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", width: "18", height: "18", children: [_jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), _jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), _jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), _jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })] })] }), open && (_jsxs("div", { className: "datepicker-calendar", children: [_jsxs("div", { className: "datepicker-header", children: [_jsx("button", { onClick: () => setCurrentMonth((prev) => (prev === 0 ? 11 : prev - 1)), children: "\u25C0" }), _jsxs("span", { children: [monthNames[currentMonth], " ", currentYear] }), _jsx("button", { onClick: () => setCurrentMonth((prev) => (prev === 11 ? 0 : prev + 1)), children: "\u25B6" })] }), _jsx("div", { className: "datepicker-weekdays", children: weekDays.map((d) => (_jsx("div", { className: "datepicker-weekday", children: d }, d))) }), _jsxs("div", { className: "datepicker-days-grid", children: [Array.from({ length: firstDayOfMonth }).map((_, i) => (_jsx("div", { className: "datepicker-day empty" }, `empty-${i}`))), Array.from({ length: daysInMonth }).map((_, i) => {
|
|
34
|
+
const day = i + 1;
|
|
35
|
+
const isSelected = selectedDate?.day === day &&
|
|
36
|
+
selectedDate?.month === currentMonth + 1 &&
|
|
37
|
+
selectedDate?.year === currentYear;
|
|
38
|
+
const isToday = today.getDate() === day &&
|
|
39
|
+
today.getMonth() === currentMonth &&
|
|
40
|
+
today.getFullYear() === currentYear;
|
|
41
|
+
return (_jsx("div", { className: `datepicker-day ${isSelected ? "selected" : ""} ${isToday ? "today" : ""}`, onClick: () => handleDayClick(day), children: day }, day));
|
|
42
|
+
})] })] })), error && _jsx("span", { className: "datepicker-error", children: error })] }));
|
|
43
|
+
};
|
|
44
|
+
export default DatePicker;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./DatePicker2.css";
|
|
3
|
+
export interface DateValue {
|
|
4
|
+
month: number;
|
|
5
|
+
day: number;
|
|
6
|
+
year: number;
|
|
7
|
+
}
|
|
8
|
+
export interface DatePicker2Props {
|
|
9
|
+
value?: DateValue;
|
|
10
|
+
onChange?: (date: DateValue) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const DatePicker2: React.FC<DatePicker2Props>;
|
|
13
|
+
export default DatePicker2;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef } from "react";
|
|
3
|
+
import "./DatePicker2.css";
|
|
4
|
+
export const DatePicker2 = ({ value, onChange }) => {
|
|
5
|
+
const currentYear = new Date().getFullYear();
|
|
6
|
+
const months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
|
|
7
|
+
const [year, setYear] = useState(null);
|
|
8
|
+
const [month, setMonth] = useState(null);
|
|
9
|
+
const [monthLabel, setMonthLabel] = useState(null);
|
|
10
|
+
const [day, setDay] = useState(null);
|
|
11
|
+
const [daysInMonth, setDaysInMonth] = useState([]);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (month && day && year && onChange) {
|
|
14
|
+
const newDate = { month, day, year };
|
|
15
|
+
// Only call onChange if different
|
|
16
|
+
if (!value ||
|
|
17
|
+
value.month !== month ||
|
|
18
|
+
value.day !== day ||
|
|
19
|
+
value.year !== year) {
|
|
20
|
+
onChange(newDate);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}, [month, day, year]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (value) {
|
|
26
|
+
setYear(value.year);
|
|
27
|
+
setMonth(value.month);
|
|
28
|
+
setDay(value.day);
|
|
29
|
+
setMonthLabel(months[value.month - 1]);
|
|
30
|
+
}
|
|
31
|
+
}, [value]);
|
|
32
|
+
const [yearOpen, setYearOpen] = useState(false);
|
|
33
|
+
const [monthOpen, setMonthOpen] = useState(false);
|
|
34
|
+
const [dayOpen, setDayOpen] = useState(false);
|
|
35
|
+
const wrapperRef = useRef(null);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const handleClickOutside = (e) => {
|
|
38
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
|
|
39
|
+
setYearOpen(false);
|
|
40
|
+
setMonthOpen(false);
|
|
41
|
+
setDayOpen(false);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
45
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
46
|
+
}, []);
|
|
47
|
+
// Update days in month
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (month && year) {
|
|
50
|
+
const totalDays = new Date(year, month, 0).getDate();
|
|
51
|
+
setDaysInMonth([...Array(totalDays)].map((_, i) => i + 1));
|
|
52
|
+
if (day && day > totalDays)
|
|
53
|
+
setDay(totalDays);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
setDaysInMonth([]);
|
|
57
|
+
setDay(null);
|
|
58
|
+
}
|
|
59
|
+
}, [month, year]);
|
|
60
|
+
// Trigger onChange
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (year && month && day && onChange) {
|
|
63
|
+
onChange({ year, month, day });
|
|
64
|
+
}
|
|
65
|
+
}, [year, month, day, onChange]);
|
|
66
|
+
return (_jsxs("div", { className: "date-picker-wrapper", ref: wrapperRef, children: [_jsxs("div", { className: "full-width", children: [_jsxs("div", { className: "date-picker-dropdown", onClick: () => { setYearOpen(!yearOpen); setMonthOpen(false); setDayOpen(false); }, children: [_jsx("span", { className: "readble", children: year ?? "Year" }), _jsx("span", { className: "date-picker-dropdown-carret", children: "\u25BC" })] }), yearOpen && (_jsxs("div", { className: "date-picker-grid-wrapper", children: [_jsxs("div", { className: "date-picker-header", children: [_jsx("span", { children: "Select Year" }), _jsx("button", { onClick: () => setYearOpen(false), children: "\u2715" })] }), _jsx("div", { className: "date-picker-grid scrollbar", children: [...Array(100)].map((_, i) => {
|
|
67
|
+
const y = currentYear - i;
|
|
68
|
+
return (_jsx("div", { className: `date-picker-dropdown-option ${y === year ? "selected" : ""}`, onClick: () => { setYear(y); setYearOpen(false); setMonthOpen(true); }, children: y }, y));
|
|
69
|
+
}) })] }))] }), _jsxs("div", { className: "full-width", children: [_jsxs("div", { className: "date-picker-dropdown", onClick: () => { setMonthOpen(!monthOpen); setYearOpen(false); setDayOpen(false); }, children: [_jsx("span", { className: "readble", children: monthLabel ?? "Month" }), _jsx("span", { className: "date-picker-dropdown-carret", children: "\u25BC" })] }), monthOpen && (_jsxs("div", { className: "date-picker-grid-wrapper", children: [_jsxs("div", { className: "date-picker-header", children: [_jsx("span", { children: "Select Month" }), _jsx("button", { onClick: () => setMonthOpen(false), children: "\u2715" })] }), _jsx("div", { className: "date-picker-grid scrollbar", children: months.map((m, idx) => (_jsx("div", { className: `date-picker-dropdown-option ${month === idx + 1 ? "selected" : ""}`, onClick: () => { setMonth(idx + 1); setMonthLabel(m); setMonthOpen(false); setDayOpen(true); }, children: m }, idx))) })] }))] }), _jsxs("div", { className: "full-width", children: [_jsxs("div", { className: "date-picker-dropdown", onClick: () => { setDayOpen(!dayOpen); setMonthOpen(false); setYearOpen(false); }, children: [_jsx("span", { className: "readble", children: day ?? "Day" }), _jsx("span", { className: "date-picker-dropdown-carret", children: "\u25BC" })] }), dayOpen && daysInMonth.length > 0 && (_jsxs("div", { className: "date-picker-grid-wrapper", children: [_jsxs("div", { className: "date-picker-header", children: [_jsx("span", { children: "Select Day" }), _jsx("button", { onClick: () => setDayOpen(false), children: "\u2715" })] }), _jsx("div", { className: "date-picker-grid scrollbar", children: daysInMonth.map((d) => (_jsx("div", { className: `date-picker-dropdown-option ${day === d ? "selected" : ""}`, onClick: () => { setDay(d); setDayOpen(false); }, children: d }, d))) })] })), dayOpen && daysInMonth.length === 0 && (_jsx("div", { className: "date-picker-empty", children: "Select Year and Month first." }))] })] }));
|
|
70
|
+
};
|
|
71
|
+
export default DatePicker2;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./Dropdown.css";
|
|
3
|
+
export interface DropdownProps {
|
|
4
|
+
label?: string;
|
|
5
|
+
options: string[];
|
|
6
|
+
value: string;
|
|
7
|
+
onChange: (value: string) => void;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const Dropdown: React.FC<DropdownProps>;
|
|
13
|
+
export default Dropdown;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect } from "react";
|
|
3
|
+
import "./Dropdown.css";
|
|
4
|
+
export const Dropdown = ({ label, value, options, onChange, placeholder = "Select", className = "", error, }) => {
|
|
5
|
+
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
6
|
+
const dropdownRef = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const handleClickOutside = (e) => {
|
|
9
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
10
|
+
setDropdownOpen(false);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
14
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
15
|
+
}, []);
|
|
16
|
+
return (_jsxs("div", { className: `dropdown-wrapper ${className} ${error ? "has-error" : ""}`, ref: dropdownRef, children: [label && _jsx("label", { className: "dropdown-label", children: label }), _jsxs("div", { className: "dropdown-trigger", onClick: () => setDropdownOpen(!dropdownOpen), children: [_jsx("span", { className: "dropdown-value", children: value === "" ? placeholder : value }), _jsx("span", { className: "dropdown-caret", children: "\u25BC" })] }), dropdownOpen && (_jsx("div", { className: "dropdown-list scrollbar", children: options.length > 0 ? (options.map((option, i) => (_jsx("div", { className: `dropdown-option ${value === option ? "selected" : ""}`, onClick: () => {
|
|
17
|
+
onChange(option);
|
|
18
|
+
setDropdownOpen(false);
|
|
19
|
+
}, children: option }, i)))) : (_jsx("div", { className: "dropdown-empty", children: "No options" })) })), error && _jsx("span", { className: "dropdown-error", children: error })] }));
|
|
20
|
+
};
|
|
21
|
+
export default Dropdown;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "./Input.css";
|
|
3
|
+
export const Input = ({ label, error, ...props }) => {
|
|
4
|
+
return (_jsxs("div", { className: "input-wrapper", children: [label && _jsx("label", { className: "input-label", children: label }), _jsx("input", { className: `input ${error ? "input-error" : ""}`, ...props, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false }), error && _jsx("span", { className: "input-error-text", children: error })] }));
|
|
5
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./Modal.css";
|
|
3
|
+
export interface ModalProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
title?: string;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
zIndex?: number;
|
|
9
|
+
variant?: "default" | "info" | "success" | "warning" | "error";
|
|
10
|
+
}
|
|
11
|
+
export declare const Modal: React.FC<ModalProps>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import "./Modal.css";
|
|
4
|
+
// import DefaultIcon from "./icons/default.png";
|
|
5
|
+
// import InfoIcon from "./icons/info.png";
|
|
6
|
+
// import SuccessIcon from "./icons/success.png";
|
|
7
|
+
// import WarningIcon from "./icons/error.png";
|
|
8
|
+
import ErrorIcon from "./icons/error.png";
|
|
9
|
+
export const Modal = ({ open, onClose, title, children, zIndex = 1000, variant = "default", }) => {
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
document.body.style.overflow = open ? "hidden" : "";
|
|
12
|
+
}, [open]);
|
|
13
|
+
if (!open)
|
|
14
|
+
return null;
|
|
15
|
+
const variantIcon = {
|
|
16
|
+
// default: DefaultIcon,
|
|
17
|
+
// info: InfoIcon,
|
|
18
|
+
// success: SuccessIcon,
|
|
19
|
+
// warning: WarningIcon,
|
|
20
|
+
error: ErrorIcon,
|
|
21
|
+
}[variant];
|
|
22
|
+
return (_jsx("div", { className: "modal-overlay", onClick: onClose, style: { zIndex }, children: _jsxs("div", { className: `modal modal-${variant}`, onClick: (e) => e.stopPropagation(), style: { zIndex: zIndex + 1 }, children: [title && (_jsx("div", { className: "modal-header", children: _jsx("h2", { className: "modal-title", children: title }) })), _jsx("div", { className: "modal-content", children: children })] }) }));
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./PhoneInput.css";
|
|
3
|
+
export interface PhoneInputProps {
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (formatted: string) => void;
|
|
6
|
+
country?: string;
|
|
7
|
+
onCountryChange?: (countryCode: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const PhoneInput: React.FC<PhoneInputProps>;
|
|
10
|
+
export default PhoneInput;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import "./PhoneInput.css";
|
|
5
|
+
const countryOptions = {
|
|
6
|
+
PH: {
|
|
7
|
+
code: "+63",
|
|
8
|
+
country: "Philippines",
|
|
9
|
+
flag: "https://flagcdn.com/w20/ph.png",
|
|
10
|
+
placeholder: "988 888 8888",
|
|
11
|
+
},
|
|
12
|
+
US: {
|
|
13
|
+
code: "+1",
|
|
14
|
+
country: "United States",
|
|
15
|
+
flag: "https://flagcdn.com/w20/us.png",
|
|
16
|
+
placeholder: "(000) 888 8888",
|
|
17
|
+
},
|
|
18
|
+
CA: {
|
|
19
|
+
code: "+1",
|
|
20
|
+
country: "Canada",
|
|
21
|
+
flag: "https://flagcdn.com/w20/ca.png",
|
|
22
|
+
placeholder: "000 888 8888",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export const PhoneInput = ({ value, onChange, country = "PH", onCountryChange, }) => {
|
|
26
|
+
const [selectedCountry, setSelectedCountry] = useState(country);
|
|
27
|
+
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
28
|
+
const dropdownRef = useRef(null);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const handleClickOutside = (e) => {
|
|
31
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
32
|
+
setDropdownOpen(false);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
36
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
37
|
+
}, []);
|
|
38
|
+
const handleCountrySelect = (countryKey) => {
|
|
39
|
+
setSelectedCountry(countryKey);
|
|
40
|
+
setDropdownOpen(false);
|
|
41
|
+
onCountryChange?.(countryKey);
|
|
42
|
+
};
|
|
43
|
+
const formatPhone = (raw) => {
|
|
44
|
+
const digits = raw.replace(/\D/g, "");
|
|
45
|
+
if (selectedCountry === "PH") {
|
|
46
|
+
return digits.replace(/^(\d{3})(\d{3})(\d{0,4}).*/, "$1 $2 $3").trim();
|
|
47
|
+
}
|
|
48
|
+
if (selectedCountry === "US" || selectedCountry === "CA") {
|
|
49
|
+
return digits.replace(/^(\d{3})(\d{3})(\d{0,4}).*/, "($1) $2 $3").trim();
|
|
50
|
+
}
|
|
51
|
+
return digits;
|
|
52
|
+
};
|
|
53
|
+
const handleInputChange = (e) => {
|
|
54
|
+
const formatted = formatPhone(e.target.value);
|
|
55
|
+
onChange(formatted);
|
|
56
|
+
};
|
|
57
|
+
return (_jsxs("div", { className: "phone-input-wrapper", ref: dropdownRef, children: [_jsxs("div", { className: "country-dropdown", onClick: () => setDropdownOpen(!dropdownOpen), children: [_jsx("img", { src: countryOptions[selectedCountry].flag, alt: countryOptions[selectedCountry].country, className: "country-flag" }), _jsx("span", { className: "country-code", children: countryOptions[selectedCountry].code })] }), dropdownOpen && (_jsx("div", { className: "country-dropdown-menu", children: Object.entries(countryOptions).map(([key, { code, country, flag }]) => (_jsxs("div", { className: "country-dropdown-item", onClick: () => handleCountrySelect(key), children: [_jsx("img", { src: flag, alt: country, className: "country-flag" }), _jsx("span", { children: country }), _jsx("span", { className: "country-code-text", children: code })] }, key))) })), _jsx("input", { type: "text", value: value, onChange: handleInputChange, placeholder: countryOptions[selectedCountry].placeholder, className: "phone-input", autoComplete: "off" })] }));
|
|
58
|
+
};
|
|
59
|
+
export default PhoneInput;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "./common.css";
|
|
2
|
+
export { Button } from "./components/Button/Button";
|
|
3
|
+
export type { ButtonProps } from "./components/Button/Button";
|
|
4
|
+
export { Modal } from "./components/Modal/Modal";
|
|
5
|
+
export type { ModalProps } from "./components/Modal/Modal";
|
|
6
|
+
export { Input } from "./components/Input/Input";
|
|
7
|
+
export type { InputProps } from "./components/Input/Input";
|
|
8
|
+
export { Alert } from "./components/Alert/Alert";
|
|
9
|
+
export type { AlertProps, AlertVariant } from "./components/Alert/Alert";
|
|
10
|
+
export { PhoneInput } from "./components/PhoneInput/PhoneInput";
|
|
11
|
+
export type { PhoneInputProps } from "./components/PhoneInput/PhoneInput";
|
|
12
|
+
export { Dropdown } from "./components/Dropdown/Dropdown";
|
|
13
|
+
export type { DropdownProps } from "./components/Dropdown/Dropdown";
|
|
14
|
+
export { DatePicker2 } from "./components/DatePicker2/DatePicker2";
|
|
15
|
+
export type { DatePicker2Props, DateValue } from "./components/DatePicker2/DatePicker2";
|
|
16
|
+
export { DatePicker } from "./components/DatePicker/DatePicker";
|
|
17
|
+
export type { DatePickerProps, DatePickerValue } from "./components/DatePicker/DatePicker";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "./common.css";
|
|
2
|
+
export { Button } from "./components/Button/Button";
|
|
3
|
+
export { Modal } from "./components/Modal/Modal";
|
|
4
|
+
export { Input } from "./components/Input/Input";
|
|
5
|
+
export { Alert } from "./components/Alert/Alert";
|
|
6
|
+
export { PhoneInput } from "./components/PhoneInput/PhoneInput";
|
|
7
|
+
export { Dropdown } from "./components/Dropdown/Dropdown";
|
|
8
|
+
export { DatePicker2 } from "./components/DatePicker2/DatePicker2";
|
|
9
|
+
export { DatePicker } from "./components/DatePicker/DatePicker";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../src/declarations.d.ts","../src/index.ts","../src/components/alert/alert.tsx","../src/components/button/button.tsx","../src/components/datepicker/datepicker.tsx","../src/components/datepicker2/datepicker2.tsx","../src/components/dropdown/dropdown.tsx","../src/components/input/input.tsx","../src/components/modal/modal.tsx","../src/components/phoneinput/phoneinput.tsx"],"version":"5.9.3"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ml-ui-lib",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"author": "Kenneth James B. Simbulan",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"watch": "tsc --watch",
|
|
14
|
+
"dev": "npm run build -- --watch"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"react": ">=17",
|
|
18
|
+
"react-dom": ">=17"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/react": "^18.0.0",
|
|
22
|
+
"@types/react-dom": "^18.0.0",
|
|
23
|
+
"typescript": "^5.9.3"
|
|
24
|
+
}
|
|
25
|
+
}
|