feat: today special

master
Guillermo Pages 4 months ago
parent 88955f095e
commit 8611d080ae

@ -2,10 +2,12 @@
A modern, flexible, and highly customizable calendar component library for React with TypeScript support. A modern, flexible, and highly customizable calendar component library for React with TypeScript support.
## 🆕 Version 1.1.0 Features ## 🆕 Version 1.3.0 Features
- 📅 **Today State in Color Schemes**: Define custom colors for today's date through color schemes
- ✏️ **Header Text Transform**: Custom function to transform day name display (e.g., `dayName => dayName.slice(0, 2)`)
- 🌍 **International Locale Support**: Full internationalization with 50+ languages via date-fns - 🌍 **International Locale Support**: Full internationalization with 50+ languages via date-fns
- 🎨 **Comprehensive Color Schemes**: Complete control over colors for every state (default, selecting, selected, range start/end/mid, active) and day type (weekday/weekend) - 🎨 **Comprehensive Color Schemes**: Complete control over colors for every state (default, today, selecting, selected, range start/end/mid, active) and day type (weekday/weekend)
- 🎯 **Enhanced Weekend Support**: Distinct colors for weekends in all selection states - 🎯 **Enhanced Weekend Support**: Distinct colors for weekends in all selection states
📖 **[View the complete Usage Guide](./USAGE_GUIDE.md)** for detailed examples of the new features! 📖 **[View the complete Usage Guide](./USAGE_GUIDE.md)** for detailed examples of the new features!

