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