432 lines
14 KiB
SCSS
432 lines
14 KiB
SCSS
@use 'sass:math';
|
|
@use '@angular/cdk';
|
|
|
|
@use '../core/style/button-common';
|
|
@use '../core/tokens/m2/mat/datepicker' as tokens-mat-datepicker;
|
|
@use '../core/tokens/token-utils';
|
|
|
|
$calendar-body-label-padding-start: 5% !default;
|
|
// We don't want the label to jump around when we switch between month and year views, so we use
|
|
// the same amount of padding regardless of the number of columns. We align the header label with
|
|
// the one third mark of the first cell, this was chosen somewhat arbitrarily to make it look
|
|
// roughly like the mock. Half way is too far since the cell text is center aligned.
|
|
$calendar-body-label-side-padding: math.div(33%, 7) !default;
|
|
$calendar-body-cell-min-size: 32px !default;
|
|
$calendar-body-cell-content-margin: 5% !default;
|
|
$calendar-body-cell-content-border-width: 1px !default;
|
|
$calendar-body-cell-radius: 999px !default;
|
|
$calendar-body-preview-cell-border: dashed 1px;
|
|
|
|
$calendar-body-min-size: 7 * $calendar-body-cell-min-size !default;
|
|
$calendar-body-cell-content-size: 100% - $calendar-body-cell-content-margin * 2 !default;
|
|
|
|
$calendar-range-end-body-cell-size:
|
|
$calendar-body-cell-content-size + $calendar-body-cell-content-margin !default;
|
|
|
|
$_tokens: (tokens-mat-datepicker.$prefix, tokens-mat-datepicker.get-token-slots());
|
|
|
|
// Styles for a highlighted calendar cell (e.g. hovered or focused).
|
|
@mixin _highlighted-cell($token-name) {
|
|
& > .mat-calendar-body-cell-content {
|
|
@include _unselected-cell {
|
|
@include token-utils.create-token-slot(background-color, $token-name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Utility mixin to target cells that aren't selected. Used to make selector easier to follow.
|
|
@mixin _unselected-cell {
|
|
&:not(.mat-calendar-body-selected):not(.mat-calendar-body-comparison-identical) {
|
|
@content;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body {
|
|
min-width: $calendar-body-min-size;
|
|
}
|
|
|
|
.mat-calendar-body-today {
|
|
@include _unselected-cell {
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include token-utils.create-token-slot(border-color,
|
|
calendar-date-today-outline-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-label {
|
|
height: 0;
|
|
line-height: 0;
|
|
text-align: start;
|
|
padding-left: $calendar-body-label-side-padding;
|
|
padding-right: $calendar-body-label-side-padding;
|
|
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include token-utils.create-token-slot(font-size, calendar-body-label-text-size);
|
|
@include token-utils.create-token-slot(font-weight, calendar-body-label-text-weight);
|
|
@include token-utils.create-token-slot(color, calendar-body-label-text-color);
|
|
}
|
|
}
|
|
|
|
// Label that is not rendered and removed from the accessibility tree.
|
|
.mat-calendar-body-hidden-label {
|
|
display: none;
|
|
}
|
|
|
|
.mat-calendar-body-cell-container {
|
|
position: relative;
|
|
height: 0;
|
|
line-height: 0;
|
|
}
|
|
|
|
.mat-calendar-body-cell {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: none;
|
|
text-align: center;
|
|
outline: none;
|
|
font-family: inherit;
|
|
margin: 0;
|
|
|
|
// Needs to be repeated here in order to override the user agent styles.
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include token-utils.create-token-slot(font-family, calendar-text-font);
|
|
@include token-utils.create-token-slot(font-size, calendar-text-size);
|
|
}
|
|
|
|
@include button-common.reset();
|
|
}
|
|
|
|
// We use ::before to apply a background to the body cell, because we need to apply a border
|
|
// radius to the start/end which means that part of the element will be cut off, making hovering
|
|
// through all the cells look glitchy. We can't do it on the cell itself, because it's the one
|
|
// that has the event listener and it can't be on the cell content, because it always has a
|
|
// border radius. Note that this and the selectors below can be much simpler if we were to use
|
|
// two separate elements for the main and comparison ranges, like we're doing for the preview
|
|
// range. We don't follow the simpler approach, because the range colors usually have some
|
|
// kind of opacity, which means that they'll start mixing when they're layered on top of each
|
|
// other, making the calendar look messy.
|
|
.mat-calendar-body-cell::before,
|
|
.mat-calendar-body-cell::after,
|
|
.mat-calendar-body-cell-preview {
|
|
content: '';
|
|
position: absolute;
|
|
top: $calendar-body-cell-content-margin;
|
|
left: 0;
|
|
z-index: 0;
|
|
box-sizing: border-box;
|
|
display: block;
|
|
|
|
// We want the range background to be slightly shorter than the cell so
|
|
// that there's a gap when the range goes across multiple rows.
|
|
height: $calendar-body-cell-content-size;
|
|
width: 100%;
|
|
}
|
|
|
|
.mat-calendar-body-range-start:not(.mat-calendar-body-in-comparison-range)::before,
|
|
.mat-calendar-body-range-start::after,
|
|
.mat-calendar-body-comparison-start:not(.mat-calendar-body-comparison-bridge-start)::before,
|
|
.mat-calendar-body-comparison-start::after,
|
|
.mat-calendar-body-preview-start .mat-calendar-body-cell-preview {
|
|
// Since the range background isn't a perfect circle, we need to size
|
|
// and offset the start so that it aligns with the main circle.
|
|
left: $calendar-body-cell-content-margin;
|
|
width: $calendar-range-end-body-cell-size;
|
|
border-top-left-radius: $calendar-body-cell-radius;
|
|
border-bottom-left-radius: $calendar-body-cell-radius;
|
|
|
|
[dir='rtl'] & {
|
|
left: 0;
|
|
border-radius: 0;
|
|
border-top-right-radius: $calendar-body-cell-radius;
|
|
border-bottom-right-radius: $calendar-body-cell-radius;
|
|
}
|
|
}
|
|
|
|
@mixin _range-right-radius {
|
|
// Since the range background isn't a perfect circle, we need to
|
|
// resize the end so that it aligns with the main circle.
|
|
width: $calendar-range-end-body-cell-size;
|
|
border-top-right-radius: $calendar-body-cell-radius;
|
|
border-bottom-right-radius: $calendar-body-cell-radius;
|
|
}
|
|
|
|
.mat-calendar-body-range-end:not(.mat-calendar-body-in-comparison-range)::before,
|
|
.mat-calendar-body-range-end::after,
|
|
.mat-calendar-body-comparison-end:not(.mat-calendar-body-comparison-bridge-end)::before,
|
|
.mat-calendar-body-comparison-end::after,
|
|
.mat-calendar-body-preview-end .mat-calendar-body-cell-preview {
|
|
@include _range-right-radius;
|
|
|
|
[dir='rtl'] & {
|
|
left: $calendar-body-cell-content-margin;
|
|
border-radius: 0;
|
|
border-top-left-radius: $calendar-body-cell-radius;
|
|
border-bottom-left-radius: $calendar-body-cell-radius;
|
|
}
|
|
}
|
|
|
|
// Styles necessary to make RTL work.
|
|
[dir='rtl'] {
|
|
.mat-calendar-body-comparison-bridge-start.mat-calendar-body-range-end::after,
|
|
.mat-calendar-body-comparison-bridge-end.mat-calendar-body-range-start::after {
|
|
@include _range-right-radius;
|
|
}
|
|
}
|
|
|
|
// Prevents the extra overlap range indication from showing up when it's not supposed to.
|
|
.mat-calendar-body-comparison-start.mat-calendar-body-range-end::after,
|
|
.mat-calendar-body-comparison-end.mat-calendar-body-range-start::after {
|
|
// Note that the RTL selector here is redundant, but we need to keep it in order to
|
|
// raise the specificity since it can be overridden by some of the styles from above.
|
|
&, [dir='rtl'] & {
|
|
width: $calendar-body-cell-content-size;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-in-preview {
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include token-utils.create-token-slot(color, calendar-date-preview-state-outline-color);
|
|
}
|
|
|
|
.mat-calendar-body-cell-preview {
|
|
border-top: $calendar-body-preview-cell-border;
|
|
border-bottom: $calendar-body-preview-cell-border;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-preview-start .mat-calendar-body-cell-preview {
|
|
border-left: $calendar-body-preview-cell-border;
|
|
|
|
[dir='rtl'] & {
|
|
border-left: 0;
|
|
border-right: $calendar-body-preview-cell-border;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-preview-end .mat-calendar-body-cell-preview {
|
|
border-right: $calendar-body-preview-cell-border;
|
|
|
|
[dir='rtl'] & {
|
|
border-right: 0;
|
|
border-left: $calendar-body-preview-cell-border;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-disabled {
|
|
cursor: default;
|
|
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
& > .mat-calendar-body-cell-content {
|
|
@include _unselected-cell {
|
|
@include token-utils.create-token-slot(color, calendar-date-disabled-state-text-color);
|
|
}
|
|
}
|
|
|
|
& > .mat-calendar-body-today {
|
|
@include _unselected-cell {
|
|
@include token-utils.create-token-slot(border-color,
|
|
calendar-date-today-disabled-state-outline-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fade out the disabled cells so that they can be distinguished from the enabled ones. Note that
|
|
// ideally we'd use `color: GreyText` here which is what the browser uses for disabled buttons,
|
|
// but we can't because Firefox doesn't recognize it.
|
|
@include cdk.high-contrast {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-cell-content {
|
|
top: $calendar-body-cell-content-margin;
|
|
left: $calendar-body-cell-content-margin;
|
|
z-index: 1;
|
|
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
box-sizing: border-box;
|
|
width: $calendar-body-cell-content-size;
|
|
height: $calendar-body-cell-content-size;
|
|
|
|
// Prevents text being off-center on Android.
|
|
line-height: 1;
|
|
|
|
border-width: $calendar-body-cell-content-border-width;
|
|
border-style: solid;
|
|
|
|
// Choosing a value clearly larger than the height ensures we get the correct capsule shape.
|
|
border-radius: $calendar-body-cell-radius;
|
|
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include token-utils.create-token-slot(color, calendar-date-text-color);
|
|
@include token-utils.create-token-slot(border-color,
|
|
calendar-date-outline-color);
|
|
}
|
|
|
|
// Increase specificity because focus indicator styles are part of the `mat-core` mixin and can
|
|
// potentially overwrite the absolute position of the container.
|
|
&.mat-focus-indicator {
|
|
position: absolute;
|
|
}
|
|
|
|
@include cdk.high-contrast {
|
|
border: none;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-active {
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
.cdk-keyboard-focused &, .cdk-program-focused & {
|
|
@include _highlighted-cell(calendar-date-focus-state-background-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
@media (hover: hover) {
|
|
.mat-calendar-body-cell:not(.mat-calendar-body-disabled):hover {
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include _highlighted-cell(calendar-date-hover-state-background-color);
|
|
}
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-selected {
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
@include token-utils.create-token-slot(background-color,
|
|
calendar-date-selected-state-background-color);
|
|
@include token-utils.create-token-slot(color, calendar-date-selected-state-text-color);
|
|
|
|
.mat-calendar-body-disabled > & {
|
|
@include token-utils.create-token-slot(background-color,
|
|
calendar-date-selected-disabled-state-background-color);
|
|
}
|
|
|
|
&.mat-calendar-body-today {
|
|
$shadow: token-utils.get-token-variable(calendar-date-today-selected-state-outline-color);
|
|
box-shadow: inset 0 0 0 1px #{$shadow};
|
|
}
|
|
}
|
|
}
|
|
|
|
@include token-utils.use-tokens($_tokens...) {
|
|
$range-color:
|
|
token-utils.get-token-variable(calendar-date-in-range-state-background-color);
|
|
$comparison-color:
|
|
token-utils.get-token-variable(calendar-date-in-comparison-range-state-background-color);
|
|
|
|
.mat-calendar-body-in-range::before {
|
|
@include token-utils.create-token-slot(background,
|
|
calendar-date-in-range-state-background-color);
|
|
}
|
|
|
|
.mat-calendar-body-comparison-identical,
|
|
.mat-calendar-body-in-comparison-range::before {
|
|
@include token-utils.create-token-slot(background,
|
|
calendar-date-in-comparison-range-state-background-color);
|
|
}
|
|
|
|
.mat-calendar-body-comparison-identical,
|
|
.mat-calendar-body-in-comparison-range::before {
|
|
@include token-utils.create-token-slot(background,
|
|
calendar-date-in-comparison-range-state-background-color);
|
|
}
|
|
|
|
.mat-calendar-body-comparison-bridge-start::before,
|
|
[dir='rtl'] .mat-calendar-body-comparison-bridge-end::before {
|
|
background: linear-gradient(to right, $range-color 50%, $comparison-color 50%);
|
|
}
|
|
|
|
.mat-calendar-body-comparison-bridge-end::before,
|
|
[dir='rtl'] .mat-calendar-body-comparison-bridge-start::before {
|
|
background: linear-gradient(to left, $range-color 50%, $comparison-color 50%);
|
|
}
|
|
|
|
.mat-calendar-body-in-range > .mat-calendar-body-comparison-identical,
|
|
.mat-calendar-body-in-comparison-range.mat-calendar-body-in-range::after {
|
|
@include token-utils.create-token-slot(background,
|
|
calendar-date-in-overlap-range-state-background-color);
|
|
}
|
|
|
|
.mat-calendar-body-comparison-identical.mat-calendar-body-selected,
|
|
.mat-calendar-body-in-comparison-range > .mat-calendar-body-selected {
|
|
@include token-utils.create-token-slot(background,
|
|
calendar-date-in-overlap-range-selected-state-background-color);
|
|
}
|
|
}
|
|
|
|
@include cdk.high-contrast {
|
|
$main-range-border: solid 1px;
|
|
$comparison-range-border: dashed 1px;
|
|
|
|
.mat-datepicker-popup:not(:empty),
|
|
.mat-calendar-body-cell:not(.mat-calendar-body-in-range) .mat-calendar-body-selected {
|
|
outline: solid 1px;
|
|
}
|
|
|
|
.mat-calendar-body-today {
|
|
outline: dotted 1px;
|
|
}
|
|
|
|
// These backgrounds need to be removed, because they'll block the date ranges.
|
|
.mat-calendar-body-cell::before,
|
|
.mat-calendar-body-cell::after,
|
|
.mat-calendar-body-selected {
|
|
background: none;
|
|
}
|
|
|
|
.mat-calendar-body-in-range::before,
|
|
.mat-calendar-body-comparison-bridge-start::before,
|
|
.mat-calendar-body-comparison-bridge-end::before {
|
|
border-top: $main-range-border;
|
|
border-bottom: $main-range-border;
|
|
}
|
|
|
|
.mat-calendar-body-range-start::before {
|
|
border-left: $main-range-border;
|
|
|
|
[dir='rtl'] & {
|
|
border-left: 0;
|
|
border-right: $main-range-border;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-range-end::before {
|
|
border-right: $main-range-border;
|
|
|
|
[dir='rtl'] & {
|
|
border-right: 0;
|
|
border-left: $main-range-border;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-in-comparison-range::before {
|
|
border-top: $comparison-range-border;
|
|
border-bottom: $comparison-range-border;
|
|
}
|
|
|
|
.mat-calendar-body-comparison-start::before {
|
|
border-left: $comparison-range-border;
|
|
|
|
[dir='rtl'] & {
|
|
border-left: 0;
|
|
border-right: $comparison-range-border;
|
|
}
|
|
}
|
|
|
|
.mat-calendar-body-comparison-end::before {
|
|
border-right: $comparison-range-border;
|
|
|
|
[dir='rtl'] & {
|
|
border-right: 0;
|
|
border-left: $comparison-range-border;
|
|
}
|
|
}
|
|
}
|