mirror of https://github.com/acid-info/lsd.git
fix: fix multiple issues and update styles
This commit is contained in:
parent
d78958b9f8
commit
261b96f3bf
|
@ -117,7 +117,7 @@ export const CalendarStyles = css`
|
|||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 0;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
||||
.${calendarClasses.disabled} {
|
||||
|
|
|
@ -22,6 +22,9 @@ export type CalendarProps = Omit<
|
|||
handleRef: React.RefObject<HTMLElement>
|
||||
size?: 'large' | 'medium' | 'small'
|
||||
onClose?: () => void
|
||||
onCalendarClickaway?: (event: Event) => void
|
||||
minDate?: Date
|
||||
maxDate?: Date
|
||||
}
|
||||
|
||||
export const Calendar: React.FC<CalendarProps> & {
|
||||
|
@ -34,17 +37,28 @@ export const Calendar: React.FC<CalendarProps> & {
|
|||
disabled = false,
|
||||
onChange,
|
||||
onClose,
|
||||
onCalendarClickaway,
|
||||
// minDate and maxDate are necessary because onDateFocus freaks out with small/large date values.
|
||||
minDate = new Date(1900, 0, 1),
|
||||
maxDate = new Date(2100, 0, 1),
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [style, setStyle] = useState<React.CSSProperties>({})
|
||||
const [value, setValue] = useState<Date | null>(
|
||||
valueProp ? safeConvertDateToString(valueProp).date : null,
|
||||
valueProp
|
||||
? safeConvertDateToString(valueProp, minDate, maxDate).date
|
||||
: null,
|
||||
)
|
||||
const isOpenControlled = typeof open !== 'undefined'
|
||||
|
||||
useClickAway(ref, (event) => {
|
||||
if (!open || event.composedPath().includes(handleRef.current!)) return
|
||||
if (!open) return
|
||||
|
||||
onCalendarClickaway && onCalendarClickaway(event)
|
||||
|
||||
if (isOpenControlled) return
|
||||
|
||||
onClose && onClose()
|
||||
})
|
||||
|
@ -84,7 +98,7 @@ export const Calendar: React.FC<CalendarProps> & {
|
|||
useEffect(() => {
|
||||
if (typeof valueProp === 'undefined') return
|
||||
|
||||
const { date } = safeConvertDateToString(valueProp)
|
||||
const { date } = safeConvertDateToString(valueProp, minDate, maxDate)
|
||||
setValue(date)
|
||||
}, [valueProp])
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ export const Day = ({ day, date, disabled = false }: DayProps) => {
|
|||
<Typography variant="label2">{parseInt(day, 10)}</Typography>
|
||||
{isToday && (
|
||||
<Typography variant="label2" className={calendarClasses.todayIndicator}>
|
||||
■
|
||||
▬
|
||||
</Typography>
|
||||
)}
|
||||
</button>
|
||||
|
|
|
@ -4,6 +4,7 @@ export const dateFieldClasses = {
|
|||
|
||||
inputContainer: `lsd-date-field__input-container`,
|
||||
input: `lsd-date-field__input-container__input`,
|
||||
inputFilled: `lsd-date-field__input-container__input--filled`,
|
||||
icon: `lsd-date-field__input-container__icon`,
|
||||
iconButton: `lsd-date-field__input-container__icon-button`,
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ export const DateFieldStyles = css`
|
|||
color: rgb(var(--lsd-text-primary));
|
||||
background: none;
|
||||
width: 100%;
|
||||
opacity: 0.4;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.${dateFieldClasses.input}::-webkit-inner-spin-button,
|
||||
|
@ -116,11 +118,9 @@ export const DateFieldStyles = css`
|
|||
}
|
||||
}
|
||||
|
||||
.${dateFieldClasses.input}::-webkit-datetime-edit-month-field:focus,
|
||||
.${dateFieldClasses.input}::-webkit-datetime-edit-day-field:focus,
|
||||
.${dateFieldClasses.input}::-webkit-datetime-edit-year-field:focus {
|
||||
color: rgb(var(--lsd-text-primary));
|
||||
opacity: 0.4;
|
||||
.${dateFieldClasses.input}:invalid, .${dateFieldClasses.inputFilled} {
|
||||
color: rgb(var(--lsd-border-primary));
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.${dateFieldClasses.error}
|
||||
|
|
|
@ -24,6 +24,7 @@ export type DateFieldProps = Omit<
|
|||
onIconClick?: () => void
|
||||
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
|
||||
variant?: 'outlined' | 'outlined-bottom'
|
||||
calendarIconRef?: React.RefObject<HTMLSpanElement>
|
||||
}
|
||||
|
||||
export const DateField: React.FC<DateFieldProps> & {
|
||||
|
@ -48,7 +49,12 @@ export const DateField: React.FC<DateFieldProps> & {
|
|||
...props
|
||||
}) => {
|
||||
const ref = useRef<HTMLInputElement>(null)
|
||||
const input = useInput({ defaultValue, value, onChange, ref })
|
||||
const input = useInput({
|
||||
defaultValue,
|
||||
value,
|
||||
onChange,
|
||||
ref,
|
||||
})
|
||||
|
||||
const onCancel = () => input.setValue('')
|
||||
|
||||
|
@ -90,15 +96,20 @@ export const DateField: React.FC<DateFieldProps> & {
|
|||
placeholder={placeholder}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
value={input.value}
|
||||
value={input.value || ''}
|
||||
onChange={input.onChange}
|
||||
className={clsx(inputProps.className, dateFieldClasses.input)}
|
||||
className={clsx(
|
||||
inputProps.className,
|
||||
dateFieldClasses.input,
|
||||
input.filled && dateFieldClasses.inputFilled,
|
||||
)}
|
||||
max={inputProps.max || '9999-12-31'}
|
||||
/>
|
||||
{icon ? (
|
||||
<span
|
||||
className={dateFieldClasses.icon}
|
||||
onClick={() => !disabled && onIconClick && onIconClick()}
|
||||
ref={props.calendarIconRef}
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
|
|
|
@ -43,7 +43,9 @@ export const DatePicker: React.FC<DatePickerProps> & {
|
|||
...props
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const calendarIconRef = useRef<HTMLSpanElement>(null)
|
||||
const [openCalendar, setOpenCalendar] = useState(false)
|
||||
const isControlled = typeof valueProp !== 'undefined'
|
||||
|
||||
const input = useInput({
|
||||
value: valueProp,
|
||||
|
@ -77,8 +79,10 @@ export const DatePicker: React.FC<DatePickerProps> & {
|
|||
variant={variant}
|
||||
icon={withCalendar && <CalendarIcon color="primary" />}
|
||||
onIconClick={() => setOpenCalendar((prev) => !prev)}
|
||||
value={input.value}
|
||||
// The DateField component is only controlled when the value prop is provided OR the calendar is open.
|
||||
value={isControlled || openCalendar ? input.value : undefined}
|
||||
onChange={input.onChange}
|
||||
calendarIconRef={calendarIconRef}
|
||||
{...props}
|
||||
>
|
||||
<Portal id="calendar">
|
||||
|
@ -86,7 +90,18 @@ export const DatePicker: React.FC<DatePickerProps> & {
|
|||
<Calendar
|
||||
onChange={(date) => handleDateChange(date)}
|
||||
open={openCalendar}
|
||||
onClose={() => setOpenCalendar(false)}
|
||||
onCalendarClickaway={(event) => {
|
||||
// If the calendar icon was clicked, return and don't close the calendar here.
|
||||
// Let the onIconClick above handle the closing.
|
||||
if (
|
||||
calendarIconRef.current &&
|
||||
event?.composedPath().includes(calendarIconRef.current)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
setOpenCalendar(false)
|
||||
}}
|
||||
handleRef={ref}
|
||||
value={input.value}
|
||||
disabled={props.disabled}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
export const safeConvertDateToString = (value: string) => {
|
||||
export const safeConvertDateToString = (
|
||||
value: string,
|
||||
minDate: Date,
|
||||
maxDate: Date,
|
||||
) => {
|
||||
const date = new Date(value ?? undefined)
|
||||
const isValid = !Number.isNaN(+date)
|
||||
const isValid = !Number.isNaN(+date) && date >= minDate && date <= maxDate
|
||||
|
||||
return {
|
||||
isValid,
|
||||
date: isValid ? date : new Date(),
|
||||
}
|
||||
}
|
||||
|
||||
export const removeDateTimezoneOffset = (date: Date) =>
|
||||
new Date(+date - date.getTimezoneOffset() * 60 * 1000)
|
||||
|
||||
|
|
Loading…
Reference in New Issue