nextui-org--nextui
362 行
9.3 KiB
CSS
362 行
9.3 KiB
CSS
/* =============================================================================
|
|
* RangeCalendar Component Styles
|
|
*
|
|
* A compound component for contiguous date range selection.
|
|
* Uses BEM naming convention: range-calendar, range-calendar__element, range-calendar--modifier
|
|
* ============================================================================= */
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Base RangeCalendar Styles
|
|
* -------------------------------------------------------------------------- */
|
|
.range-calendar {
|
|
@apply w-63 max-w-63;
|
|
|
|
container-type: inline-size;
|
|
}
|
|
|
|
/* Week view – visibleDuration={{ weeks: n }} */
|
|
.range-calendar--week-view {
|
|
.range-calendar__cell {
|
|
/* Keep cells circular on the 7-column grid; only filled cells take space. */
|
|
@apply aspect-square size-auto w-full place-self-center;
|
|
}
|
|
}
|
|
|
|
/* Day view – visibleDuration={{ days: n }} */
|
|
.range-calendar--day-view {
|
|
.range-calendar__cell {
|
|
@apply aspect-square size-auto w-full place-self-center;
|
|
}
|
|
|
|
/*
|
|
* Isolate header and body into separate 7-column grids. With display:contents
|
|
* on the root grid, fewer than 7 weekday headers flow into the same row as dates.
|
|
*/
|
|
.range-calendar__grid {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.range-calendar__grid-header {
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
@apply w-full;
|
|
|
|
& > tr {
|
|
display: contents;
|
|
}
|
|
}
|
|
|
|
.range-calendar__grid-body {
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
@apply mt-1 w-full;
|
|
|
|
& > tr {
|
|
display: contents;
|
|
}
|
|
|
|
& > tr:first-child > td {
|
|
@apply mt-0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* RangeCalendar Header
|
|
* -------------------------------------------------------------------------- */
|
|
.range-calendar__header {
|
|
@apply flex items-center justify-between px-0.5 pb-4;
|
|
|
|
&:has(.calendar-year-picker__trigger[data-open="true"]) {
|
|
.range-calendar__nav-button {
|
|
@apply pointer-events-none opacity-0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.range-calendar__heading {
|
|
@apply flex-1 text-sm font-medium;
|
|
}
|
|
|
|
.range-calendar__nav-button {
|
|
@apply flex size-6 items-center justify-center rounded-xl text-accent-soft-foreground;
|
|
|
|
will-change: scale;
|
|
|
|
/**
|
|
* Transitions
|
|
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
*/
|
|
transition:
|
|
transform 250ms var(--ease-out),
|
|
background-color 100ms var(--ease-out),
|
|
box-shadow 100ms var(--ease-out),
|
|
opacity 150ms var(--ease-out);
|
|
@apply transform-gpu motion-reduce:transition-none;
|
|
|
|
cursor: var(--cursor-interactive);
|
|
|
|
/* Hover state – only on devices that support hover (avoids false triggers on touch) */
|
|
@media (hover: hover) {
|
|
&:hover,
|
|
&[data-hovered="true"] {
|
|
@apply bg-default text-accent-soft-foreground;
|
|
}
|
|
}
|
|
|
|
/* Pressed state */
|
|
&:active,
|
|
&[data-pressed="true"] {
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
/* Focus state */
|
|
&:focus-visible,
|
|
&[data-focus-visible="true"] {
|
|
@apply status-focused;
|
|
}
|
|
|
|
/* Disabled state */
|
|
&:disabled,
|
|
&[data-disabled="true"] {
|
|
@apply status-disabled;
|
|
}
|
|
}
|
|
|
|
.range-calendar__nav-button-icon {
|
|
@apply size-4;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* RangeCalendar Grid
|
|
* -------------------------------------------------------------------------- */
|
|
.range-calendar__grid {
|
|
/* Override table display with CSS Grid for easier customization */
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
@apply w-full;
|
|
|
|
&[aria-readonly="true"] {
|
|
.range-calendar__cell {
|
|
@apply pointer-events-none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.range-calendar__grid-header {
|
|
/* Grid header (thead) styles */
|
|
display: contents;
|
|
|
|
& > tr {
|
|
display: contents;
|
|
}
|
|
}
|
|
|
|
.range-calendar__grid-body {
|
|
/* Grid body (tbody) styles */
|
|
display: contents;
|
|
|
|
& > tr {
|
|
display: contents;
|
|
}
|
|
|
|
/* Add top spacing between header and first body row */
|
|
& > tr:first-child > td {
|
|
@apply mt-1;
|
|
}
|
|
}
|
|
|
|
.range-calendar__grid-row {
|
|
/* Use 'contents' so cells participate directly in grid */
|
|
/* Note: This class can be used for custom row styling if needed */
|
|
display: contents;
|
|
}
|
|
|
|
.range-calendar__header-cell {
|
|
/* Header cell (th - weekday names) styles */
|
|
@apply flex items-center justify-center pb-2 text-xs font-medium text-muted;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* RangeCalendar Cells
|
|
* -------------------------------------------------------------------------- */
|
|
.range-calendar__cell {
|
|
@apply relative z-1 mx-0 my-[2px] rounded-3xl p-0 outline-none;
|
|
cursor: var(--cursor-interactive);
|
|
|
|
will-change: background-color, border-color;
|
|
/**
|
|
* Transitions
|
|
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
*/
|
|
transition:
|
|
box-shadow 100ms var(--ease-out),
|
|
border-color 100ms var(--ease-out);
|
|
@apply transform-gpu motion-reduce:transition-none;
|
|
|
|
/* Inner interactive circle/capsule (equivalent to React Aria "button-base") */
|
|
.range-calendar__cell-button {
|
|
@apply flex aspect-square w-full items-center justify-center rounded-3xl text-sm font-medium text-foreground no-highlight;
|
|
|
|
will-change: scale;
|
|
transition: scale 200ms var(--ease-out);
|
|
@apply transform-gpu motion-reduce:transition-none;
|
|
}
|
|
|
|
/* Focus state */
|
|
&:focus-visible:not(:focus),
|
|
&[data-focus-visible="true"] {
|
|
@apply z-2;
|
|
|
|
.range-calendar__cell-button {
|
|
@apply status-focused;
|
|
}
|
|
}
|
|
|
|
/* Today indicator */
|
|
&[data-today="true"] {
|
|
.range-calendar__cell-button {
|
|
@apply bg-accent-soft text-accent-soft-foreground;
|
|
}
|
|
|
|
@media (hover: hover) {
|
|
&:hover:not([data-selected="true"]),
|
|
&[data-hovered="true"]:not([data-selected="true"]) {
|
|
.range-calendar__cell-button {
|
|
@apply bg-accent-soft-hover;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Range selected track (middle segment) */
|
|
&[data-selected="true"]:not([data-outside-month="true"]) {
|
|
@apply rounded-none bg-accent-soft;
|
|
}
|
|
|
|
/* Round row boundaries so the range track looks continuous across weeks */
|
|
&[data-selected="true"]:is(td:first-child > *, [aria-disabled] + td > *) {
|
|
@apply rounded-ss-lg rounded-es-lg;
|
|
&[data-selection-start="true"] {
|
|
@apply rounded-ss-3xl rounded-es-3xl;
|
|
}
|
|
}
|
|
|
|
&[data-selected="true"]:is(td:last-child > *, td:has(+ [aria-disabled]) > *) {
|
|
@apply rounded-se-lg rounded-ee-lg;
|
|
&[data-selection-end="true"] {
|
|
@apply rounded-se-3xl rounded-ee-3xl;
|
|
}
|
|
}
|
|
|
|
/* Range caps (start/end) */
|
|
&[data-selection-start="true"]:not([data-outside-month="true"]),
|
|
&[data-selection-end="true"]:not([data-outside-month="true"]) {
|
|
@apply z-2;
|
|
|
|
.range-calendar__cell-button {
|
|
@apply bg-accent text-accent-foreground;
|
|
}
|
|
}
|
|
|
|
/* &[data-selection-start="true"]:has(+ [data-selection-end="true"]) {
|
|
@apply rounded-full;
|
|
} */
|
|
|
|
&[data-selection-start="true"]:not([data-outside-month="true"]) {
|
|
@apply rounded-tl-3xl rounded-bl-3xl;
|
|
}
|
|
|
|
&[data-selection-end="true"]:not([data-outside-month="true"]) {
|
|
@apply rounded-tr-3xl rounded-br-3xl;
|
|
}
|
|
|
|
/* Pressed state */
|
|
&:active,
|
|
&[data-pressed="true"] {
|
|
.range-calendar__cell-button {
|
|
scale: 0.9;
|
|
}
|
|
|
|
&[data-selection-start="true"],
|
|
&[data-selection-end="true"] {
|
|
.range-calendar__cell-button {
|
|
@apply bg-accent-hover;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Hover state for non-selected days */
|
|
@media (hover: hover) {
|
|
&:hover:not([data-selected="true"]),
|
|
&[data-hovered="true"]:not([data-selected="true"]) {
|
|
.range-calendar__cell-button {
|
|
@apply bg-default;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Outside month (previous/next month days) */
|
|
&[data-outside-month="true"] {
|
|
@apply text-muted opacity-50;
|
|
}
|
|
|
|
&[data-selected="true"][data-outside-month="true"]:not(
|
|
[data-selection-start="true"],
|
|
[data-selection-end="true"]
|
|
) {
|
|
@apply bg-default/20;
|
|
}
|
|
|
|
/* Unavailable dates */
|
|
&[data-unavailable="true"] {
|
|
@apply status-disabled;
|
|
}
|
|
|
|
/* Disabled state */
|
|
&:disabled:not([data-outside-month="true"]),
|
|
&[data-disabled="true"]:not([data-outside-month="true"]) {
|
|
@apply status-disabled;
|
|
|
|
text-decoration: line-through;
|
|
}
|
|
}
|
|
|
|
/* Outside-month cell followed by selected cell across adjacent table cells */
|
|
.range-calendar__grid-body
|
|
td:has(> .range-calendar__cell[data-outside-month="true"])
|
|
+ td
|
|
> .range-calendar__cell[data-selected="true"] {
|
|
@apply rounded-ss-lg rounded-es-lg;
|
|
|
|
&[data-outside-month="true"],
|
|
&[data-selection-start="true"] {
|
|
@apply rounded-ss-3xl rounded-es-3xl;
|
|
}
|
|
}
|
|
|
|
/* Selected cell followed by outside-month cell across adjacent table cells */
|
|
.range-calendar__grid-body
|
|
td:has(> .range-calendar__cell[data-selected="true"]):has(
|
|
+ td > .range-calendar__cell[data-outside-month="true"]
|
|
)
|
|
> .range-calendar__cell[data-selected="true"] {
|
|
@apply rounded-se-lg rounded-ee-lg;
|
|
|
|
&[data-outside-month="true"],
|
|
&[data-selection-end="true"] {
|
|
@apply rounded-se-3xl rounded-ee-3xl;
|
|
}
|
|
}
|
|
|
|
/* Cell indicator - small dot at bottom center of cell */
|
|
.range-calendar__cell-indicator {
|
|
@apply absolute bottom-1 left-1/2 size-[3px] -translate-x-1/2 rounded-xs bg-muted;
|
|
|
|
/* Indicator color changes when cell is selected */
|
|
[data-selected="true"] > & {
|
|
@apply bg-accent-foreground;
|
|
}
|
|
}
|