feat: interactive date range
parent
81fd7dec58
commit
22a02950c3
@ -0,0 +1,125 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { DateRange } from '../components/calendar/DateRange';
|
||||||
|
import { Controls } from '../components/calendar/Controls';
|
||||||
|
import { HeaderStyle, DaySize, MonthCutoffType } from '../types/calendar';
|
||||||
|
import { format, startOfDay } from 'date-fns';
|
||||||
|
import styles from './Examples.module.scss';
|
||||||
|
|
||||||
|
export const InteractiveDateRange: React.FC = () => {
|
||||||
|
const [dayHeaderStyle, setDayHeaderStyle] = useState<HeaderStyle>('tiny');
|
||||||
|
const [size, setSize] = useState<DaySize>('l');
|
||||||
|
const [fontProportion, setFontProportion] = useState<number>(100);
|
||||||
|
const [included, setIncluded] = useState<boolean>(true);
|
||||||
|
const [selected, setSelected] = useState<boolean>(false);
|
||||||
|
const [monthCutoff, setMonthCutoff] = useState<MonthCutoffType>(undefined);
|
||||||
|
const [activeDates, setActiveDates] = useState<Date[]>([]);
|
||||||
|
const [lastClicked, setLastClicked] = useState<string>('');
|
||||||
|
|
||||||
|
const fromDate = new Date(2025, 0, 10); // January 10, 2025
|
||||||
|
const toDate = new Date(2025, 0, 25); // January 25, 2025
|
||||||
|
|
||||||
|
const handleDateClick = (date: Date) => {
|
||||||
|
const dateString = format(date, 'MMMM d, yyyy');
|
||||||
|
setLastClicked(dateString);
|
||||||
|
|
||||||
|
// Toggle the date in activeDates
|
||||||
|
setActiveDates(prev => {
|
||||||
|
const dateTime = startOfDay(date).getTime();
|
||||||
|
const existingIndex = prev.findIndex(d =>
|
||||||
|
startOfDay(d).getTime() === dateTime
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingIndex >= 0) {
|
||||||
|
// Remove if already active
|
||||||
|
return prev.filter((_, index) => index !== existingIndex);
|
||||||
|
} else {
|
||||||
|
// Add if not active
|
||||||
|
return [...prev, date];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show alert
|
||||||
|
alert(`Clicked: ${dateString}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.section}>
|
||||||
|
<h2 className={styles.sectionTitle}>Interactive Date Range</h2>
|
||||||
|
<p className={styles.sectionDescription}>
|
||||||
|
Click on dates to toggle their active state. Active dates have inverted colors.
|
||||||
|
</p>
|
||||||
|
<Controls
|
||||||
|
headerStyle={dayHeaderStyle}
|
||||||
|
monthCutoff={monthCutoff}
|
||||||
|
size={size}
|
||||||
|
fontProportion={fontProportion}
|
||||||
|
onHeaderStyleChange={setDayHeaderStyle}
|
||||||
|
onMonthCutoffChange={setMonthCutoff}
|
||||||
|
onSizeChange={setSize}
|
||||||
|
onFontProportionChange={setFontProportion}
|
||||||
|
/>
|
||||||
|
<div className={styles.controlRow}>
|
||||||
|
<label className={styles.control}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={included}
|
||||||
|
onChange={(e) => setIncluded(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>Include start/end dates</span>
|
||||||
|
</label>
|
||||||
|
<label className={styles.control}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={selected}
|
||||||
|
onChange={(e) => setSelected(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>Show as selected range</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className={styles.info}>
|
||||||
|
<p>Last clicked: {lastClicked || 'None'}</p>
|
||||||
|
<p>Active dates: {activeDates.length > 0
|
||||||
|
? activeDates.map(d => format(d, 'MMM d')).join(', ')
|
||||||
|
: 'None'}</p>
|
||||||
|
</div>
|
||||||
|
<div className={styles.demoContainer}>
|
||||||
|
<DateRange
|
||||||
|
from={fromDate}
|
||||||
|
to={toDate}
|
||||||
|
included={included}
|
||||||
|
selected={selected}
|
||||||
|
headerStyle={dayHeaderStyle}
|
||||||
|
weekendDays={[6, 0]}
|
||||||
|
size={size}
|
||||||
|
fontProportion={fontProportion}
|
||||||
|
magnify={true}
|
||||||
|
onDateClick={handleDateClick}
|
||||||
|
activeDates={activeDates}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.codeExample}>
|
||||||
|
<pre>{`<DateRange
|
||||||
|
from={new Date(2025, 0, 10)}
|
||||||
|
to={new Date(2025, 0, 25)}
|
||||||
|
included={${included}}
|
||||||
|
selected={${selected}}
|
||||||
|
headerStyle="${dayHeaderStyle}"
|
||||||
|
size="${size}"
|
||||||
|
fontProportion={${fontProportion}}
|
||||||
|
magnify={true}
|
||||||
|
onDateClick={(date) => {
|
||||||
|
alert(\`Clicked: \${format(date, 'MMMM d, yyyy')}\`);
|
||||||
|
// Toggle active state
|
||||||
|
setActiveDates(prev => {
|
||||||
|
const exists = prev.some(d => d.getTime() === date.getTime());
|
||||||
|
return exists
|
||||||
|
? prev.filter(d => d.getTime() !== date.getTime())
|
||||||
|
: [...prev, date];
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
activeDates={activeDates}
|
||||||
|
/>`}</pre>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue