/* * : an M3 Expressive FAB that opens into a short list of related actions. * * FabMenuBaselineTokens (androidx Compose Material 3, Apache-2.0): the trigger is a 56px FAB, * `data-md-color`'s container, large corner, elevation 3, rising to elevation 4 under a hovering * pointer; while its list is open (`aria-expanded`) it turns fully round and paints the colour * itself, on the default spatial and effects springs (ACT-19 splits the two). The list sits * `data-md-position`'s corner of the trigger, 8px padding — the room the close button keeps below * the first item — and scrolls past `calc(100dvh - 128px)` on a short window, behind the close * button, which stays fixed (ACT-32). * * The items (fab-menu-item.css) rise into place as the list opens and sink back as it closes: the * entry is `@starting-style` on the item itself; the exit needs the state to be readable while the * popover is on its way out, which `[data-md-fab-menu-popover]:not(:popover-open) > *` is — the * popover keeps `display: flex` for the length of its own discrete transition, so the items have * somewhere to animate to (ACT-33). The Tailwind-era rule sat outside the layers to beat the * item's utilities; inside the layer it still beats fab-menu-item.css's resting `translate: 0 0` * and `opacity: 1`, on specificity — an attribute and a pseudo-class against the item's one * attribute — whichever order the two files are bundled in. */ @layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; @import './icon.css'; @layer material.components { [data-md-fab-menu] { position: relative; display: inline-flex; } [data-md-fab-menu-anchor] { display: inline-flex; } [data-md-fab-menu-trigger] { --md-fab-menu-container: var(--md-sys-color-primary-container); --md-fab-menu-on-container: var(--md-sys-color-on-primary-container); --md-fab-menu-color: var(--md-sys-color-primary); --md-fab-menu-on-color: var(--md-sys-color-on-primary); position: relative; isolation: isolate; display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; inline-size: var(--md-sys-measurement-space700); block-size: var(--md-sys-measurement-space700); border-radius: var(--md-sys-shape-corner-lg); background-color: var(--md-fab-menu-container); color: var(--md-fab-menu-on-container); box-shadow: var(--md-sys-elevation-3); cursor: pointer; outline: none; -webkit-user-select: none; user-select: none; transition-property: border-radius, background-color, color, box-shadow; transition-duration: var(--md-sys-motion-spatial-default-duration), var(--md-sys-motion-effects-default-duration), var(--md-sys-motion-effects-default-duration), var(--md-sys-motion-effects-default-duration); transition-timing-function: var(--md-sys-motion-spatial-default), var(--md-sys-motion-effects-default), var(--md-sys-motion-effects-default), var(--md-sys-motion-effects-default); &::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 { box-shadow: var(--md-sys-elevation-4); } &: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); } &[aria-expanded='true'] { border-radius: var(--md-sys-shape-corner-full); background-color: var(--md-fab-menu-color); color: var(--md-fab-menu-on-color); } } [data-md-fab-menu-trigger][data-md-color='secondary'] { --md-fab-menu-container: var(--md-sys-color-secondary-container); --md-fab-menu-on-container: var(--md-sys-color-on-secondary-container); --md-fab-menu-color: var(--md-sys-color-secondary); --md-fab-menu-on-color: var(--md-sys-color-on-secondary); } [data-md-fab-menu-trigger][data-md-color='tertiary'] { --md-fab-menu-container: var(--md-sys-color-tertiary-container); --md-fab-menu-on-container: var(--md-sys-color-on-tertiary-container); --md-fab-menu-color: var(--md-sys-color-tertiary); --md-fab-menu-on-color: var(--md-sys-color-on-tertiary); } [data-md-fab-menu-close-icon] { display: none; } [data-md-fab-menu-trigger][aria-expanded='true'] [data-md-fab-menu-icon] { display: none; } [data-md-fab-menu-trigger][aria-expanded='true'] [data-md-fab-menu-close-icon] { display: inline-flex; } [data-md-fab-menu-popover] { inset: auto; margin: 0; display: none; flex-direction: column; gap: var(--md-sys-measurement-space50); max-block-size: calc(100dvh - 128px); overflow-y: auto; border-width: 0; background-color: transparent; padding: var(--md-sys-measurement-space100); transition-property: display, overlay; transition-duration: var(--md-sys-motion-spatial-fast-duration); transition-behavior: allow-discrete; &:popover-open { display: flex; } } [data-md-fab-menu-popover][data-md-position='top-end'] { margin-inline: calc(-1 * var(--md-sys-measurement-space100)); margin-block-start: calc(-1 * var(--md-sys-measurement-space100)); align-items: flex-end; position-area: top span-left; } [data-md-fab-menu-popover][data-md-position='top-start'] { margin-inline: calc(-1 * var(--md-sys-measurement-space100)); margin-block-start: calc(-1 * var(--md-sys-measurement-space100)); align-items: flex-start; position-area: top span-right; } [data-md-fab-menu-popover][data-md-position='bottom-end'] { margin-inline: calc(-1 * var(--md-sys-measurement-space100)); margin-block-end: calc(-1 * var(--md-sys-measurement-space100)); align-items: flex-end; position-area: bottom span-left; } [data-md-fab-menu-popover][data-md-position='bottom-start'] { margin-inline: calc(-1 * var(--md-sys-measurement-space100)); margin-block-end: calc(-1 * var(--md-sys-measurement-space100)); align-items: flex-start; position-area: bottom span-right; } [data-md-fab-menu-popover]:not(:popover-open) > * { translate: 0 var(--md-sys-measurement-space100); opacity: 0; } }