Merge branch 'worktree-agent-a4fc1072037346c95'
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
/*
|
||||
* M3's date pickers — docked, modal and modal input (resources/views/components/datepicker.blade.php).
|
||||
*
|
||||
* One `<dialog>` wears both: 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).
|
||||
* Both are 360px of surface-container-high at elevation 3.
|
||||
* One `<dialog>` 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
|
||||
@@ -13,15 +15,19 @@
|
||||
*
|
||||
* [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 <dialog>; data-presentation="docked" | "modal"
|
||||
* [data-datepicker-picker] the <dialog>; data-presentation="docked" | "modal" | "full"
|
||||
* [data-datepicker-surface]
|
||||
* [data-datepicker-header] modal only: title, headline, switch
|
||||
* [data-datepicker-calendar]
|
||||
* [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
|
||||
* 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
|
||||
@@ -128,6 +134,87 @@
|
||||
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] {
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
* error state's second indicator
|
||||
* .field-outline the fieldset and its legend (the filled field's indicator line)
|
||||
* .field-label the visible label
|
||||
* .field-support the hint, or the error in its place
|
||||
* .field-support-row the row under the field
|
||||
* .field-support the hint, or the error in its place
|
||||
* .field-counter M3's character counter, `n/max`, at the end of that row
|
||||
*
|
||||
* A select's open list is not part of the field: it is the dropdown menu in components/menu.css.
|
||||
*/
|
||||
@@ -40,6 +42,20 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* M3 § Text Fields, Behaviour: "compact breakpoints can let a text field span full width;
|
||||
* medium/expanded should bound it with flexible margins/other containers — never let it span the
|
||||
* full width of a large screen." The site names no number, so 40rem is this package's: it is
|
||||
* under half the `large` class's 1200px, a little over the `expanded` class's half, and holds
|
||||
* about the 70 characters body-large reads best at. It is a ceiling, not a width — a narrower
|
||||
* pane still gets a narrower field. A `max-w-*` class from the call site beats it, because
|
||||
* utilities come after this layer, and `full` takes it off for a field that really is the width
|
||||
* of its pane (a search-and-filter row, an editor). Below `medium` nothing is bounded. */
|
||||
@media (width >= 37.5rem) {
|
||||
.field:not([data-full]) {
|
||||
max-width: 40rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* A filled field's resting indicator line is on-surface-variant, where an outline is outline. */
|
||||
.field[data-variant="filled"] {
|
||||
--field-edge: var(--md-sys-color-on-surface-variant);
|
||||
@@ -450,7 +466,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* The hint or the error, and — when the field has a maximum — M3's character counter at the far
|
||||
end of the same row (specs: "Padding between supporting text and counter | 16dp", which the
|
||||
two paddings between them already make). */
|
||||
.field-support-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.field-support {
|
||||
min-width: 0;
|
||||
padding: 0.25rem var(--field-pad) 0;
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
font: var(--md-sys-typescale-body-sm);
|
||||
@@ -461,6 +486,22 @@
|
||||
color: var(--md-sys-color-error);
|
||||
}
|
||||
|
||||
.field-counter {
|
||||
flex: none;
|
||||
margin-inline-start: auto;
|
||||
padding-block-start: 0.25rem;
|
||||
padding-inline-end: var(--field-pad);
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
font: var(--md-sys-typescale-body-sm);
|
||||
letter-spacing: var(--md-sys-typescale-body-sm-tracking);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Past the maximum the count is an error, and says so in the error colour. */
|
||||
.field-counter[data-over] {
|
||||
color: var(--md-sys-color-error);
|
||||
}
|
||||
|
||||
/* ---- The filled text field ---------------------------------------------------------------- */
|
||||
|
||||
.field[data-variant="filled"] .field-box {
|
||||
|
||||
@@ -15,14 +15,16 @@
|
||||
* `--search-width: 22.5rem` on a wrapper. The leading and trailing padding is 24px unfocused and
|
||||
* 16px focused, as the search specs table gives it.
|
||||
*
|
||||
* [data-search] the root; data-open, data-full-screen
|
||||
* [data-search-scrim] over the page while the view is docked
|
||||
* [data-search-bar] the pill, above the view
|
||||
* [data-search] the root; data-open, data-full-screen, data-trigger
|
||||
* [data-search-scrim] over the page while the view is docked
|
||||
* [data-search-trigger] data-trigger="icon" only: the icon button that expands the view
|
||||
* [data-search-bar] the pill, above the view
|
||||
* [data-search-leading], [data-search-field] (the combobox around [data-search-input]),
|
||||
* [data-search-clear], [data-search-trailing]
|
||||
* [data-search-view] the container behind the bar
|
||||
* [data-search-results]
|
||||
* [data-search-status] the polite live region that counts the results
|
||||
* [data-search-view] the container behind the bar
|
||||
* [data-search-suggestions] before the first keystroke
|
||||
* [data-search-results] once something is typed
|
||||
* [data-search-status] the polite live region that counts whichever list is on screen
|
||||
*/
|
||||
|
||||
@layer components {
|
||||
@@ -204,19 +206,62 @@
|
||||
|
||||
/* M3: the docked container is at least 240px tall — once there is something in it to be tall
|
||||
about; a search with nothing to show stays the height of its bar. */
|
||||
[data-search-view]:has([data-search-results]) {
|
||||
[data-search-view]:has([data-search-results], [data-search-suggestions]) {
|
||||
min-height: 15rem;
|
||||
}
|
||||
|
||||
/* No divider: that belongs to the divided style, which Expressive deprecates in favour of the
|
||||
contained one this file draws. */
|
||||
[data-search-results] {
|
||||
contained one this file draws. The suggestions stand in the same place, before the first
|
||||
keystroke; only one of the two is ever on screen. */
|
||||
[data-search-results],
|
||||
[data-search-suggestions] {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
padding-block: 0.5rem;
|
||||
}
|
||||
|
||||
/* M3's second entry point: search as a secondary action, one icon button that expands into the
|
||||
full-screen view. The root keeps the button's 48px whether the view is open or not, so a
|
||||
toolbar does not shift under it, and the bar is the view's header rather than a resting bar. */
|
||||
[data-search][data-trigger="icon"] {
|
||||
flex: none;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
[data-search-trigger] {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: var(--md-sys-shape-corner-full);
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: background-color var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-search-trigger]:hover {
|
||||
background-color: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 8%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
[data-search-trigger]:focus-visible {
|
||||
background-color: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 10%, transparent);
|
||||
outline: 3px solid var(--md-sys-color-secondary);
|
||||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
[data-search-trigger]:active {
|
||||
background-color: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 10%, transparent);
|
||||
}
|
||||
|
||||
[data-search][data-trigger="icon"]:not([data-open]) [data-search-bar] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Full screen, on a compact window. */
|
||||
[data-search][data-full-screen] [data-search-bar] {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user