Files
tabler/core/scss/ui/_datepicker.scss

474 lines
12 KiB
SCSS

// Datepicker
//
// Styles the `data-vc-*` markup that Vanilla Calendar Pro renders, the same way
// Bootstrap 6 does: the calendar grid is one set of tokens (`--calendar-*`),
// the popup surface the datepicker adds around it is another (`--datepicker-*`).
// An inline calendar renders unadorned and takes the surface of its container.
@use '../config' as *;
// stylelint-disable selector-max-attribute, selector-no-qualifying-type -- the plugin marks everything with data attributes
//
// Calendar grid
//
[data-vc='calendar'] {
--calendar-padding: #{$datepicker-calendar-padding};
--calendar-color: var(--body-color);
--calendar-font-size: #{$datepicker-calendar-font-size};
--calendar-header-font-weight: #{$datepicker-calendar-header-font-weight};
--calendar-weekday-color: var(--secondary);
--calendar-week-number-color: var(--secondary);
--calendar-week-number-border-color: var(--border-color);
--calendar-day-hover-bg: var(--hover-bg);
--calendar-day-selected-bg: var(--primary);
--calendar-day-selected-color: var(--primary-fg);
--calendar-day-today-bg: #{color-transparent(var(--body-color), 6%)};
--calendar-day-today-color: var(--primary);
--calendar-day-disabled-color: var(--disabled-color);
--calendar-day-size: #{$datepicker-calendar-day-size};
--calendar-day-font-size: #{$datepicker-calendar-day-font-size};
--calendar-border-radius: var(--border-radius);
position: relative;
box-sizing: border-box;
display: flex;
flex-direction: column;
width: fit-content;
padding: var(--calendar-padding);
font-family: inherit;
font-size: var(--calendar-font-size);
color: var(--calendar-color);
button {
font-family: inherit;
@include focus-ring-transition();
}
button:focus-visible {
position: relative;
z-index: 1;
@include focus-ring(true);
}
}
// Month navigation
[data-vc-arrow] {
position: relative;
display: block;
width: 2rem;
height: 2rem;
color: var(--calendar-color);
pointer-events: auto;
cursor: pointer;
background-color: transparent;
border: 0;
@include border-radius(var(--calendar-border-radius));
&::before {
position: absolute;
inset: 0.25rem;
content: '';
background-color: currentColor;
@include mask-icon(url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 16c-.3 0-.5-.1-.7-.3l-6-6c-.4-.4-.4-1 0-1.4s1-.4 1.4 0l5.3 5.3 5.3-5.3c.4-.4 1-.4 1.4 0s.4 1 0 1.4l-6 6c-.2.2-.4.3-.7.3'/></svg>"), $size: 1rem);
}
&:hover {
background-color: var(--calendar-day-hover-bg);
}
}
[data-vc-arrow='prev']::before {
transform: rotate(90deg);
}
[data-vc-arrow='next']::before {
transform: rotate(-90deg);
}
// The controls overlay the header, so they repeat the calendar's own inset to
// keep the arrows aligned with the content below.
[data-vc='controls'] {
position: absolute;
top: 0;
right: 0;
left: 0;
z-index: 20;
display: flex;
align-items: center;
justify-content: space-between;
padding-block-start: var(--calendar-padding);
padding-inline: var(--calendar-padding);
pointer-events: none;
}
[data-vc='grid'] {
display: flex;
flex-grow: 1;
flex-wrap: wrap;
gap: 1.75rem;
}
[data-vc='column'] {
display: flex;
flex-grow: 1;
flex-direction: column;
min-width: 240px;
}
// Header: month and year
[data-vc='header'] {
position: relative;
display: flex;
align-items: center;
margin-bottom: 0.75rem;
}
[data-vc-header='content'] {
display: inline-flex;
flex-grow: 1;
align-items: center;
justify-content: center;
white-space: pre-wrap;
}
[data-vc='month'],
[data-vc='year'] {
padding: 0.25rem 0.5rem;
margin-inline: -0.125rem;
font-size: var(--font-size-base, 1rem);
font-weight: var(--calendar-header-font-weight);
color: var(--calendar-color);
background-color: transparent;
border: 0;
@include border-radius(var(--calendar-border-radius));
&:disabled {
color: var(--calendar-day-disabled-color);
pointer-events: none;
}
&:hover:not(:disabled) {
background-color: var(--calendar-day-hover-bg);
}
}
// Holds the week numbers column, when enabled, next to the month
[data-vc='wrapper'] {
display: flex;
flex-grow: 1;
}
[data-vc='content'] {
display: flex;
flex-grow: 1;
flex-direction: column;
}
// Month and year views. The plugin wraps each set in role="row" and
// role="gridcell" elements, so the column grid goes on the row.
[data-vc='months'],
[data-vc='years'] {
display: flex;
flex-grow: 1;
flex-direction: column;
row-gap: 1rem;
}
[data-vc-months='row'],
[data-vc-years='row'] {
display: grid;
grid-template-columns: repeat(var(--calendar-columns, 4), minmax(0, 1fr));
column-gap: 0.25rem;
align-items: center;
}
[data-vc='years'] {
--calendar-columns: 5;
}
[data-vc-months='cell'],
[data-vc-years='cell'] {
display: flex;
}
[data-vc-months-month],
[data-vc-years-year] {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 2.5rem;
padding: 0.25rem;
font-size: var(--calendar-day-font-size);
font-weight: var(--calendar-header-font-weight);
line-height: 1rem;
color: var(--calendar-weekday-color);
text-align: center;
word-break: break-all;
cursor: pointer;
background-color: transparent;
border: 0;
@include border-radius(var(--calendar-border-radius));
&:disabled {
color: var(--calendar-day-disabled-color);
pointer-events: none;
}
&:hover:not(:disabled) {
background-color: var(--calendar-day-hover-bg);
}
&[data-vc-months-month-selected],
&[data-vc-years-year-selected] {
color: var(--calendar-day-selected-color);
background-color: var(--calendar-day-selected-bg);
&:hover {
color: var(--calendar-day-selected-color);
background-color: var(--calendar-day-selected-bg);
}
}
}
// Weekday header
[data-vc='week'] {
display: grid;
grid-template-columns: repeat(7, 1fr);
justify-items: center;
margin-bottom: 0.5rem;
}
[data-vc-week-day] {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-width: var(--calendar-day-size);
padding: 0;
margin: 0;
font-size: var(--calendar-day-font-size);
font-weight: var(--calendar-header-font-weight);
line-height: 1rem;
color: var(--calendar-weekday-color);
background-color: transparent;
border: 0;
}
button[data-vc-week-day] {
cursor: pointer;
}
// Week numbers: a column in front of the month, with a title that lines up
// with the weekday header and one number for each row of dates.
[data-vc-week='numbers'] {
display: flex;
flex-direction: column;
padding-inline-end: 0.5rem;
margin-inline-end: 0.5rem;
border-inline-end: var(--border-width) solid var(--calendar-week-number-border-color);
}
[data-vc-week-numbers='title'] {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.5rem;
font-size: var(--calendar-day-font-size);
font-weight: var(--calendar-header-font-weight);
line-height: 1rem;
color: var(--calendar-week-number-color);
}
[data-vc-week-numbers='content'] {
display: grid;
grid-auto-rows: calc(var(--calendar-day-size) + 0.25rem);
align-items: center;
justify-items: center;
}
[data-vc-week-number] {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-width: var(--calendar-day-size);
font-size: var(--calendar-day-font-size);
font-weight: $font-weight-normal;
line-height: 1rem;
color: var(--calendar-week-number-color);
}
// Dates grid
[data-vc='dates'] {
pointer-events: none;
}
[data-vc-dates='row'] {
display: grid;
grid-template-columns: repeat(7, 1fr);
align-items: center;
justify-items: center;
width: 100%;
}
[data-vc-date] {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding-top: 0.125rem;
padding-bottom: 0.125rem;
pointer-events: auto;
&:not(:has([data-vc-date-btn])),
&[data-vc-date-disabled],
&[data-vc-date-disabled] [data-vc-date-btn] {
pointer-events: none;
}
}
// A day paints its background from two variables: the colour a state picks
// and the opacity it gets. States change the variables, never `opacity`, so
// the date stays readable on a faded background.
[data-vc-date-btn] {
--calendar-day-bg: transparent;
--calendar-day-bg-opacity: 100%;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-width: var(--calendar-day-size);
height: 100%;
min-height: var(--calendar-day-size);
padding: 0;
font-size: var(--calendar-day-font-size);
font-weight: $font-weight-normal;
line-height: 1rem;
color: var(--calendar-color);
cursor: pointer;
background-color: color-transparent(var(--calendar-day-bg), var(--calendar-day-bg-opacity));
border: 0;
border-radius: var(--calendar-border-radius);
@include focus-ring-transition(color $transition-time, background-color $transition-time);
&:hover {
--calendar-day-bg: var(--calendar-day-hover-bg);
}
}
// Today
[data-vc-date-today] [data-vc-date-btn] {
font-weight: $font-weight-bold;
--calendar-day-bg: var(--calendar-day-today-bg);
color: var(--calendar-day-today-color);
}
// Days of the previous and next month
[data-vc-date-month='next'] [data-vc-date-btn],
[data-vc-date-month='prev'] [data-vc-date-btn] {
--calendar-day-bg-opacity: 50%;
color: var(--calendar-weekday-color);
}
[data-vc-date-disabled] [data-vc-date-btn] {
color: var(--calendar-day-disabled-color);
}
// Range selection: the hovered and selected runs join into one bar, so only the
// outer corners keep their radius. Logical corners follow the writing direction.
[data-vc-date-hover] [data-vc-date-btn] {
--calendar-day-bg: var(--calendar-day-hover-bg);
border-radius: 0;
}
[data-vc-date-hover='first'] [data-vc-date-btn] {
border-start-start-radius: var(--calendar-border-radius);
border-end-start-radius: var(--calendar-border-radius);
}
[data-vc-date-hover='last'] [data-vc-date-btn] {
border-start-end-radius: var(--calendar-border-radius);
border-end-end-radius: var(--calendar-border-radius);
}
[data-vc-date-hover='first-and-last'] [data-vc-date-btn] {
border-radius: var(--calendar-border-radius);
}
[data-vc-date-selected] [data-vc-date-btn] {
--calendar-day-bg: var(--calendar-day-selected-bg);
color: var(--calendar-day-selected-color);
}
// Inside a range only the two ends are solid; the days between keep their own
// text colour on a faint tint of the selected colour.
[data-vc-date-selected='middle'] [data-vc-date-btn] {
--calendar-day-bg-opacity: #{$datepicker-calendar-range-bg-opacity};
color: var(--calendar-color);
border-radius: 0;
}
[data-vc-date-selected='first'] [data-vc-date-btn] {
border-start-start-radius: var(--calendar-border-radius);
border-start-end-radius: 0;
border-end-start-radius: var(--calendar-border-radius);
border-end-end-radius: 0;
}
[data-vc-date-selected='last'] [data-vc-date-btn] {
border-start-start-radius: 0;
border-start-end-radius: var(--calendar-border-radius);
border-end-start-radius: 0;
border-end-end-radius: var(--calendar-border-radius);
}
[data-vc-date-selected='first-and-last'] [data-vc-date-btn] {
border-radius: var(--calendar-border-radius);
}
//
// Popup surface
//
// The plugin adds `[data-vc-input]` only when it owns a popup, so inline
// calendars keep the bare grid styling above.
[data-vc='calendar'][data-vc-input] {
--datepicker-padding: #{$datepicker-padding};
--datepicker-bg: #{$datepicker-bg};
--datepicker-border-radius: #{$datepicker-border-radius};
--datepicker-box-shadow: #{$datepicker-box-shadow};
--datepicker-min-width: #{$datepicker-min-width};
--datepicker-zindex: #{$zindex-dropdown};
--calendar-padding: var(--datepicker-padding);
position: absolute;
z-index: var(--datepicker-zindex);
min-width: var(--datepicker-min-width);
// Same surface as `.dropdown-menu`: the edge is the 1px ring inside the
// dropdown shadow, so the popup has no border of its own.
background-color: var(--datepicker-bg);
box-shadow: var(--datepicker-box-shadow);
@include border-radius(var(--datepicker-border-radius));
// The plugin creates the popup at 0/0 with this attribute, positions it on
// show, and puts the attribute back on hide. The selector repeats the popup
// one so it wins on specificity; otherwise the popup flashes in the corner
// and never disappears.
&[data-vc-calendar-hidden] {
pointer-events: none;
opacity: 0;
}
}
[data-vc-position='bottom'] {
margin-block-start: 0.25rem;
}
[data-vc-position='top'] {
margin-block-end: -0.25rem;
}
// stylelint-enable selector-max-attribute, selector-no-qualifying-type