/* * DropdownMenu recipe. * * Soma anchors the Content via the floating layer (Side / Align / * collision avoidance). Eidos paints the surface chrome: panel with * shadow, item hover/focus highlight, indicator slots for * Checkbox/Radio items, muted Separator and GroupHeading. * * [data-dropdown-menu-trigger] → toggle button * [data-dropdown-menu-content] → floating menu panel * [data-dropdown-menu-item] → menuitem row * [data-dropdown-menu-checkbox-item] → menuitemcheckbox row * [data-dropdown-menu-radio-item] → menuitemradio row * [data-dropdown-menu-sub-trigger] → menuitem that opens a submenu * [data-dropdown-menu-sub-content] → nested menu panel * [data-dropdown-menu-group] → semantic grouping wrapper * [data-dropdown-menu-group-heading] → muted group label * [data-dropdown-menu-separator] → 1px divider * [data-dropdown-menu-arrow] → optional anchor pointer * * All highlighted-row visuals share one set of tokens so a fly-out * SubContent reads identically to the root Content. */ /* ── Panel (Content / SubContent) ──────────────────────────────────── */ [data-dropdown-menu-content], [data-dropdown-menu-sub-content] { min-inline-size: var(--dropdown-menu-content-min-width, 12rem); max-block-size: var(--dropdown-menu-content-max-height, min(60vh, 22rem)); overflow-y: auto; padding: var(--dropdown-menu-content-padding, var(--space-1)); border: var(--dropdown-menu-content-border-width, 1px) solid var(--dropdown-menu-content-border-color, var(--color-border-default)); border-radius: var(--dropdown-menu-content-radius, var(--radius-md)); background: var(--dropdown-menu-content-bg, var(--color-surface-overlay)); box-shadow: var(--dropdown-menu-content-shadow, var(--shadow-floating)); font-family: var(--style-label-font-family, var(--font-ui)); font-size: var(--dropdown-menu-content-font-size, var(--font-size-sm)); color: var(--color-content-primary); } [data-dropdown-menu-content]:focus-visible, [data-dropdown-menu-sub-content]:focus-visible { outline: none; } /* ── Item rows ─────────────────────────────────────────────────────── */ [data-dropdown-menu-item], [data-dropdown-menu-checkbox-item], [data-dropdown-menu-radio-item], [data-dropdown-menu-sub-trigger] { display: flex; align-items: center; gap: var(--dropdown-menu-item-gap, var(--space-2)); min-block-size: var(--dropdown-menu-item-height, 2rem); padding-block: var(--dropdown-menu-item-py, var(--space-1)); padding-inline: var(--dropdown-menu-item-px, var(--space-2)); border-radius: var(--dropdown-menu-item-radius, var(--radius-sm)); color: var(--color-content-primary); line-height: var(--leading-ui); cursor: pointer; user-select: none; transition: background var(--duration-fast) var(--ease-default), color var(--duration-fast) var(--ease-default); } [data-dropdown-menu-item]:hover:not([data-disabled]), [data-dropdown-menu-checkbox-item]:hover:not([data-disabled]), [data-dropdown-menu-radio-item]:hover:not([data-disabled]), [data-dropdown-menu-sub-trigger]:hover:not([data-disabled]), [data-dropdown-menu-item]:focus-visible, [data-dropdown-menu-checkbox-item]:focus-visible, [data-dropdown-menu-radio-item]:focus-visible, [data-dropdown-menu-sub-trigger]:focus-visible, [data-dropdown-menu-sub-trigger][data-state='open'] { outline: none; background: var(--dropdown-menu-item-bg-hover, var(--color-primary-element)); color: var(--dropdown-menu-item-fg-hover, var(--color-content-primary)); } [data-dropdown-menu-item][data-disabled], [data-dropdown-menu-checkbox-item][data-disabled], [data-dropdown-menu-radio-item][data-disabled], [data-dropdown-menu-sub-trigger][data-disabled] { cursor: default; opacity: var(--dropdown-menu-item-disabled-opacity, 0.55); } /* Indicator slot for Checkbox/Radio — soma renders the Indicator child * inline. The recipe reserves a leading affordance for the glyph. */ [data-dropdown-menu-checkbox-item], [data-dropdown-menu-radio-item] { padding-inline-start: var(--dropdown-menu-item-indicator-inset, calc(var(--space-2) + 1rem)); position: relative; } [data-dropdown-menu-checkbox-item][data-state='checked']::before, [data-dropdown-menu-radio-item][data-state='checked']::before { content: ''; position: absolute; inset-inline-start: var(--dropdown-menu-item-px, var(--space-2)); inline-size: 0.875rem; block-size: 0.875rem; border-radius: 0.2rem; background: var(--color-primary-solid); mask-image: var(--dropdown-menu-check-mask, none); } [data-dropdown-menu-radio-item][data-state='checked']::before { border-radius: 50%; } /* SubTrigger gets a chevron affordance on the trailing edge. */ [data-dropdown-menu-sub-trigger]::after { content: ''; margin-inline-start: auto; inline-size: 0.625rem; block-size: 0.625rem; border-inline-end: 2px solid currentColor; border-block-start: 2px solid currentColor; transform: rotate(45deg); opacity: 0.65; } /* ── Group / GroupHeading / Separator ─────────────────────────────── */ [data-dropdown-menu-group] { display: contents; } [data-dropdown-menu-group-heading] { padding-block: var(--dropdown-menu-heading-py, var(--space-1)); padding-inline: var(--dropdown-menu-heading-px, var(--space-2)); color: var(--color-content-muted); font-size: var(--dropdown-menu-heading-font-size, var(--font-size-xs)); font-weight: var(--style-label-font-weight, 500); text-transform: uppercase; letter-spacing: 0.04em; /* literal: micro-tracking for caps */ } [data-dropdown-menu-separator] { margin-block: var(--dropdown-menu-separator-my, var(--space-1)); block-size: 1px; background: var(--dropdown-menu-separator-bg, var(--color-border-subtle)); } /* ── Trigger (button-ish, but bring-your-own visual) ──────────────── */ [data-dropdown-menu-trigger] { cursor: pointer; } [data-dropdown-menu-trigger]:focus-visible { outline: none; box-shadow: var(--focus-ring); } /* ── Arrow ────────────────────────────────────────────────────────── */ [data-dropdown-menu-arrow] { fill: var(--dropdown-menu-content-bg, var(--color-surface-overlay)); } /* ── State transitions ────────────────────────────────────────────── */ [data-dropdown-menu-content][data-state='closed'], [data-dropdown-menu-sub-content][data-state='closed'] { opacity: 0; pointer-events: none; } [data-dropdown-menu-content][data-state='open'], [data-dropdown-menu-sub-content][data-state='open'] { animation: dropdown-menu-enter var(--duration-fast) var(--ease-out); } @keyframes dropdown-menu-enter { from { opacity: 0; transform: translateY(-4px) scale(0.97); } to { opacity: 1; transform: none; } }