/* * : 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; } } }