Plan step 39 (part 4). With Tailwind gone the Workbench's Vite build still turns every `:dir(rtl)` into a long `:lang()` list (its own CSS minifier, not Tailwind's doing — confirmed by rebuilding and grepping the output). Every RTL mirror rule across the eleven stylesheets that had one now selects `:is([dir='rtl'], [dir='rtl'] *)` instead, matching `:dir(rtl)`'s own specificity (one pseudo-class) and its inherited "this element or a descendant of one carrying the attribute" reach; the built CSS now keeps the selector as written (no `:lang(` or `:dir(` left). RTL browser tests drop the `lang="ar"` workaround the old rewrite needed (ContainmentTest's side-sheet probe, LayoutTest's shared layoutPage() helper) and set only dir="rtl"; CarouselTest's probe already did. Feature tests asserting the selector's literal text (Progress, Overlay, Menu, ListDetail, Icon, Carousel) updated to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
404 lines
14 KiB
CSS
404 lines
14 KiB
CSS
/*
|
|
* <x-slider>: M3 Expressive's slider (resources/views/components/slider.blade.php), drawn over native
|
|
* range inputs by resources/js/slider.js, which places every part with inline `left`, `width` and
|
|
* `border-radius`; this file gives the parts their size, colour and states.
|
|
*
|
|
* From androidx Compose Material 3 at commit 27cf9a7 (Slider.kt, SliderTokens.kt, Apache-2.0) and
|
|
* M3's sliders/specs table: a 4px handle, 2px while pressed or focused and 6px shorter while its
|
|
* focus ring shows (Material Components' m3_slider_focus_ring_thumb_height_decrease); 4px stop
|
|
* indicators and ticks; the active track and the handle in the colour, the inactive track in its
|
|
* container, and a stop, a tick or the inset icon in the "on" colour of the part of the track it
|
|
* sits on. Disabled, the active parts are on-surface at 38% and the inactive track, and the ticks
|
|
* over the active track, at 12% (tokens/state.css). The value label is M3's label container: 44px
|
|
* tall and at least 48px wide in inverse-surface with label-large, 4px above the handle, growing in
|
|
* on the fast effects spring while the handle is pressed or focused (`data-md-value-label="drag"`).
|
|
*
|
|
* Expressive's sizes, by `data-md-size`, as custom properties on the root:
|
|
*
|
|
* size track handle (and the slider across) inset icon
|
|
* xs 16px 44px (the slider 48px) —
|
|
* sm 24px 44px (48px) —
|
|
* md 40px 52px 24px
|
|
* lg 56px 68px 24px
|
|
* xl 96px 108px 32px
|
|
*
|
|
* `data-md-orientation="vertical"` turns the same drawing a quarter inside a size container: the
|
|
* slider is as wide as a horizontal one is tall and 192px long unless the root's height says
|
|
* otherwise; the value label turns back so it reads across, beside the handle. A right-to-left page
|
|
* mirrors a horizontal drawing and turns its label and icon back. Without script the inputs show as
|
|
* native ranges in the colour.
|
|
*
|
|
* [data-md-slider] the root; data-md-size, data-md-color, data-md-value-label,
|
|
* data-md-orientation, data-md-centered
|
|
* [data-md-slider-label]
|
|
* [data-md-slider-control] the element the pointer presses; holds the inputs
|
|
* [data-md-slider-drawing]
|
|
* [data-md-slider-track]
|
|
* [data-md-slider-segment="start|active|end"], [data-md-slider-tick] (data-md-active),
|
|
* [data-md-slider-stop="start|end"], [data-md-slider-icon] (data-md-active)
|
|
* [data-md-slider-handle="start|end"] (data-md-pressed, data-md-focused)
|
|
* [data-md-slider-thumb], [data-md-slider-value-anchor] > [data-md-slider-value]
|
|
* [data-md-slider-input="start|end"]
|
|
* [data-md-slider-hint] | [data-md-slider-errors]
|
|
*/
|
|
|
|
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
|
|
|
@import './icon.css';
|
|
|
|
@layer material.components {
|
|
[data-md-slider] {
|
|
--slider-active: var(--md-sys-color-primary);
|
|
--slider-inactive: var(--md-sys-color-secondary-container);
|
|
--slider-on-active: var(--md-sys-color-on-primary);
|
|
--slider-on-inactive: var(--md-sys-color-on-secondary-container);
|
|
--slider-disabled-active: color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-content-opacity) * 100%), transparent);
|
|
--slider-disabled-inactive: color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-container-opacity) * 100%), transparent);
|
|
--slider-across: 48px;
|
|
--slider-track: 16px;
|
|
--slider-handle: 44px;
|
|
|
|
width: 100%;
|
|
min-width: 0;
|
|
}
|
|
|
|
[data-md-slider][data-md-size='sm'] {
|
|
--slider-track: 24px;
|
|
}
|
|
|
|
[data-md-slider][data-md-size='md'] {
|
|
--slider-across: 52px;
|
|
--slider-track: 40px;
|
|
--slider-handle: 52px;
|
|
}
|
|
|
|
[data-md-slider][data-md-size='lg'] {
|
|
--slider-across: 68px;
|
|
--slider-track: 56px;
|
|
--slider-handle: 68px;
|
|
}
|
|
|
|
[data-md-slider][data-md-size='xl'] {
|
|
--slider-across: 108px;
|
|
--slider-track: 96px;
|
|
--slider-handle: 108px;
|
|
}
|
|
|
|
[data-md-slider][data-md-color='secondary'] {
|
|
--slider-active: var(--md-sys-color-secondary);
|
|
--slider-on-active: var(--md-sys-color-on-secondary);
|
|
}
|
|
|
|
[data-md-slider][data-md-color='tertiary'] {
|
|
--slider-active: var(--md-sys-color-tertiary);
|
|
--slider-inactive: var(--md-sys-color-tertiary-container);
|
|
--slider-on-active: var(--md-sys-color-on-tertiary);
|
|
--slider-on-inactive: var(--md-sys-color-on-tertiary-container);
|
|
}
|
|
|
|
[data-md-slider][data-md-color='error'] {
|
|
--slider-active: var(--md-sys-color-error);
|
|
--slider-inactive: var(--md-sys-color-error-container);
|
|
--slider-on-active: var(--md-sys-color-on-error);
|
|
--slider-on-inactive: var(--md-sys-color-on-error-container);
|
|
}
|
|
|
|
[data-md-slider][data-md-color='success'] {
|
|
--slider-active: var(--md-sys-color-success);
|
|
--slider-inactive: var(--md-sys-color-success-container);
|
|
--slider-on-active: var(--md-sys-color-on-success);
|
|
--slider-on-inactive: var(--md-sys-color-on-success-container);
|
|
}
|
|
|
|
[data-md-slider][data-md-color='warning'] {
|
|
--slider-active: var(--md-sys-color-warning);
|
|
--slider-inactive: var(--md-sys-color-warning-container);
|
|
--slider-on-active: var(--md-sys-color-on-warning);
|
|
--slider-on-inactive: var(--md-sys-color-on-warning-container);
|
|
}
|
|
|
|
[data-md-slider][data-md-color='info'] {
|
|
--slider-active: var(--md-sys-color-info);
|
|
--slider-inactive: var(--md-sys-color-info-container);
|
|
--slider-on-active: var(--md-sys-color-on-info);
|
|
--slider-on-inactive: var(--md-sys-color-on-info-container);
|
|
}
|
|
|
|
/* Disabled: the colours give way to on-surface at M3's disabled opacities. */
|
|
[data-md-slider]:has([data-md-slider-input]:disabled) {
|
|
--slider-active: var(--slider-disabled-active);
|
|
--slider-inactive: var(--slider-disabled-inactive);
|
|
--slider-on-active: var(--slider-disabled-inactive);
|
|
--slider-on-inactive: var(--slider-disabled-active);
|
|
}
|
|
|
|
[data-md-slider][data-md-orientation='vertical'] {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: fit-content;
|
|
}
|
|
|
|
[data-md-slider-label] {
|
|
display: block;
|
|
margin-bottom: var(--md-sys-measurement-space100);
|
|
color: var(--md-sys-color-on-surface-variant);
|
|
font: var(--md-sys-typescale-label-lg);
|
|
letter-spacing: var(--md-sys-typescale-label-lg-tracking);
|
|
font-variation-settings: normal;
|
|
}
|
|
|
|
[data-md-slider-control] {
|
|
position: relative;
|
|
height: var(--slider-across);
|
|
cursor: pointer;
|
|
touch-action: pan-y;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
}
|
|
|
|
[data-md-slider-control]:has(:disabled) {
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Standing up: as wide as a lying slider is tall, 192px long unless the root says otherwise, and
|
|
a size container, which lets the drawing be as long as this is tall. */
|
|
[data-md-slider][data-md-orientation='vertical'] [data-md-slider-control] {
|
|
flex: auto;
|
|
width: var(--slider-across);
|
|
height: 192px;
|
|
min-height: 0;
|
|
container-type: size;
|
|
touch-action: pan-x;
|
|
}
|
|
|
|
/* Room for a label that never hides: half the handle, 4px and the 44px pill — above the track
|
|
lying down, beside it standing up. */
|
|
[data-md-slider][data-md-value-label='always'] [data-md-slider-control] {
|
|
margin-top: var(--md-sys-measurement-space600);
|
|
}
|
|
|
|
[data-md-slider][data-md-value-label='always'][data-md-orientation='vertical'] [data-md-slider-control] {
|
|
margin-top: 0;
|
|
margin-inline-start: var(--md-sys-measurement-space600);
|
|
}
|
|
|
|
[data-md-slider-drawing] {
|
|
position: absolute;
|
|
inset-block: 0;
|
|
inset-inline: var(--md-sys-measurement-space25);
|
|
pointer-events: none;
|
|
|
|
&:is([dir='rtl'], [dir='rtl'] *) {
|
|
scale: -1 1;
|
|
}
|
|
}
|
|
|
|
/* The same drawing, laid out as long as the slider is tall and turned a quarter anticlockwise so
|
|
the value grows upwards. Everything inside it is placed as if the slider were lying down. */
|
|
[data-md-slider][data-md-orientation='vertical'] [data-md-slider-drawing] {
|
|
inset: auto;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: calc(100cqh - var(--md-sys-measurement-space50));
|
|
height: 100cqw;
|
|
translate: -50% -50%;
|
|
rotate: -90deg;
|
|
scale: none;
|
|
}
|
|
|
|
[data-md-slider-track] {
|
|
position: absolute;
|
|
inset-inline: 0;
|
|
top: 50%;
|
|
height: var(--slider-track);
|
|
translate: 0 -50%;
|
|
}
|
|
|
|
[data-md-slider-segment] {
|
|
position: absolute;
|
|
inset-block: 0;
|
|
background-color: var(--slider-inactive);
|
|
}
|
|
|
|
[data-md-slider-segment='active'] {
|
|
background-color: var(--slider-active);
|
|
}
|
|
|
|
:is([data-md-slider-tick], [data-md-slider-stop]) {
|
|
position: absolute;
|
|
top: 50%;
|
|
width: 4px;
|
|
height: 4px;
|
|
translate: -50% -50%;
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
background-color: var(--slider-on-inactive);
|
|
}
|
|
|
|
[data-md-slider-tick][data-md-active] {
|
|
background-color: var(--slider-on-active);
|
|
}
|
|
|
|
/* A disabled icon is on-surface at 38% wherever it sits. */
|
|
[data-md-slider]:has([data-md-slider-input]:disabled) [data-md-slider-icon] {
|
|
color: var(--slider-disabled-active);
|
|
}
|
|
|
|
[data-md-slider-icon] {
|
|
position: absolute;
|
|
top: 50%;
|
|
display: flex;
|
|
translate: 0 -50%;
|
|
color: var(--slider-on-inactive);
|
|
|
|
&[data-md-active] {
|
|
color: var(--slider-on-active);
|
|
}
|
|
|
|
&:is([dir='rtl'], [dir='rtl'] *) {
|
|
scale: -1 1;
|
|
}
|
|
}
|
|
|
|
/* Turned back the quarter the drawing turns, so the glyph stands up. */
|
|
[data-md-slider][data-md-orientation='vertical'] [data-md-slider-icon] {
|
|
rotate: 90deg;
|
|
scale: none;
|
|
}
|
|
|
|
[data-md-slider-handle] {
|
|
position: absolute;
|
|
inset-block: 0;
|
|
width: 0;
|
|
}
|
|
|
|
[data-md-slider-thumb] {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 0;
|
|
width: 4px;
|
|
height: var(--slider-handle);
|
|
translate: -50% -50%;
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
background-color: var(--slider-active);
|
|
outline-offset: 2px;
|
|
transition-property: width, height;
|
|
transition-duration: var(--md-sys-motion-spatial-fast-duration);
|
|
transition-timing-function: var(--md-sys-motion-spatial-fast);
|
|
}
|
|
|
|
:is([data-md-pressed], [data-md-focused]) > [data-md-slider-thumb] {
|
|
width: 2px;
|
|
}
|
|
|
|
[data-md-focused] > [data-md-slider-thumb] {
|
|
height: calc(var(--slider-handle) - 6px);
|
|
outline: 3px solid var(--md-sys-color-secondary);
|
|
}
|
|
|
|
[data-md-slider-value-anchor] {
|
|
position: absolute;
|
|
bottom: calc(50% + var(--slider-handle) / 2 + var(--md-sys-measurement-space50));
|
|
left: 0;
|
|
z-index: 10;
|
|
display: flex;
|
|
justify-content: center;
|
|
translate: -50% 0;
|
|
|
|
&:is([dir='rtl'], [dir='rtl'] *) {
|
|
scale: -1 1;
|
|
}
|
|
}
|
|
|
|
[data-md-slider][data-md-orientation='vertical'] [data-md-slider-value-anchor] {
|
|
scale: none;
|
|
}
|
|
|
|
[data-md-slider-value] {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: var(--md-sys-measurement-space600);
|
|
height: 44px;
|
|
padding-inline: var(--md-sys-measurement-space125);
|
|
border-radius: var(--md-sys-shape-corner-full);
|
|
background-color: var(--md-sys-color-inverse-surface);
|
|
color: var(--md-sys-color-inverse-on-surface);
|
|
font: var(--md-sys-typescale-label-lg);
|
|
letter-spacing: var(--md-sys-typescale-label-lg-tracking);
|
|
font-variation-settings: normal;
|
|
white-space: nowrap;
|
|
transform-origin: bottom;
|
|
transition-property: opacity, scale;
|
|
transition-duration: var(--md-sys-motion-effects-fast-duration);
|
|
transition-timing-function: var(--md-sys-motion-effects-fast);
|
|
}
|
|
|
|
/* Turned back the quarter the drawing turns: the pill lands beside the handle and reads across. */
|
|
[data-md-slider][data-md-orientation='vertical'] [data-md-slider-value] {
|
|
transform-origin: center;
|
|
rotate: 90deg;
|
|
}
|
|
|
|
[data-md-slider][data-md-value-label='drag'] [data-md-slider-value] {
|
|
opacity: 0;
|
|
scale: 0.75;
|
|
}
|
|
|
|
[data-md-slider][data-md-value-label='drag'] :is([data-md-pressed], [data-md-focused]) [data-md-slider-value] {
|
|
opacity: 1;
|
|
scale: 1;
|
|
}
|
|
|
|
[data-md-slider-input] {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
margin: 0;
|
|
appearance: none;
|
|
background: transparent;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
accent-color: var(--slider-active);
|
|
}
|
|
|
|
[data-md-slider-hint],
|
|
[data-md-slider-errors] > p {
|
|
margin-top: var(--md-sys-measurement-space50);
|
|
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-variation-settings: normal;
|
|
}
|
|
|
|
[data-md-slider-errors] > p {
|
|
color: var(--md-sys-color-error);
|
|
}
|
|
|
|
/* Without script there is no drawing: the inputs show as native ranges, one under the other. */
|
|
@media (scripting: none) {
|
|
:is([data-md-slider], [data-md-slider][data-md-orientation]) [data-md-slider-control] {
|
|
height: auto;
|
|
cursor: auto;
|
|
}
|
|
|
|
[data-md-slider-control] > :not(:last-child) {
|
|
margin-block-end: var(--md-sys-measurement-space100);
|
|
}
|
|
|
|
[data-md-slider-drawing] {
|
|
display: none;
|
|
}
|
|
|
|
[data-md-slider-input] {
|
|
position: static;
|
|
display: block;
|
|
width: 100%;
|
|
height: 24px;
|
|
appearance: auto;
|
|
opacity: 1;
|
|
pointer-events: auto;
|
|
}
|
|
}
|
|
}
|