@ -1,5 +1,47 @@
# Calendar Component Usage Guide # Calendar Component Usage Guide
## ✏️ Header Text Transform (v1.2.0+)
Customize how day names are displayed with a transform function:
```tsx
import { Month } from 'react-calendario';
// Example 1: Two-letter abbreviations
<Month
date={new Date()}
headerStyle="compacted" // Shows "MON", "TUE", etc.
headerTextTransform={(dayName) => dayName.slice(0, 2)} // Returns "MO", "TU", etc.
/>
// Example 2: Custom mapping
const customDayNames = (dayName: string) => {
const map: Record<string, string> = {
'MON': 'Mo', 'TUE': 'Tu', 'WED': 'We',
'THU': 'Th', 'FRI': 'Fr', 'SAT': 'Sa', 'SUN': 'Su'
};
return map[dayName] || dayName;
};
<Month
date={new Date()}
headerStyle="compacted"
headerTextTransform={customDayNames}
/>
// Example 3: Lowercase
<Month
date={new Date()}
headerStyle="tiny"
headerTextTransform={(dayName) => dayName.toLowerCase()}
/>
```
The `headerTextTransform` function:
- Receives the day name after `headerStyle` processing
- Can return any string for display
- Works with all components: Year, Month, Week, DateRange, Day
## 🎨 Custom Color Schemes ## 🎨 Custom Color Schemes
### Basic Active Colors (Simple) ### Basic Active Colors (Simple)
@ -29,6 +71,23 @@ Full control over colors for every state and day type:
import { Year, ColorScheme } from 'react-calendario'; import { Year, ColorScheme } from 'react-calendario';
const colorScheme: ColorScheme = [ const colorScheme: ColorScheme = [
// Today's date colors (highest priority)
{
type: 'weekday',
state: 'today', // Today if it's a weekday
colors: {
header: { backgroundColor: '#ffd700', color: '#000000' },
content: { backgroundColor: '#fff9e6', color: '#000000' }
}
},
{
type: 'weekend',
state: 'today', // Today if it's a weekend
colors: {
header: { backgroundColor: '#ffb347', color: '#000000' },
content: { backgroundColor: '#fff5e6', color: '#000000' }
}
},
// Weekday colors // Weekday colors
{ {
type: 'weekday', type: 'weekday',
@ -83,6 +142,7 @@ const colorScheme: ColorScheme = [
#### Available States: #### Available States:
- `default` - Normal day appearance - `default` - Normal day appearance
- `today` - Today's date (automatically detected, highest priority)
- `selected` - Day is part of a completed selection (deprecated, use `rangeMid`) - `selected` - Day is part of a completed selection (deprecated, use `rangeMid`)
- `selecting` - Day is being hovered during selection (important for weekends!) - `selecting` - Day is being hovered during selection (important for weekends!)
- `rangeStart` - First day of a range - `rangeStart` - First day of a range

@ -1,6 +1,6 @@
{ {
"name": "react-calendario", "name": "react-calendario",
"version": "1.1.1", "version": "1.3.1",
"description": "A modern, flexible calendar component for React with TypeScript support", "description": "A modern, flexible calendar component for React with TypeScript support",
"type": "module", "type": "module",
"main": "dist/index.umd.js", "main": "dist/index.umd.js",

@ -21,6 +21,7 @@ interface DateRangeProps {
activeColors?: ActiveColors; activeColors?: ActiveColors;
colorScheme?: ColorScheme; colorScheme?: ColorScheme;
locale?: Locale; locale?: Locale;
headerTextTransform?: (dayName: string) => string;
} }
export const DateRange: React.FC<DateRangeProps> = ({ export const DateRange: React.FC<DateRangeProps> = ({
@ -37,7 +38,8 @@ export const DateRange: React.FC<DateRangeProps> = ({
activeDates = [], activeDates = [],
activeColors, activeColors,
colorScheme, colorScheme,
locale locale,
headerTextTransform
}) => { }) => {
const startDate = startOfDay(from); const startDate = startOfDay(from);
const endDate = startOfDay(to); const endDate = startOfDay(to);
@ -95,6 +97,7 @@ export const DateRange: React.FC<DateRangeProps> = ({
activeColors={activeColors} activeColors={activeColors}
colorScheme={colorScheme} colorScheme={colorScheme}
locale={locale} locale={locale}
headerTextTransform={headerTextTransform}
/> />
</div> </div>
); );

@ -190,6 +190,12 @@
} }
// end implicit (midrange) { // end implicit (midrange) {
// today state - no default styling, handled by color scheme
&.Day__Container--today {
// Today state can combine with other states
// Styling is handled through the color scheme
}
// active state - inverted colors // active state - inverted colors
&.Day__Container--active { &.Day__Container--active {
background: colors.$day-header-defaultmode-defaultstate-background-color; background: colors.$day-header-defaultmode-defaultstate-background-color;

@ -19,7 +19,8 @@ export const Day: React.FC<DayProps> = ({
magnify = false, magnify = false,
activeColors, activeColors,
colorScheme, colorScheme,
locale locale,
headerTextTransform
}) => { }) => {
const isInteractive = Boolean(onSelect || onHover); const isInteractive = Boolean(onSelect || onHover);
@ -45,6 +46,7 @@ export const Day: React.FC<DayProps> = ({
[styles['Day__Container--rowStart']]: variations.includes('rowStart'), [styles['Day__Container--rowStart']]: variations.includes('rowStart'),
[styles['Day__Container--rowEnd']]: variations.includes('rowEnd'), [styles['Day__Container--rowEnd']]: variations.includes('rowEnd'),
[styles['Day__Container--active']]: variations.includes('active'), [styles['Day__Container--active']]: variations.includes('active'),
[styles['Day__Container--today']]: variations.includes('today'),
[styles['magnify']]: magnify && (variations.includes('selected') || variations.includes('selecting')) [styles['magnify']]: magnify && (variations.includes('selected') || variations.includes('selecting'))
}, },
styles[`Day--${headerStyle}`], styles[`Day--${headerStyle}`],
@ -103,7 +105,7 @@ export const Day: React.FC<DayProps> = ({
{headerStyle !== 'none' && ( {headerStyle !== 'none' && (
<div className={headerClasses} style={headerCustomStyles}> <div className={headerClasses} style={headerCustomStyles}>
<div className={styles.Day__HeaderText}> <div className={styles.Day__HeaderText}>
{getDayLabel(date, headerStyle, locale)} {getDayLabel(date, headerStyle, locale, headerTextTransform)}
</div> </div>
</div> </div>
)} )}

@ -22,7 +22,8 @@ export const Month: React.FC<MonthProps> = ({
activeColors, activeColors,
activeDates, activeDates,
colorScheme, colorScheme,
locale = enUS locale = enUS,
headerTextTransform
}) => { }) => {
const monthStart = startOfMonth(date); const monthStart = startOfMonth(date);
const start = startOfWeek(monthStart, { weekStartsOn: 1 }); const start = startOfWeek(monthStart, { weekStartsOn: 1 });
@ -54,6 +55,7 @@ export const Month: React.FC<MonthProps> = ({
activeDates={activeDates} activeDates={activeDates}
colorScheme={colorScheme} colorScheme={colorScheme}
locale={locale} locale={locale}
headerTextTransform={headerTextTransform}
/> />
); );
current = addWeeks(current, 1); current = addWeeks(current, 1);

@ -21,7 +21,8 @@ export const Week: React.FC<WeekProps> = ({
activeColors, activeColors,
activeDates = [], activeDates = [],
colorScheme, colorScheme,
locale locale,
headerTextTransform
}) => { }) => {
const allDays = Array.from({ length: 7 }, (_, i) => { const allDays = Array.from({ length: 7 }, (_, i) => {
const date = addDays(startDate, i); const date = addDays(startDate, i);
@ -65,6 +66,7 @@ export const Week: React.FC<WeekProps> = ({
activeColors={activeColors} activeColors={activeColors}
colorScheme={colorScheme} colorScheme={colorScheme}
locale={locale} locale={locale}
headerTextTransform={headerTextTransform}
/> />
</div> </div>
); );
@ -84,6 +86,7 @@ export const Week: React.FC<WeekProps> = ({
activeColors={activeColors} activeColors={activeColors}
colorScheme={colorScheme} colorScheme={colorScheme}
locale={locale} locale={locale}
headerTextTransform={headerTextTransform}
/> />
</div> </div>
); );

@ -18,7 +18,8 @@ export const Year: React.FC<YearProps> = ({
activeColors, activeColors,
activeDates, activeDates,
colorScheme, colorScheme,
locale locale,
headerTextTransform
}) => { }) => {
const months = Array.from({ length: 12 }, (_, index) => { const months = Array.from({ length: 12 }, (_, index) => {
const monthDate = new Date(year, index, 1); const monthDate = new Date(year, index, 1);
@ -41,6 +42,7 @@ export const Year: React.FC<YearProps> = ({
activeDates={activeDates} activeDates={activeDates}
colorScheme={colorScheme} colorScheme={colorScheme}
locale={locale} locale={locale}
headerTextTransform={headerTextTransform}
/> />
); );
}); });

@ -30,15 +30,18 @@ export const getMinWidthByHeaderStyle = (headerStyle: HeaderStyle) => {
return `min-width: ${baseWidths[headerStyle]};`; return `min-width: ${baseWidths[headerStyle]};`;
}; };
export const getDayLabel = (date: Date, headerStyle: HeaderStyle, locale: Locale = enUS): string => { export const getDayLabel = (date: Date, headerStyle: HeaderStyle, locale: Locale = enUS, headerTextTransform?: (dayName: string) => string): string => {
const day = format(date, 'EEEE', { locale }); const day = format(date, 'EEEE', { locale });
let result: string;
switch (headerStyle) { switch (headerStyle) {
case 'expanded': case 'expanded':
return day.toUpperCase(); result = day.toUpperCase();
break;
case 'compacted': case 'compacted':
// Use EEE format for proper 3-letter abbreviation in the locale // Use EEE format for proper 3-letter abbreviation in the locale
return format(date, 'EEE', { locale }).toUpperCase(); result = format(date, 'EEE', { locale }).toUpperCase();
break;
case 'tiny': case 'tiny':
// Use EEEEE format for single letter abbreviation when available // Use EEEEE format for single letter abbreviation when available
// Fallback to first letter for better locale support // Fallback to first letter for better locale support
@ -47,14 +50,29 @@ export const getDayLabel = (date: Date, headerStyle: HeaderStyle, locale: Locale
// For English, handle special cases (Thursday/Tuesday, Saturday/Sunday) // For English, handle special cases (Thursday/Tuesday, Saturday/Sunday)
if (locale.code === 'en-US' || locale.code === 'en') { if (locale.code === 'en-US' || locale.code === 'en') {
const dayName = format(date, 'EEEE', { locale }); const dayName = format(date, 'EEEE', { locale });
if (dayName === 'Thursday') return 'T'; if (dayName === 'Thursday') {
if (dayName === 'Tuesday') return 't'; result = 'T';
if (dayName === 'Saturday') return 's'; } else if (dayName === 'Tuesday') {
if (dayName === 'Sunday') return 'S'; result = 't';
} else if (dayName === 'Saturday') {
result = 's';
} else if (dayName === 'Sunday') {
result = 'S';
} else {
result = singleLetter.toUpperCase();
}
} else {
result = singleLetter.toUpperCase();
} }
break;
return singleLetter.toUpperCase();
default: default:
return day; result = day;
}
// Apply custom transform if provided
if (headerTextTransform) {
return headerTextTransform(result);
} }
return result;
}; };

@ -1,10 +1,14 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { DateRange } from '../components/calendar/DateRange'; import { DateRange } from '../components/calendar/DateRange';
import { ActiveColors } from '../types/calendar'; import { ActiveColors } from '../types/calendar';
import { format, startOfDay } from 'date-fns';
import styles from './Examples.module.scss'; import styles from './Examples.module.scss';
export const DateRangeWithActiveColors: React.FC = () => { export const DateRangeWithActiveColors: React.FC = () => {
const [colorScheme, setColorScheme] = useState<'default' | 'green' | 'purple' | 'orange'>('default'); const [colorScheme, setColorScheme] = useState<'default' | 'green' | 'purple' | 'orange'>('default');
const [activeDates, setActiveDates] = useState<Date[]>([]);
const [lastClicked, setLastClicked] = useState<string>('');
const [headerMode, setHeaderMode] = useState<'normal' | 'short' | 'twoLetter'>('normal');
const fromDate = new Date(2025, 0, 15); // January 15, 2025 const fromDate = new Date(2025, 0, 15); // January 15, 2025
const toDate = new Date(2025, 0, 20); // January 20, 2025 const toDate = new Date(2025, 0, 20); // January 20, 2025
@ -31,11 +35,62 @@ export const DateRangeWithActiveColors: React.FC = () => {
} }
}; };
const handleDateClick = (date: Date) => {
const dateString = format(date, 'MMMM d, yyyy');
setLastClicked(dateString);
setActiveDates(prev => {
const dateTime = startOfDay(date).getTime();
const existingIndex = prev.findIndex(d =>
startOfDay(d).getTime() === dateTime
);
if (existingIndex >= 0) {
return prev.filter((_, index) => index !== existingIndex);
} else {
return [...prev, date];
}
});
};
// Header text transform functions
const headerTransforms = {
normal: undefined,
short: (dayName: string) => dayName.slice(0, 2),
twoLetter: (dayName: string) => {
// Custom logic: Mo, Tu, We, Th, Fr, Sa, Su
const customMap: Record<string, string> = {
'MONDAY': 'Mo',
'TUESDAY': 'Tu',
'WEDNESDAY': 'We',
'THURSDAY': 'Th',
'FRIDAY': 'Fr',
'SATURDAY': 'Sa',
'SUNDAY': 'Su',
'MON': 'Mo',
'TUE': 'Tu',
'WED': 'We',
'THU': 'Th',
'FRI': 'Fr',
'SAT': 'Sa',
'SUN': 'Su',
'M': 'Mo',
'T': 'Tu',
'W': 'We',
't': 'Th',
'F': 'Fr',
's': 'Sa',
'S': 'Su'
};
return customMap[dayName] || dayName.slice(0, 2);
}
};
return ( return (
<section className={styles.section}> <section className={styles.section}>
<h2 className={styles.sectionTitle}>Date Range with Active Colors</h2> <h2 className={styles.sectionTitle}>Date Range with Active Colors & Header Transform</h2>
<p className={styles.sectionDescription}> <p className={styles.sectionDescription}>
Customize the colors of selected date ranges using the activeColors prop. Customize colors and header text display using activeColors and headerTextTransform props.
</p> </p>
<div className={styles.controlRow}> <div className={styles.controlRow}>
@ -52,28 +107,42 @@ export const DateRangeWithActiveColors: React.FC = () => {
<option value="orange">Orange</option> <option value="orange">Orange</option>
</select> </select>
</label> </label>
<label className={styles.control} style={{ marginLeft: '20px' }}>
<strong>Header Transform:</strong>
<select
value={headerMode}
onChange={(e) => setHeaderMode(e.target.value as any)}
style={{ marginLeft: '8px', padding: '4px 8px' }}
>
<option value="normal">Normal (default)</option>
<option value="short">First 2 letters</option>
<option value="twoLetter">Custom 2-letter (Mo, Tu, We...)</option>
</select>
</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 (click dates to toggle)'}</p>
</div> </div>
<div className={styles.demoContainer}> <div className={styles.demoContainer}>
<h3>Before (Default Colors)</h3> <h3>Interactive Date Range with Custom Colors & Headers</h3>
<DateRange
from={fromDate}
to={toDate}
selected={true}
headerStyle="tiny"
size="l"
magnify={true}
/>
<h3 style={{ marginTop: '2rem' }}>After (Custom Active Colors)</h3>
<DateRange <DateRange
from={fromDate} from={fromDate}
to={toDate} to={toDate}
selected={true} selected={true}
headerStyle="tiny" headerStyle="compacted"
size="l" size="l"
fontProportion={100}
magnify={true} magnify={true}
onDateClick={handleDateClick}
activeDates={activeDates}
activeColors={colorSchemes[colorScheme]} activeColors={colorSchemes[colorScheme]}
headerTextTransform={headerTransforms[headerMode]}
/> />
</div> </div>
@ -82,21 +151,35 @@ export const DateRangeWithActiveColors: React.FC = () => {
from={new Date(2025, 0, 15)} from={new Date(2025, 0, 15)}
to={new Date(2025, 0, 20)} to={new Date(2025, 0, 20)}
selected={true} selected={true}
headerStyle="tiny" headerStyle="compacted"
size="l" size="l"
magnify={true}${colorScheme !== 'default' ? ` magnify={true}
onDateClick={handleDateClick}
activeDates={activeDates}${colorScheme !== 'default' ? `
activeColors={{ activeColors={{
headerBg: '${colorSchemes[colorScheme]?.headerBg}', headerBg: '${colorSchemes[colorScheme]?.headerBg}',
headerColor: '${colorSchemes[colorScheme]?.headerColor}', headerColor: '${colorSchemes[colorScheme]?.headerColor}',
contentBg: '${colorSchemes[colorScheme]?.contentBg}', contentBg: '${colorSchemes[colorScheme]?.contentBg}',
contentColor: '${colorSchemes[colorScheme]?.contentColor}' contentColor: '${colorSchemes[colorScheme]?.contentColor}'
}}` : ''} }}` : ''}${headerMode !== 'normal' ? `
headerTextTransform={${headerMode === 'short'
? '(dayName) => dayName.slice(0, 2)'
: '(dayName) => customTwoLetterMap[dayName]'}}` : ''}
/>`}</pre> />`}</pre>
</div> </div>
<div className={styles.info}> <div className={styles.info} style={{ marginTop: '20px', padding: '15px', background: '#f9f9f9', borderRadius: '8px' }}>
<h4>ActiveColors Properties:</h4> <h4 style={{ margin: '0 0 10px 0' }}>📝 New Feature: headerTextTransform</h4>
<ul> <ul style={{ margin: '10px 0', paddingLeft: '20px' }}>
<li>The <code>headerTextTransform</code> prop accepts a function: <code>(dayName: string) => string</code></li>
<li>It receives the day name after headerStyle processing (e.g., "MON" for compacted)</li>
<li>You can return any string to display in the header</li>
<li>Great for custom abbreviations or localization needs</li>
<li>Example: <code>dayName => dayName.slice(0, 2)</code> for 2-letter abbreviations</li>
</ul>
<h4 style={{ margin: '20px 0 10px 0' }}>🎨 ActiveColors Properties:</h4>
<ul style={{ margin: '10px 0', paddingLeft: '20px' }}>
<li><code>headerBg</code>: Background color for the day header</li> <li><code>headerBg</code>: Background color for the day header</li>
<li><code>headerColor</code>: Text color for the day header</li> <li><code>headerColor</code>: Text color for the day header</li>
<li><code>contentBg</code>: Background color for the day content (number)</li> <li><code>contentBg</code>: Background color for the day content (number)</li>

@ -19,8 +19,10 @@ export const InteractiveDateRange: React.FC = () => {
const [useColorScheme, setUseColorScheme] = useState<boolean>(false); const [useColorScheme, setUseColorScheme] = useState<boolean>(false);
const [colorTheme, setColorTheme] = useState<'ocean' | 'sunset' | 'forest'>('ocean'); const [colorTheme, setColorTheme] = useState<'ocean' | 'sunset' | 'forest'>('ocean');
const fromDate = new Date(2025, 0, 10); // January 10, 2025 // Use today's date in the range to showcase the 'today' styling
const toDate = new Date(2025, 0, 25); // January 25, 2025 const today = new Date();
const fromDate = new Date(today.getFullYear(), today.getMonth(), Math.max(1, today.getDate() - 5));
const toDate = new Date(today.getFullYear(), today.getMonth(), Math.min(28, today.getDate() + 10));
// Locale options // Locale options
const locales: Record<string, { locale: Locale; name: string }> = { const locales: Record<string, { locale: Locale; name: string }> = {
@ -34,9 +36,18 @@ export const InteractiveDateRange: React.FC = () => {
zhCN: { locale: zhCN, name: '中文' } zhCN: { locale: zhCN, name: '中文' }
}; };
// Color schemes with proper weekend support // Color schemes with proper weekend and today support
const colorSchemes: Record<string, ColorScheme> = { const colorSchemes: Record<string, ColorScheme> = {
ocean: [ ocean: [
// Today state (highest priority)
{ type: 'weekday', state: 'today', colors: {
header: { backgroundColor: '#ffd700', color: '#000000' },
content: { backgroundColor: '#fff9e6', color: '#000000' }
}},
{ type: 'weekend', state: 'today', colors: {
header: { backgroundColor: '#ffb347', color: '#000000' },
content: { backgroundColor: '#fff5e6', color: '#000000' }
}},
// Weekday states // Weekday states
{ type: 'weekday', state: 'default', colors: { { type: 'weekday', state: 'default', colors: {
header: { backgroundColor: '#006994', color: '#ffffff' }, header: { backgroundColor: '#006994', color: '#ffffff' },
@ -89,6 +100,15 @@ export const InteractiveDateRange: React.FC = () => {
}} }}
], ],
sunset: [ sunset: [
// Today state
{ type: 'weekday', state: 'today', colors: {
header: { backgroundColor: '#ff1744', color: '#ffffff' },
content: { backgroundColor: '#ffebee', color: '#c62828' }
}},
{ type: 'weekend', state: 'today', colors: {
header: { backgroundColor: '#ff6b6b', color: '#ffffff' },
content: { backgroundColor: '#ffe0e0', color: '#d32f2f' }
}},
// Weekday states // Weekday states
{ type: 'weekday', state: 'default', colors: { { type: 'weekday', state: 'default', colors: {
header: { backgroundColor: '#ff6b35', color: '#ffffff' }, header: { backgroundColor: '#ff6b35', color: '#ffffff' },
@ -141,6 +161,15 @@ export const InteractiveDateRange: React.FC = () => {
}} }}
], ],
forest: [ forest: [
// Today state
{ type: 'weekday', state: 'today', colors: {
header: { backgroundColor: '#66bb6a', color: '#ffffff' },
content: { backgroundColor: '#e8f5e9', color: '#2e7d32' }
}},
{ type: 'weekend', state: 'today', colors: {
header: { backgroundColor: '#81c784', color: '#ffffff' },
content: { backgroundColor: '#f1f8e9', color: '#33691e' }
}},
// Weekday states // Weekday states
{ type: 'weekday', state: 'default', colors: { { type: 'weekday', state: 'default', colors: {
header: { backgroundColor: '#2d6a4f', color: '#ffffff' }, header: { backgroundColor: '#2d6a4f', color: '#ffffff' },
@ -325,8 +354,8 @@ export const InteractiveDateRange: React.FC = () => {
</div> </div>
<div className={styles.codeExample}> <div className={styles.codeExample}>
<pre>{`<DateRange <pre>{`<DateRange
from={new Date(2025, 0, 10)} from={fromDate} // Includes today's date
to={new Date(2025, 0, 25)} to={toDate}
included={${included}} included={${included}}
selected={${selected}} selected={${selected}}
headerStyle="${dayHeaderStyle}" headerStyle="${dayHeaderStyle}"
@ -352,13 +381,14 @@ export const InteractiveDateRange: React.FC = () => {
<div className={styles.info} style={{ marginTop: '20px', padding: '15px', background: '#f9f9f9', borderRadius: '8px' }}> <div className={styles.info} style={{ marginTop: '20px', padding: '15px', background: '#f9f9f9', borderRadius: '8px' }}>
<h4 style={{ margin: '0 0 10px 0' }}>🎨 Color Scheme Features:</h4> <h4 style={{ margin: '0 0 10px 0' }}>🎨 Color Scheme Features:</h4>
<ul style={{ margin: '10px 0', paddingLeft: '20px' }}> <ul style={{ margin: '10px 0', paddingLeft: '20px' }}>
<li><strong>📅 Today's Date:</strong> Automatically highlighted with special colors (gold/red/green based on theme)</li>
<li><strong>Weekdays vs Weekends:</strong> Notice the subtle color differences</li> <li><strong>Weekdays vs Weekends:</strong> Notice the subtle color differences</li>
<li><strong>Selecting State:</strong> Hover while range is selected to see the selecting colors</li> <li><strong>Selecting State:</strong> Hover while range is selected to see the selecting colors</li>
<li><strong>Range States:</strong> Start/End dates have stronger colors than middle dates</li> <li><strong>Range States:</strong> Start/End dates have stronger colors than middle dates</li>
<li><strong>Active Dates:</strong> Click to toggle - active dates get special highlighting</li> <li><strong>Active Dates:</strong> Click to toggle - active dates get special highlighting</li>
</ul> </ul>
<p style={{ margin: '10px 0 0 0', fontSize: '0.9em', color: '#666' }}> <p style={{ margin: '10px 0 0 0', fontSize: '0.9em', color: '#666' }}>
Try selecting Saturday and Sunday to see weekend-specific colors during selection! 💡 Today's date has its own distinct styling that works with all themes!
</p> </p>
</div> </div>
)} )}

@ -32,7 +32,8 @@ export type DayState =
| 'rangeStart' | 'rangeStart'
| 'rangeEnd' | 'rangeEnd'
| 'rangeMid' | 'rangeMid'
| 'active'; | 'active'
| 'today';
export type DayType = 'weekday' | 'weekend'; export type DayType = 'weekday' | 'weekend';
@ -55,7 +56,8 @@ export type DayVariation =
| 'selecting' | 'selecting'
| 'rowStart' | 'rowStart'
| 'rowEnd' | 'rowEnd'
| 'active'; | 'active'
| 'today';
export type DaySize = 'xl' | 'l' | 'm' | 's' | 'xs' | 'xxs'; export type DaySize = 'xl' | 'l' | 'm' | 's' | 'xs' | 'xxs';
export interface YearProps { export interface YearProps {
@ -74,6 +76,7 @@ export interface YearProps {
activeDates?: Date[]; activeDates?: Date[];
colorScheme?: ColorScheme; colorScheme?: ColorScheme;
locale?: Locale; locale?: Locale;
headerTextTransform?: (dayName: string) => string;
} }
export interface MonthProps { export interface MonthProps {
@ -93,6 +96,7 @@ export interface MonthProps {
activeDates?: Date[]; activeDates?: Date[];
colorScheme?: ColorScheme; colorScheme?: ColorScheme;
locale?: Locale; locale?: Locale;
headerTextTransform?: (dayName: string) => string;
} }
export interface WeekProps { export interface WeekProps {
@ -111,6 +115,7 @@ export interface WeekProps {
activeDates?: Date[]; activeDates?: Date[];
colorScheme?: ColorScheme; colorScheme?: ColorScheme;
locale?: Locale; locale?: Locale;
headerTextTransform?: (dayName: string) => string;
} }
export interface DayProps { export interface DayProps {
@ -126,4 +131,5 @@ export interface DayProps {
activeColors?: ActiveColors; activeColors?: ActiveColors;
colorScheme?: ColorScheme; colorScheme?: ColorScheme;
locale?: Locale; locale?: Locale;
headerTextTransform?: (dayName: string) => string;
} }

@ -17,7 +17,8 @@ export const getDayType = (date: Date, variations: DayVariation[], weekendDays:
* Maps variations to a DayState for color lookup * Maps variations to a DayState for color lookup
*/ */
export const getDayState = (variations: DayVariation[]): DayState => { export const getDayState = (variations: DayVariation[]): DayState => {
// Priority order for states // Priority order for states (today has highest priority for visibility)
if (variations.includes('today')) return 'today';
if (variations.includes('rangeStart') || variations.includes('rangeEnd')) { if (variations.includes('rangeStart') || variations.includes('rangeEnd')) {
if (variations.includes('rangeStart') && !variations.includes('rangeEnd')) { if (variations.includes('rangeStart') && !variations.includes('rangeEnd')) {
return 'rangeStart'; return 'rangeStart';

@ -1,4 +1,4 @@
import { isSameDay, isWithinInterval, startOfDay } from 'date-fns'; import { isSameDay, isWithinInterval, startOfDay, isToday } from 'date-fns';
import { DateRange, DayVariation } from '../types/calendar'; import { DateRange, DayVariation } from '../types/calendar';
export const getDateVariations = ( export const getDateVariations = (
@ -7,9 +7,17 @@ export const getDateVariations = (
weekendDays: number[] = [], weekendDays: number[] = [],
dayIndex: number = 0 dayIndex: number = 0
): DayVariation[] => { ): DayVariation[] => {
const greyedClasses: DayVariation[] = weekendDays.includes(date.getDay()) const variations: DayVariation[] = [];
? ['greyed']
: []; // Check if it's today
if (isToday(date)) {
variations.push('today');
}
// Check if it's a weekend
if (weekendDays.includes(date.getDay())) {
variations.push('greyed');
}
const greyedAndRowRelativeClasses = ['rowStart', 'rowEnd'].reduce((p, c) => { const greyedAndRowRelativeClasses = ['rowStart', 'rowEnd'].reduce((p, c) => {
switch (c) { switch (c) {
@ -20,7 +28,7 @@ export const getDateVariations = (
default: default:
return p; return p;
} }
}, greyedClasses); }, variations);
if (!dateRange?.startDate || !dateRange?.endDate) { if (!dateRange?.startDate || !dateRange?.endDate) {
return greyedAndRowRelativeClasses; return greyedAndRowRelativeClasses;

Loading…
Cancel
Save