feat: add color customization options to SingleDatePicker and implement unique ID generation for styling

This commit is contained in:
Astrian Zheng 2025-02-20 09:47:54 +11:00
parent 9b420232a3
commit a7d9c62fd5
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
5 changed files with 82 additions and 11 deletions

View File

@ -1,7 +1,7 @@
import LeftArrowIcon from '@/assets/icons/left-arrow.svg' import LeftArrowIcon from '@/assets/icons/left-arrow.svg'
import RightArrowIcon from '@/assets/icons/right-arrow.svg' import RightArrowIcon from '@/assets/icons/right-arrow.svg'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { getCalendarDates, getL10Weekday } from '../utils' import { getCalendarDates, getL10Weekday, generateUniqueId, applyColor } from '../utils'
interface Props { interface Props {
/** /**
@ -39,6 +39,36 @@ interface Props {
* @default undefined * @default undefined
*/ */
onClose?: () => void onClose?: () => void
/**
* The main color of the panel, including the text color and the border color.
*@default '#000000'
*/
mainColor?: string
/**
* The accent color of the panel, including the background color of the selected date.
*@default '#000000'
*/
accentColor?: string
/**
* The reversed color of the panel, including the text color of the selected date.
*@default '#ffffff'
*/
reversedColor?: string
/**
* The hover color of the panel, including the hover background color of the date.
*@default '#00000017'
*/
hoverColor?: string
/**
* The border color of the panel, including the divider color between the header and the body.
*@default '#e0e0e0'
*/
borderColor?: string
} }
/** /**
@ -48,13 +78,14 @@ interface Props {
* *
* @param {Props} props * @param {Props} props
*/ */
export default ({ value, onSelect, localization, onClose }: Props) => { export default ({ value, onSelect, localization, onClose, mainColor = '#000000', accentColor = '#000000', reversedColor = '#ffffff', hoverColor = '#00000017', borderColor = '#e0e0e0' }: Props) => {
const [currentMonth, setCurrentMonth] = useState(new Date().getMonth()) const [currentMonth, setCurrentMonth] = useState(new Date().getMonth())
const [currentYear, setCurrentYear] = useState(new Date().getFullYear()) const [currentYear, setCurrentYear] = useState(new Date().getFullYear())
const [selectedDate, setSelectedDate] = useState(new Date()) const [selectedDate, setSelectedDate] = useState(new Date())
const [dates, setDates] = useState<Date[]>([]) const [dates, setDates] = useState<Date[]>([])
const [l10nDays, setL10nDays] = useState<string[]>([]) const [l10nDays, setL10nDays] = useState<string[]>([])
const [selectMonth, setSelectMonth] = useState(false) const [selectMonth, setSelectMonth] = useState(false)
const uniqueId = generateUniqueId()
useEffect(() => { useEffect(() => {
setDates(getCalendarDates(currentMonth, currentYear)) setDates(getCalendarDates(currentMonth, currentYear))
@ -73,6 +104,26 @@ export default ({ value, onSelect, localization, onClose }: Props) => {
setL10nDays(getL10Weekday(i18n)) setL10nDays(getL10Weekday(i18n))
}, [localization]) }, [localization])
useEffect(() => {
applyColor(uniqueId, {
mainColor: mainColor,
accentColor: accentColor,
reversedColor: reversedColor,
hoverColor: hoverColor,
borderColor: borderColor
})
} , [mainColor, accentColor, reversedColor, hoverColor, borderColor])
useEffect(() => {
applyColor(uniqueId, {
mainColor: mainColor,
accentColor: accentColor,
reversedColor: reversedColor,
hoverColor: hoverColor,
borderColor: borderColor
})
}, [])
function selectDate(date: Date) { function selectDate(date: Date) {
setSelectedDate(date) setSelectedDate(date)
onSelect?.({ onSelect?.({
@ -99,7 +150,7 @@ export default ({ value, onSelect, localization, onClose }: Props) => {
} }
if (selectMonth) return ( if (selectMonth) return (
<div className='datenel-component' role="dialog" aria-label="Date selection panel, you are now at month and year quick-select"> <div className='datenel-component' role="dialog" aria-label="Date selection panel, you are now at month and year quick-select" id={`__datenel-${uniqueId}`}>
<div className='header'> <div className='header'>
<button className='stepper' onClick={() => { <button className='stepper' onClick={() => {
if (currentYear === 0) return if (currentYear === 0) return
@ -127,7 +178,7 @@ export default ({ value, onSelect, localization, onClose }: Props) => {
</div> </div>
) )
else return ( else return (
<div className='datenel-component' role="dialog" aria-label="Date selection panel"> <div className='datenel-component' role="dialog" aria-label="Date selection panel" id={`__datenel-${uniqueId}`}>
<div className='header'> <div className='header'>
<button className='stepper' onClick={skipToLastMonth} aria-label={`Go to last month, ${new Date(currentYear, currentMonth - 1).toLocaleString(localization || navigator.language, { month: 'long' })}`}><img src={LeftArrowIcon} /></button> <button className='stepper' onClick={skipToLastMonth} aria-label={`Go to last month, ${new Date(currentYear, currentMonth - 1).toLocaleString(localization || navigator.language, { month: 'long' })}`}><img src={LeftArrowIcon} /></button>
<button className='indicator' onClick={() => setSelectMonth(true)} aria-label={`You are now at ${new Date(currentYear, currentMonth).toLocaleString(localization || navigator.language, { month: 'long', year: 'numeric' })}. Click here to quick-select month or year.`}> <button className='indicator' onClick={() => setSelectMonth(true)} aria-label={`You are now at ${new Date(currentYear, currentMonth).toLocaleString(localization || navigator.language, { month: 'long', year: 'numeric' })}. Click here to quick-select month or year.`}>

View File

@ -1,10 +1,4 @@
.datenel-component { .datenel-component {
--main-color: #000000;
--accent-color: #000000;
--reversed-color: #ffffff;
--hover-color: #00000017;
--border-color: #e0e0e0;
user-select: none; user-select: none;
color: var(--main-color); color: var(--main-color);

21
src/utils/applyColor.ts Normal file
View File

@ -0,0 +1,21 @@
export default (id: string, colorValues: {
mainColor: string
accentColor: string
reversedColor: string
hoverColor: string
borderColor: string
} = {
mainColor: '#000000',
accentColor: '#000000',
reversedColor: '#ffffff',
hoverColor: '#00000017',
borderColor: '#e0e0e0'
}) => {
const element = document.querySelector(`#__datenel-${id}`) as HTMLDivElement
if (!element) return
element.style.setProperty(`--main-color`, colorValues.mainColor)
element.style.setProperty(`--accent-color`, colorValues.accentColor)
element.style.setProperty(`--reversed-color`, colorValues.reversedColor)
element.style.setProperty(`--hover-color`, colorValues.hoverColor)
element.style.setProperty(`--border-color`, colorValues.borderColor)
}

View File

@ -0,0 +1,3 @@
export default (): string => {
return Math.random().toString(36).split('.')[1]
}

View File

@ -1,2 +1,4 @@
export { default as getCalendarDates } from './getCalendarDates' export { default as getCalendarDates } from './getCalendarDates'
export { default as getL10Weekday } from './getL10Weekday' export { default as getL10Weekday } from './getL10Weekday'
export { default as generateUniqueId } from './generateUniqueId'
export { default as applyColor } from './applyColor'