/* * M3's date pickers — docked, modal and modal input (resources/views/components/datepicker.blade.php). * * One `` wears all three: docked it is a popover hung under the field by CSS anchor * positioning (large corner), modal it is opened with `showModal()` over a scrim (extra-large * corner, with M3's header: a title, the chosen date as the headline, and the switch between * calendar and typing), and full — a `range` picker on a compact window — is that modal dialog * grown to the whole screen, M3's full-screen range picker. The first two are 360px of * surface-container-high at elevation 3; the third keeps the colour and drops the corner. * * Values from DatePickerModalTokens and DateInputModalTokens (androidx Compose Material 3, commit * 27cf9a7d5788aa0f5f2d8b6699ce279560daf326) and the layout of DatePicker.kt, DateRangePicker.kt and * DateInput.kt; the docked picker's from material-web's md-comp-date-picker-docked tokens (v0_192). * Apache-2.0. * * [data-datepicker] the root: the field, its support line, the dialog * [data-datepicker-support] the hint, a server error, or what is wrong with the typed date * [data-datepicker-picker] the ; data-presentation="docked" | "modal" | "full" * [data-datepicker-surface] * [data-datepicker-header] modal only: title, headline, switch * [data-datepicker-full] full only: [data-datepicker-app-bar] (close, switch, Save) * and [data-datepicker-full-headline] (title, headline) * [data-datepicker-calendar] the scroller, full screen * [data-datepicker-nav] month and year: one menu button and arrows (modal), * or a month and a year stepper (docked, data-docked) * [data-datepicker-grid] the weekdays and six weeks of [data-datepicker-day] cells: * data-today, data-selected, data-start, data-end, * data-between, data-outside, data-blank, aria-disabled — * full screen, every month of the window under a * [data-datepicker-month-label] row * [data-datepicker-years] the modal year grid * [data-datepicker-menu] a docked month or year list of [data-datepicker-option]s * [data-datepicker-entry] the text field(s) of the modal input * [data-datepicker-actions] Cancel and OK * * Every state layer is the content colour at 8% on hover (only where a pointer can hover) and 10% on * focus and press; keyboard focus adds the package's 3px secondary ring. */ @layer components { /* ---- The support line under the field ------------------------------------------------------ */ /* The padding is on the lines, not the box, so a box with nothing to say takes no room. */ [data-datepicker-support] { --datepicker-pad: 1rem; color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-sm); letter-spacing: var(--md-sys-typescale-body-sm-tracking); } [data-datepicker-support] > * { padding: 0.25rem var(--datepicker-pad) 0; } [data-datepicker-support][data-size="sm"] { --datepicker-pad: 0.75rem; } [data-datepicker-support][data-size="xs"] { --datepicker-pad: 0.625rem; } [data-datepicker-error] { color: var(--md-sys-color-error); } /* ---- The dialog ---------------------------------------------------------------------------- */ [data-datepicker-picker] { inset: auto; width: 22.5rem; max-width: calc(100vw - 1rem); max-height: calc(100dvh - 1rem); margin: 0; padding: 0; overflow: visible; border: 0; background: transparent; color: var(--md-sys-color-on-surface); } [data-datepicker-picker]:popover-open { top: anchor(bottom); left: anchor(left); margin-block: 0.25rem; position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline; opacity: 1; transition-property: opacity; transition-duration: var(--md-sys-motion-effects-fast-duration); transition-timing-function: var(--md-sys-motion-effects-fast); } @starting-style { [data-datepicker-picker]:popover-open { opacity: 0; } } [data-datepicker-picker]:modal { inset: 0; margin: auto; opacity: 1; scale: 1; transition-property: opacity, scale; transition-duration: var(--md-sys-motion-spatial-fast-duration); transition-timing-function: var(--md-sys-motion-spatial-fast); } @starting-style { [data-datepicker-picker]:modal { opacity: 0; scale: 0.95; } } [data-datepicker-picker]:modal::backdrop { background-color: color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent); } [data-datepicker-surface] { display: flex; flex-direction: column; max-height: inherit; overflow-x: hidden; overflow-y: auto; border-radius: var(--md-sys-shape-corner-lg); background-color: var(--md-sys-color-surface-container-high); box-shadow: var(--md-sys-elevation-3); outline: none; } [data-datepicker-picker][data-presentation="modal"] [data-datepicker-surface] { border-radius: var(--md-sys-shape-corner-xl); } /* ---- The full-screen range picker (compact) ------------------------------------------------- */ /* M3 § Date Pickers: a range picker at a compact breakpoint is a full-screen dialog, "covering * the whole screen for readability and touch-target size", with a close (×) icon button and a * Save confirmation instead of Cancel and OK. Its anatomy is the modal picker's parts in a * different order: an app bar, the supporting text and the range as the headline, a divider, the * day-of-week labels, and a vertically scrolling list of months under them, each with its label. * Only the months scroll; everything above them stays where it is. */ [data-datepicker-picker][data-presentation="full"] { inset: 0; width: 100vw; max-width: none; height: 100dvh; max-height: none; margin: 0; } [data-datepicker-picker][data-presentation="full"] [data-datepicker-surface] { height: 100%; max-height: none; padding-block: var(--material-safe-top, env(safe-area-inset-top)) var(--material-safe-bottom, env(safe-area-inset-bottom)); overflow: hidden; border-radius: 0; box-shadow: none; } [data-datepicker-full] { flex: none; border-bottom: 1px solid var(--md-sys-color-outline-variant); color: var(--md-sys-color-on-surface-variant); } [data-datepicker-app-bar] { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; height: 4rem; padding-inline: 0.25rem 0.75rem; } [data-datepicker-app-bar-actions] { display: flex; align-items: center; gap: 0.25rem; } [data-datepicker-full-headline] { display: flex; flex-direction: column; gap: 0.25rem; padding: 0 1.5rem 1rem; } /* The calendar is the only part that scrolls, with the weekday header held at its top. */ [data-datepicker-picker][data-presentation="full"] [data-datepicker-calendar] { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; } [data-datepicker-picker][data-presentation="full"] [data-datepicker-grid] thead th { position: sticky; top: 0; z-index: 1; background-color: var(--md-sys-color-surface-container-high); } [data-datepicker-picker][data-presentation="full"] [data-datepicker-day] { scroll-margin-block: 3rem; } [data-datepicker-month-label] { padding: 1.25rem 0 0.5rem; color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-title-sm); letter-spacing: var(--md-sys-typescale-title-sm-tracking); text-align: start; } /* ---- The modal header ---------------------------------------------------------------------- */ [data-datepicker-header] { display: flex; flex-direction: column; justify-content: space-between; flex: none; min-height: 7.5rem; border-bottom: 1px solid var(--md-sys-color-outline-variant); color: var(--md-sys-color-on-surface-variant); } [data-datepicker-header][data-range] { min-height: 8rem; } [data-datepicker-title] { padding: 1rem 0.75rem 0 1.5rem; font: var(--md-sys-typescale-label-lg); letter-spacing: var(--md-sys-typescale-label-lg-tracking); } [data-datepicker-headline-row] { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0 0.75rem 0.75rem 1.5rem; } [data-datepicker-headline] { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: var(--md-sys-typescale-headline-lg); letter-spacing: var(--md-sys-typescale-headline-lg-tracking); } [data-datepicker-header][data-range] [data-datepicker-headline] { font: var(--md-sys-typescale-title-lg); letter-spacing: var(--md-sys-typescale-title-lg-tracking); } /* ---- Month and year navigation -------------------------------------------------------------- */ [data-datepicker-nav] { display: flex; flex: none; align-items: center; justify-content: space-between; height: 3.5rem; padding-inline: 0.75rem; color: var(--md-sys-color-on-surface-variant); } [data-datepicker-nav][data-docked] { height: 4rem; padding-inline: 0.25rem; } [data-datepicker-stepper], [data-datepicker-arrows] { display: flex; align-items: center; } /* While a year or month list is open the arrows keep their place but are gone, as androidx hides them. */ [data-datepicker-arrows][data-concealed] { visibility: hidden; } [data-datepicker-menu-button] { position: relative; display: inline-flex; align-items: center; gap: 0.5rem; height: 2.5rem; padding-inline: 0.75rem 0.5rem; border-radius: var(--md-sys-shape-corner-full); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-label-lg); letter-spacing: var(--md-sys-typescale-label-lg-tracking); white-space: nowrap; cursor: pointer; outline: none; isolation: isolate; } [data-datepicker-nav][data-docked] [data-datepicker-menu-button] { padding-inline: 0.5rem 0.25rem; gap: 0.25rem; } [data-datepicker-menu-arrow] { transition: rotate var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } [data-datepicker-menu-button][aria-expanded="true"] [data-datepicker-menu-arrow] { rotate: 180deg; } /* ---- State layers shared by days, years, menu buttons and list rows ------------------------ */ [data-datepicker-menu-button]::before, [data-datepicker-day] > span::before, [data-datepicker-year]::before, [data-datepicker-option]::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background-color: var(--datepicker-layer, currentColor); opacity: 0; pointer-events: none; transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } @media (hover: hover) { [data-datepicker-menu-button]:hover::before, [data-datepicker-day]:not([aria-disabled="true"], [data-blank]):hover > span::before, [data-datepicker-year]:hover::before, [data-datepicker-option]:not([aria-disabled="true"]):hover::before { opacity: 0.08; } } [data-datepicker-menu-button]:focus-visible::before, [data-datepicker-menu-button]:active::before, [data-datepicker-day]:focus-visible > span::before, [data-datepicker-day]:not([aria-disabled="true"], [data-blank]):active > span::before, [data-datepicker-year]:focus-visible::before, [data-datepicker-year]:active::before, [data-datepicker-option]:focus-visible::before, [data-datepicker-option]:not([aria-disabled="true"]):active::before { opacity: 0.1; } [data-datepicker-menu-button]:focus-visible, [data-datepicker-day]:focus-visible > span, [data-datepicker-year]:focus-visible { outline: 3px solid var(--md-sys-color-secondary); outline-offset: 2px; } [data-datepicker-option]:focus-visible { outline: 3px solid var(--md-sys-color-secondary); outline-offset: -3px; } /* ---- The days ----------------------------------------------------------------------------- */ [data-datepicker-grid] { width: calc(100% - 1.5rem); margin-inline: 0.75rem; border-collapse: collapse; table-layout: fixed; } [data-datepicker-grid] th { height: 3rem; padding: 0; color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-lg); letter-spacing: var(--md-sys-typescale-body-lg-tracking); text-align: center; } [data-datepicker-day] { --datepicker-layer: var(--md-sys-color-on-surface-variant); position: relative; height: 3rem; padding: 0; color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-lg); letter-spacing: var(--md-sys-typescale-body-lg-tracking); text-align: center; cursor: pointer; outline: none; isolation: isolate; -webkit-tap-highlight-color: transparent; } [data-datepicker-day] > span { position: relative; display: grid; place-items: center; width: 2.5rem; height: 2.5rem; margin: auto; border-radius: var(--md-sys-shape-corner-full); transition: background-color var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } [data-datepicker-day][data-blank] { cursor: default; } /* A docked picker shows the neighbouring months' days, quieter. */ [data-datepicker-day][data-outside] { color: var(--md-sys-color-on-surface-variant); } [data-datepicker-day][data-today] { --datepicker-layer: var(--md-sys-color-primary); color: var(--md-sys-color-primary); } [data-datepicker-day][data-today] > span { box-shadow: inset 0 0 0 1px var(--md-sys-color-primary); } /* A range's band: secondary-container behind the days between its ends, from the middle of each end. */ [data-datepicker-day][data-between]::before, [data-datepicker-day][data-start]::before, [data-datepicker-day][data-end]::before { content: ""; position: absolute; inset-block: 0.25rem; inset-inline: 0; z-index: -1; background-color: var(--md-sys-color-secondary-container); } [data-datepicker-day][data-start]::before { inset-inline-start: 50%; } [data-datepicker-day][data-end]::before { inset-inline-end: 50%; } [data-datepicker-day][data-between] { --datepicker-layer: var(--md-sys-color-on-secondary-container); color: var(--md-sys-color-on-secondary-container); } [data-datepicker-day][data-selected] { --datepicker-layer: var(--md-sys-color-on-primary); color: var(--md-sys-color-on-primary); } [data-datepicker-day][data-selected] > span { background-color: var(--md-sys-color-primary); box-shadow: none; } [data-datepicker-day][aria-disabled="true"] { color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); cursor: default; } [data-datepicker-day][aria-disabled="true"][data-today] > span { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); } /* ---- The modal year grid ----------------------------------------------------------------- */ [data-datepicker-years] { display: grid; grid-template-columns: repeat(3, 1fr); align-content: start; justify-items: center; row-gap: 1rem; height: 20.9375rem; padding: 0.5rem 0.75rem; overflow-y: auto; overscroll-behavior: contain; border-bottom: 1px solid var(--md-sys-color-outline-variant); } [data-datepicker-year] { --datepicker-layer: var(--md-sys-color-on-surface-variant); position: relative; width: 4.5rem; height: 2.25rem; border-radius: var(--md-sys-shape-corner-full); color: var(--md-sys-color-on-surface-variant); font: var(--md-sys-typescale-body-lg); letter-spacing: var(--md-sys-typescale-body-lg-tracking); cursor: pointer; outline: none; isolation: isolate; scroll-margin-block: 0.5rem; } [data-datepicker-year][data-current] { --datepicker-layer: var(--md-sys-color-primary); color: var(--md-sys-color-primary); box-shadow: inset 0 0 0 1px var(--md-sys-color-primary); } [data-datepicker-year][aria-selected="true"] { --datepicker-layer: var(--md-sys-color-on-primary); background-color: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); box-shadow: none; } /* ---- The docked month and year lists ------------------------------------------------------ */ [data-datepicker-menu] { height: 21.5rem; padding-block: 0.5rem; overflow-y: auto; overscroll-behavior: contain; border-top: 1px solid var(--md-sys-color-outline-variant); } [data-datepicker-option] { --datepicker-layer: var(--md-sys-color-on-surface); position: relative; display: flex; align-items: center; gap: 1rem; width: 100%; height: 3rem; padding-inline: 1rem; color: var(--md-sys-color-on-surface); font: var(--md-sys-typescale-body-lg); letter-spacing: var(--md-sys-typescale-body-lg-tracking); text-align: start; cursor: pointer; outline: none; isolation: isolate; } [data-datepicker-option][aria-selected="true"] { background-color: var(--md-sys-color-surface-container-highest); } [data-datepicker-option][aria-disabled="true"] { color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); cursor: default; } [data-datepicker-check] { color: var(--md-sys-color-on-surface); } [data-datepicker-option]:not([aria-selected="true"]) [data-datepicker-check] { visibility: hidden; } /* ---- The modal input ------------------------------------------------------------------------ */ [data-datepicker-entry] { padding: 0.625rem 1.5rem 1rem; } [data-datepicker-entry-fields][data-range] { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; } /* ---- Cancel and OK ---------------------------------------------------------------------------- */ [data-datepicker-actions] { display: flex; flex: none; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.5rem; padding: 0.25rem 0.375rem 0.5rem 0.75rem; } }