/* * : M3's assist, filter, input and suggestion chips (resources/views/components/chip.blade.php). * * From androidx Compose Material 3 (Chip.kt, AssistChipTokens, FilterChipTokens, InputChipTokens, * SuggestionChipTokens at androidx/androidx 27cf9a7, Apache-2.0): 32px tall, the small corner, * label-large, 18px icons and a 24px avatar; 16px padding beside a label and 8px beside an icon, * 8px between (an input chip: 12px, 8px, and 4px beside an avatar). Compose draws the 1px border * inside the chip; a CSS border takes room, so every padding beside it is 1px short of its token * (7px for 8, 11px for 12, 15px for 16). * * Colours by type and state, each one role (never an opacity but M3's disabled 12% and 38%, * tokens/state.css): * * flat outline-variant border; on-surface ink (assist) or on-surface-variant (the rest); * the border turns on-surface (assist) or on-surface-variant while keyboard-focused * elevated surface-container-low at elevation 1, 2 on hover, no border (not for input chips) * selected a filter chip that is checked or pressed, an input chip marked `data-md-selected`: * secondary-container with on-secondary-container ink, no border; a flat selected * filter chip rises to elevation 1 on hover * disabled on-surface ink at 38%; the border (flat) or the container (elevated, selected) at 12% * * Leading icons are primary on assist, suggestion and filter chips; on an input chip they are * on-surface-variant, primary on a selected chip and while a chip with its own action is hovered, * focused or pressed (`data-md-actionable`). A trailing icon is primary on assist and suggestion * chips. A disabled chip's icons take its ink. * * The state layer is the chip's own ::before in the chip's ink (an input chip draws it on its * action, since the remove button is a second control), at M3's hover, focus and press opacities; * the focus indicator is the package's secondary ring outside the chip. Both the chip (or an input * chip's action) and the remove button catch presses over 48×48 — M3 lets the target extend beyond * the visible container. The filter chip's check grows in on the fast spatial spring and fades in * on the slow effects one; it shrinks on default effects and fades on fast effects, as * AnimatingChipContent does. * * [data-md-chip="assist|filter|input|suggestion"] the chip; data-md-elevated, data-md-disabled, * data-md-selected, data-md-actionable, * data-md-icon-start, data-md-icon-end, * data-md-avatar, data-md-removable * [data-md-chip-check-slot] a filter chip's check, over its icon when it has one * [data-md-chip-icon], [data-md-chip-check] * [data-md-chip-action] an input chip's own button or link (a without one) * [data-md-chip-avatar], [data-md-chip-icon], [data-md-chip-label] * [data-md-chip-remove] an input chip's remove button * [data-md-chip-label], [data-md-chip-icon], [data-md-chip-trailing] */ @layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; @import './icon.css'; /* TODO(step 36): @import './tooltip.css' once leaves Tailwind (actions stream). */ @layer material.components { [data-md-chip] { --chip-disabled-container: color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-container-opacity) * 100%), transparent); --chip-disabled-ink: color-mix(in srgb, var(--md-sys-color-on-surface) calc(var(--md-sys-state-disabled-content-opacity) * 100%), transparent); position: relative; display: inline-flex; flex-shrink: 0; align-items: center; max-width: 100%; height: 32px; border: 1px solid var(--md-sys-color-outline-variant); border-radius: var(--md-sys-shape-corner-sm); 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; white-space: nowrap; -webkit-user-select: none; user-select: none; transition-property: background-color, border-color, color, box-shadow; transition-duration: var(--md-sys-motion-effects-fast-duration); transition-timing-function: var(--md-sys-motion-effects-fast); } /* ---- Assist, filter and suggestion: the chip is the control ------------------------------ */ [data-md-chip]:not([data-md-chip='input']) { isolation: isolate; padding-inline: 15px; outline: none; cursor: pointer; /* The 48px target, past the chip's 32px. */ &::after { content: ''; position: absolute; inset-inline: 0; top: 50%; height: var(--md-sys-measurement-space600); translate: 0 -50%; } &::before { content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background-color: currentColor; opacity: 0; pointer-events: none; transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } @media (hover: hover) { &:hover::before { opacity: var(--md-sys-state-hover-state-layer-opacity); } } &:focus-visible::before, &:has(:focus-visible)::before { opacity: var(--md-sys-state-focus-state-layer-opacity); } &:active::before { opacity: var(--md-sys-state-pressed-state-layer-opacity); } &:is(:focus-visible, :has(:focus-visible)) { outline: 3px solid var(--md-sys-color-secondary); outline-offset: 2px; } &:is(:disabled, [aria-disabled='true'], [data-md-disabled])::before { display: none; } } [data-md-chip]:is([data-md-chip='filter'], [data-md-icon-start]):not([data-md-chip='input']) { padding-inline-start: 7px; } [data-md-chip][data-md-icon-end] { padding-inline-end: 7px; } [data-md-chip='assist'] { color: var(--md-sys-color-on-surface); } [data-md-chip='assist']:not([data-md-elevated], [data-md-disabled]):focus-visible { border-color: var(--md-sys-color-on-surface); } :is([data-md-chip='suggestion'], [data-md-chip='filter']):not([data-md-elevated], [data-md-disabled], :has(:checked), [aria-pressed='true']):is(:focus-visible, :has(:focus-visible)) { border-color: var(--md-sys-color-on-surface-variant); } [data-md-chip][data-md-elevated] { border-color: transparent; background-color: var(--md-sys-color-surface-container-low); box-shadow: var(--md-sys-elevation-1); } @media (hover: hover) { [data-md-chip][data-md-elevated]:not([data-md-disabled]):hover { box-shadow: var(--md-sys-elevation-2); } } /* Selected: a checked filter chip, or a pressed one. */ [data-md-chip='filter']:is(:has(:checked), [aria-pressed='true']), [data-md-chip='input'][data-md-selected] { border-color: transparent; background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); } @media (hover: hover) { [data-md-chip='filter']:not([data-md-elevated], [data-md-disabled]):is(:has(:checked), [aria-pressed='true']):hover { box-shadow: var(--md-sys-elevation-1); } } [data-md-chip][data-md-disabled] { border-color: var(--chip-disabled-container); color: var(--chip-disabled-ink); box-shadow: none; } [data-md-chip][data-md-disabled]:is([data-md-elevated], [data-md-selected], :has(:checked), [aria-pressed='true']) { border-color: transparent; background-color: var(--chip-disabled-container); } [data-md-chip][data-md-disabled]:not(a) { cursor: not-allowed; } /* A disabled link leaves the pointer too. */ a[data-md-chip][aria-disabled='true'] { pointer-events: none; } /* ---- Contents ------------------------------------------------------------------------------ */ [data-md-chip-label] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } :is([data-md-chip], [data-md-chip-action]) > [data-md-chip-icon] { margin-inline-end: var(--md-sys-measurement-space100); } [data-md-chip-trailing] { margin-inline-start: var(--md-sys-measurement-space100); } [data-md-chip]:not([data-md-chip='input'], [data-md-disabled]) [data-md-chip-icon], [data-md-chip='input'][data-md-selected]:not([data-md-disabled]) [data-md-chip-icon], :is([data-md-chip='assist'], [data-md-chip='suggestion']):not([data-md-disabled]) [data-md-chip-trailing] { color: var(--md-sys-color-primary); } [data-md-chip][data-md-actionable] [data-md-chip-icon] { transition: color var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } [data-md-chip][data-md-actionable]:is(:active, :has(:focus-visible)) [data-md-chip-icon] { color: var(--md-sys-color-primary); } @media (hover: hover) { [data-md-chip][data-md-actionable]:hover [data-md-chip-icon] { color: var(--md-sys-color-primary); } } /* The filter chip's check: from nothing to 18px as it is selected, or over the icon it replaces. */ [data-md-chip-check-slot] { display: grid; flex-shrink: 0; width: 0; height: 18px; margin-inline-end: var(--md-sys-measurement-space100); overflow: hidden; transition: width var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default); } [data-md-chip-check-slot] > * { grid-area: 1 / 1; } [data-md-chip-check-slot]:has([data-md-chip-icon]) { width: 18px; transition: none; } [data-md-chip]:is(:has(:checked), [aria-pressed='true']) [data-md-chip-check-slot]:not(:has([data-md-chip-icon])) { width: 18px; transition-duration: var(--md-sys-motion-spatial-fast-duration); transition-timing-function: var(--md-sys-motion-spatial-fast); } [data-md-chip-check-slot] [data-md-chip-icon] { transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } [data-md-chip-check] { opacity: 0; transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } [data-md-chip]:is(:has(:checked), [aria-pressed='true']) [data-md-chip-check-slot] [data-md-chip-icon] { opacity: 0; } [data-md-chip]:is(:has(:checked), [aria-pressed='true']) [data-md-chip-check] { opacity: 1; transition-duration: var(--md-sys-motion-effects-slow-duration); transition-timing-function: var(--md-sys-motion-effects-slow); } /* ---- Input chips: an action of their own, and a remove button ---------------------------- */ [data-md-chip='input'] { isolation: isolate; } [data-md-chip='input']:not([data-md-selected], [data-md-disabled]):has([data-md-chip-action]:focus-visible) { border-color: var(--md-sys-color-on-surface-variant); } [data-md-chip='input']:has([data-md-chip-action]:focus-visible) { outline: 3px solid var(--md-sys-color-secondary); outline-offset: 2px; } [data-md-chip-action] { display: flex; align-items: center; min-width: 0; height: 100%; padding-inline: 11px; outline: none; } [data-md-chip][data-md-icon-start] [data-md-chip-action] { padding-inline-start: 7px; } [data-md-chip][data-md-avatar] [data-md-chip-action] { padding-inline-start: 3px; } [data-md-chip][data-md-removable] [data-md-chip-action] { padding-inline-end: var(--md-sys-measurement-space100); } :is(a, button)[data-md-chip-action] { cursor: pointer; /* The 48px target and the state layer, across the whole chip. */ &::after { content: ''; position: absolute; inset-inline: 0; top: 50%; height: var(--md-sys-measurement-space600); translate: 0 -50%; } } [data-md-chip]:not([data-md-disabled]) :is(a, button)[data-md-chip-action] { &::before { content: ''; position: absolute; inset: -1px; z-index: -1; border-radius: var(--md-sys-shape-corner-sm); background-color: currentColor; opacity: 0; transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } @media (hover: hover) { &:hover::before { opacity: var(--md-sys-state-hover-state-layer-opacity); } } &:focus-visible::before { opacity: var(--md-sys-state-focus-state-layer-opacity); } &:active::before { opacity: var(--md-sys-state-pressed-state-layer-opacity); } } [data-md-chip][data-md-disabled] :is(a, button)[data-md-chip-action] { cursor: not-allowed; } [data-md-chip][data-md-disabled] a[data-md-chip-action] { pointer-events: none; } [data-md-chip-avatar] { flex-shrink: 0; width: 24px; height: 24px; margin-inline-end: var(--md-sys-measurement-space100); border-radius: var(--md-sys-shape-corner-full); } span[data-md-chip-avatar] { display: grid; place-items: center; background-color: var(--md-sys-color-primary-container); color: var(--md-sys-color-on-primary-container); font: var(--md-sys-typescale-label-sm); letter-spacing: var(--md-sys-typescale-label-sm-tracking); font-variation-settings: normal; } img[data-md-chip-avatar] { object-fit: cover; } [data-md-chip][data-md-disabled] [data-md-chip-avatar] { opacity: var(--md-sys-state-disabled-content-opacity); } /* An 18px icon in a 24px state layer, catching presses 15px out on every side: M3's 48px. */ [data-md-chip-remove] { position: relative; display: grid; flex-shrink: 0; place-items: center; width: 18px; height: 18px; margin-inline-end: 7px; border-radius: var(--md-sys-shape-corner-full); outline: none; cursor: pointer; &::after { content: ''; position: absolute; inset: -15px; } &:disabled { cursor: not-allowed; } &:not(:disabled) { &::before { content: ''; position: absolute; inset: -3px; border-radius: var(--md-sys-shape-corner-full); background-color: currentColor; opacity: 0; transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast); } @media (hover: hover) { &:hover::before { opacity: var(--md-sys-state-hover-state-layer-opacity); } } &:focus-visible { outline: 3px solid var(--md-sys-color-secondary); outline-offset: 2px; } &:focus-visible::before { opacity: var(--md-sys-state-focus-state-layer-opacity); } &:active::before { opacity: var(--md-sys-state-pressed-state-layer-opacity); } } } }