Files
livewire-material/resources/css/components/search.css
T
Andreas Reinhold / reiniandClaude Opus 5 53bb000425 Let an application replace the safe-area insets and dock on the bottom bar
Components read the device's safe-area insets straight from env(), which a
browser test cannot fake and an application drawing its own status strip
cannot extend. Every inset the package reads, in its CSS and its views, is
now var(--material-safe-top|bottom|left|right, env(safe-area-inset-…)):
unchanged while the variables are unset.

The app shell's --material-bottom-bar also adds
var(--material-bottom-extra, 0px), so an application that docks something on
the phone's navigation bar (an offline banner) sets its height once and the
snackbar, a fab button and the page's bottom padding clear it.

A guard test fails on any env(safe-area-inset-*) outside such a variable, and
AppShellTest's assertion on the bar height's class follows the new value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHoXZSHc8gGpZjFmA5fPc2
2026-09-13 18:03:20 +02:00

183 lines
5.7 KiB
CSS

/*
* M3's search: a search bar that opens into a search view (SearchBarTokens, SearchViewTokens,
* androidx Compose Material 3, Apache-2.0).
*
* The bar is a 56px pill in surface-container-high: a leading search icon, the input in
* body-large, a clear button once something is typed, and whatever the caller trails it with (an
* avatar, an icon button). Focus opens the view. On a medium or wider window the view is docked:
* the bar grows down into an extra-large-cornered container at elevation 3 that holds the
* results. On a compact window it takes the whole screen, and the search icon turns into a back
* arrow. `docked` keeps it docked at every width.
*
* [data-search] the root; data-open, data-full-screen
* [data-search-bar] the pill, above the view
* [data-search-leading], [data-search-input], [data-search-clear], [data-search-trailing]
* [data-search-view] the container behind the bar
* [data-search-results]
*/
@layer components {
[data-search] {
--search-height: 3.5rem;
}
[data-search][data-open] {
z-index: 50;
}
[data-search-bar] {
position: relative;
z-index: 1;
display: flex;
align-items: center;
gap: 0.25rem;
height: var(--search-height);
padding-inline: 0.25rem;
border-radius: var(--md-sys-shape-corner-full);
background-color: var(--md-sys-color-surface-container-high);
color: var(--md-sys-color-on-surface);
cursor: text;
transition: background-color var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
}
@media (hover: hover) {
[data-search]:not([data-open]) [data-search-bar]:hover {
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, var(--md-sys-color-surface-container-high));
}
}
[data-search][data-open] [data-search-bar] {
background-color: transparent;
}
[data-search-leading],
[data-search-clear] {
display: grid;
flex: none;
place-items: center;
width: 3rem;
height: 3rem;
border-radius: var(--md-sys-shape-corner-full);
}
[data-search-leading] {
color: var(--md-sys-color-on-surface);
}
[data-search-clear] {
color: var(--md-sys-color-on-surface-variant);
cursor: pointer;
}
[data-search-bar] button {
outline: none;
transition: background-color var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
}
@media (hover: hover) {
[data-search-bar] button:hover {
background-color: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 8%, transparent);
}
}
[data-search-bar] button: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-input] {
flex: 1 1 0%;
min-width: 0;
height: 100%;
padding-inline: 0.25rem;
appearance: none;
background: transparent;
color: var(--md-sys-color-on-surface);
caret-color: var(--md-sys-color-primary);
outline: none;
font: var(--md-sys-typescale-body-lg);
letter-spacing: var(--md-sys-typescale-body-lg-tracking);
}
[data-search-input]::placeholder {
color: var(--md-sys-color-on-surface-variant);
opacity: 1;
}
[data-search-input]::-webkit-search-cancel-button,
[data-search-input]::-webkit-search-decoration {
appearance: none;
display: none;
}
[data-search-bar]:has([data-search-input]:placeholder-shown) [data-search-clear] {
display: none;
}
[data-search-trailing] {
display: flex;
flex: none;
align-items: center;
gap: 0.25rem;
padding-inline-end: 0.25rem;
}
[data-search][data-open] [data-search-trailing] {
display: none;
}
[data-search-view] {
position: absolute;
inset-inline: 0;
top: 0;
display: flex;
flex-direction: column;
max-height: min(40rem, 70dvh);
padding-top: var(--search-height);
overflow: hidden;
border-radius: var(--md-sys-shape-corner-xl);
background-color: var(--md-sys-color-surface-container-high);
box-shadow: var(--md-sys-elevation-3);
transform-origin: top;
transition-property: opacity, scale, display;
transition-duration: var(--md-sys-motion-spatial-fast-duration);
transition-timing-function: var(--md-sys-motion-spatial-fast);
transition-behavior: allow-discrete;
}
@starting-style {
[data-search-view] {
opacity: 0;
scale: 1 0.9;
}
}
[data-search-results] {
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
border-top: 1px solid var(--md-sys-color-outline);
padding-block: 0.5rem;
}
/* Full screen, on a compact window. */
[data-search][data-full-screen] [data-search-bar] {
position: fixed;
inset: 0 0 auto;
height: calc(4.5rem + var(--material-safe-top, env(safe-area-inset-top)));
padding-top: var(--material-safe-top, env(safe-area-inset-top));
padding-inline: 0.25rem;
border-radius: 0;
}
[data-search][data-full-screen] [data-search-view] {
position: fixed;
inset: 0;
max-height: none;
padding-top: calc(4.5rem + var(--material-safe-top, env(safe-area-inset-top)));
border-radius: 0;
box-shadow: none;
}
}