diff --git a/src/components/library/molecules/Dropdown/Dropdown.module.scss b/src/components/library/molecules/Dropdown/Dropdown.module.scss index 6ae6fdc6..283cac88 100644 --- a/src/components/library/molecules/Dropdown/Dropdown.module.scss +++ b/src/components/library/molecules/Dropdown/Dropdown.module.scss @@ -42,6 +42,12 @@ .text { flex: 1; + // The trigger is a fixed-height row, so a long selected label has to + // truncate — wrapping would spill out of the bottom of the control. + min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; text-align: left; } @@ -98,6 +104,12 @@ position: fixed; right: auto; z-index: 1500; + // `.menu` is `width: 100%`, which under `position: fixed` resolves against + // the viewport. Size to the longest option instead; the inline min-width + // keeps the menu at least as wide as the trigger (compact pill triggers + // would otherwise crush option labels into a one-word-per-line column) and + // the inline max-width keeps it inside the viewport. + width: max-content; } .optionWrapper { @@ -138,6 +150,14 @@ } } +// Shelf and library names can be a single long token ("Crime/Detective"), and +// the menu is `overflow: visible` so an unbroken one paints over whatever sits +// behind the dropdown. Break it instead. +.optionLabel { + min-width: 0; + overflow-wrap: anywhere; +} + .subArrow { flex-shrink: 0; transform: rotate(0deg); diff --git a/src/components/library/molecules/Dropdown/Dropdown.tsx b/src/components/library/molecules/Dropdown/Dropdown.tsx index 80330446..647272b1 100644 --- a/src/components/library/molecules/Dropdown/Dropdown.tsx +++ b/src/components/library/molecules/Dropdown/Dropdown.tsx @@ -112,7 +112,11 @@ export function Dropdown(props: DropdownProps): JSX.Element { ? { top: menuPos.top, left: menuPos.left, - width: menuPos.width, + // Never narrower than the trigger, never wider than the room + // left of the viewport's right edge, and capped so a long shelf + // name can't stretch the menu across the whole screen. + minWidth: menuPos.width, + maxWidth: `min(320px, calc(100vw - ${menuPos.left + 8}px))`, transform: menuPos.placement === 'top' ? 'translateY(-100%)' : undefined, } @@ -167,7 +171,12 @@ export function Dropdown(props: DropdownProps): JSX.Element { ) : ( - {option.label} + + {option.label} + )} {hasSubOptions ? ( handleSubSelect(sub.value))} aria-label={`Select ${sub.label}`} > - + {sub.label} {value === sub.value && ( diff --git a/src/components/library/organisms/ObjectOverviewModal/ObjectOverviewModal.module.scss b/src/components/library/organisms/ObjectOverviewModal/ObjectOverviewModal.module.scss index 6469c808..4bdc0fb5 100644 --- a/src/components/library/organisms/ObjectOverviewModal/ObjectOverviewModal.module.scss +++ b/src/components/library/organisms/ObjectOverviewModal/ObjectOverviewModal.module.scss @@ -363,6 +363,9 @@ // the Shelf settings-trigger override). Compact pill, not a full-width field. .moveToTrigger { width: fit-content !important; + // The pill hugs its label, so a long shelf name would push it past the + // modal's edge; cap it and let the trigger's own ellipsis do the rest. + max-width: 100%; padding: 7px 12px !important; background: var(--white) !important; border: 1px solid var(--beige) !important;