From d9c1d28a7d6374c62f3d2d1d6a28032620fb922e Mon Sep 17 00:00:00 2001 From: Josh Black Date: Tue, 9 Jun 2026 13:30:10 -0500 Subject: [PATCH 1/2] feat: add CSS Layers to 10-overlay-consumers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/css-layers-overlay-consumers.md | 5 + .../react/src/ActionBar/ActionBar.module.css | 178 +++--- .../src/ActionMenu/ActionMenu.module.css | 96 +-- .../AnchoredOverlay.module.css | 244 ++++---- .../Autocomplete/AutocompleteMenu.module.css | 16 +- .../AutocompleteOverlay.module.css | 6 +- packages/react/src/Banner/Banner.module.css | 400 ++++++------ .../src/Blankslate/Blankslate.module.css | 214 +++---- .../src/Breadcrumbs/Breadcrumbs.module.css | 254 ++++---- packages/react/src/Dialog/Dialog.module.css | 568 +++++++++--------- .../react/src/__tests__/css-layers.test.ts | 11 + .../src/deprecated/DialogV1/Dialog.module.css | 120 ++-- .../SelectPanel2/SelectPanel.module.css | 466 +++++++------- 13 files changed, 1308 insertions(+), 1270 deletions(-) create mode 100644 .changeset/css-layers-overlay-consumers.md diff --git a/.changeset/css-layers-overlay-consumers.md b/.changeset/css-layers-overlay-consumers.md new file mode 100644 index 00000000000..509970ce935 --- /dev/null +++ b/.changeset/css-layers-overlay-consumers.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +AnchoredOverlay, Autocomplete, Banner, Blankslate, Breadcrumbs, Dialog, ActionMenu, ActionBar, SelectPanel2: Improve custom class override behavior for component styles diff --git a/packages/react/src/ActionBar/ActionBar.module.css b/packages/react/src/ActionBar/ActionBar.module.css index 8f625d29130..8fddfc0fcd0 100644 --- a/packages/react/src/ActionBar/ActionBar.module.css +++ b/packages/react/src/ActionBar/ActionBar.module.css @@ -1,110 +1,112 @@ -.List { - position: relative; - display: flex; - min-width: 0; - - /* wonder why this is here */ - /* stylelint-disable-next-line primer/spacing */ - margin-bottom: -1px; - list-style: none; - align-items: flex-start; - gap: var(--actionbar-gap, var(--stack-gap-condensed)); - overflow: hidden; - /* Explicit height is required to clip wrapped items */ - height: var(--actionbar-height, var(--control-small-size)); - - /* Scroll-based animations have no effect unless the container is scrollable (has overflow, even with overflow:hidden) - so we can use them to detect overflow. It would be cleaner to use scroll-state container queries for this, but - browser support for scroll-driven animations is slightly better. */ - animation: detect-overflow linear; - animation-timeline: scroll(self block); - - /* After initial render, JS is used to control visibility which provides progressive enhancement for unsupported browsers */ - &[data-has-overflow='true'] { - --morebutton-display: flex; - } +@layer primer.components.ActionBar { + .List { + position: relative; + display: flex; + min-width: 0; - &:where([data-size='small']) { - --actionbar-height: var(--control-small-size); - } + /* wonder why this is here */ + /* stylelint-disable-next-line primer/spacing */ + margin-bottom: -1px; + list-style: none; + align-items: flex-start; + gap: var(--actionbar-gap, var(--stack-gap-condensed)); + overflow: hidden; + /* Explicit height is required to clip wrapped items */ + height: var(--actionbar-height, var(--control-small-size)); + + /* Scroll-based animations have no effect unless the container is scrollable (has overflow, even with overflow:hidden) + so we can use them to detect overflow. It would be cleaner to use scroll-state container queries for this, but + browser support for scroll-driven animations is slightly better. */ + animation: detect-overflow linear; + animation-timeline: scroll(self block); + + /* After initial render, JS is used to control visibility which provides progressive enhancement for unsupported browsers */ + &[data-has-overflow='true'] { + --morebutton-display: flex; + } - &:where([data-size='medium']) { - --actionbar-height: var(--control-medium-size); - } + &:where([data-size='small']) { + --actionbar-height: var(--control-small-size); + } - &:where([data-size='large']) { - --actionbar-height: var(--control-large-size); - } + &:where([data-size='medium']) { + --actionbar-height: var(--control-medium-size); + } + + &:where([data-size='large']) { + --actionbar-height: var(--control-large-size); + } - /* Gap scale (mirrors Stack) */ - &:where([data-gap='none']) { - --actionbar-gap: 0; + /* Gap scale (mirrors Stack) */ + &:where([data-gap='none']) { + --actionbar-gap: 0; - .Divider { - padding: 0 var(--base-size-8); + .Divider { + padding: 0 var(--base-size-8); + } } - } - &:where([data-gap='condensed']) { - --actionbar-gap: var(--stack-gap-condensed); - } + &:where([data-gap='condensed']) { + --actionbar-gap: var(--stack-gap-condensed); + } - & [data-overflowing] { - /* Hide overflowing items. Even though they are clipped by `overflow: hidden`, setting `visibility: hidden` ensures - they can't accidentally be shown and also hides them from screen readers / keyboard nav. `!important` prevents - consumers from unintentionally overriding this and breaking accessibility. */ - visibility: hidden !important; + & [data-overflowing] { + /* Hide overflowing items. Even though they are clipped by `overflow: hidden`, setting `visibility: hidden` ensures + they can't accidentally be shown and also hides them from screen readers / keyboard nav. `!important` prevents + consumers from unintentionally overriding this and breaking accessibility. */ + visibility: hidden !important; + } } -} -@keyframes detect-overflow { - 0%, - 100% { - --morebutton-display: flex; + @keyframes detect-overflow { + 0%, + 100% { + --morebutton-display: flex; + } } -} -.Nav { - display: flex; - padding-inline: var(--base-size-16); - justify-content: flex-end; - align-items: center; + .Nav { + display: flex; + padding-inline: var(--base-size-16); + justify-content: flex-end; + align-items: center; - &:where([data-flush='true']) { - padding-inline: 0; + &:where([data-flush='true']) { + padding-inline: 0; + } } -} -.Divider { - &::before { - display: block; - width: var(--borderWidth-thin); - height: var(--base-size-20); - content: ''; - /* stylelint-disable-next-line primer/colors */ - background: var(--borderColor-muted); - /* stylelint-disable-next-line primer/spacing */ - margin-top: calc((var(--actionbar-height) - var(--base-size-20)) / 2); + .Divider { + &::before { + display: block; + width: var(--borderWidth-thin); + height: var(--base-size-20); + content: ''; + /* stylelint-disable-next-line primer/colors */ + background: var(--borderColor-muted); + /* stylelint-disable-next-line primer/spacing */ + margin-top: calc((var(--actionbar-height) - var(--base-size-20)) / 2); + } } -} -.Group { - display: flex; - gap: inherit; -} + .Group { + display: flex; + gap: inherit; + } -.OverflowContainer { - display: flex; - flex-wrap: wrap; - gap: inherit; - justify-content: flex-end; - overflow: hidden; + .OverflowContainer { + display: flex; + flex-wrap: wrap; + gap: inherit; + justify-content: flex-end; + overflow: hidden; - .OverflowSpacer { - height: var(--actionbar-height); + .OverflowSpacer { + height: var(--actionbar-height); + } } -} -.MoreButton { - display: var(--morebutton-display, none); + .MoreButton { + display: var(--morebutton-display, none); + } } diff --git a/packages/react/src/ActionMenu/ActionMenu.module.css b/packages/react/src/ActionMenu/ActionMenu.module.css index 5b6780562d5..862a4b5789b 100644 --- a/packages/react/src/ActionMenu/ActionMenu.module.css +++ b/packages/react/src/ActionMenu/ActionMenu.module.css @@ -1,70 +1,72 @@ -.ActionMenuContainer { - /* add default max height */ - max-height: 100vh; +@layer primer.components.ActionMenu { + .ActionMenuContainer { + /* add default max height */ + max-height: 100vh; - &:where([data-variant='fullscreen']) { - padding-top: var(--base-size-36); - } + &:where([data-variant='fullscreen']) { + padding-top: var(--base-size-36); + } - /* Overflow variants */ - &:where([data-overflow-auto]) { - overflow: auto; - } + /* Overflow variants */ + &:where([data-overflow-auto]) { + overflow: auto; + } - &:where([data-overflow-hidden]) { - overflow: hidden; - } + &:where([data-overflow-hidden]) { + overflow: hidden; + } - &:where([data-overflow-scroll]) { - overflow: scroll; - } + &:where([data-overflow-scroll]) { + overflow: scroll; + } - &:where([data-overflow-visible]) { - overflow: visible; - } + &:where([data-overflow-visible]) { + overflow: visible; + } - /* Max-height size tokens (mirror Overlay sizes) */ - &:where([data-max-height-xsmall]) { - max-height: min(192px, 100vh); + /* Max-height size tokens (mirror Overlay sizes) */ + &:where([data-max-height-xsmall]) { + max-height: min(192px, 100vh); - @supports (height: 100dvh) { - max-height: min(192px, 100dvh); + @supports (height: 100dvh) { + max-height: min(192px, 100dvh); + } } - } - &:where([data-max-height-small]) { - max-height: min(256px, 100vh); + &:where([data-max-height-small]) { + max-height: min(256px, 100vh); - @supports (height: 100dvh) { - max-height: min(256px, 100dvh); + @supports (height: 100dvh) { + max-height: min(256px, 100dvh); + } } - } - &:where([data-max-height-medium]) { - max-height: min(320px, 100vh); + &:where([data-max-height-medium]) { + max-height: min(320px, 100vh); - @supports (height: 100dvh) { - max-height: min(320px, 100dvh); + @supports (height: 100dvh) { + max-height: min(320px, 100dvh); + } } - } - &:where([data-max-height-large]) { - max-height: min(432px, 100vh); + &:where([data-max-height-large]) { + max-height: min(432px, 100vh); - @supports (height: 100dvh) { - max-height: min(432px, 100dvh); + @supports (height: 100dvh) { + max-height: min(432px, 100dvh); + } } - } - &:where([data-max-height-xlarge]) { - max-height: min(600px, 100vh); + &:where([data-max-height-xlarge]) { + max-height: min(600px, 100vh); - @supports (height: 100dvh) { - max-height: min(600px, 100dvh); + @supports (height: 100dvh) { + max-height: min(600px, 100dvh); + } } - } - &:where([data-max-height-fit-content]) { - max-height: fit-content; + &:where([data-max-height-fit-content]) { + max-height: fit-content; + } } } diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.module.css b/packages/react/src/AnchoredOverlay/AnchoredOverlay.module.css index f8f2c11f075..97834c7f274 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.module.css +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.module.css @@ -1,151 +1,153 @@ -.ResponsiveCloseButtonContainer { - position: relative; -} - -.ResponsiveCloseButton { - position: absolute; - top: var(--base-size-8); - right: var(--base-size-8); - display: none; - - @media screen and (--viewportRange-narrow) { - display: inline-grid; +@layer primer.components.AnchoredOverlay { + .ResponsiveCloseButtonContainer { + position: relative; } -} -.AnchoredOverlay { - position-try-fallbacks: - flip-block, - flip-inline, - flip-block flip-inline, - --inline-end-center, - --inline-start-center, - --fit-block-bottom, - --fit-block-top; - position-visibility: anchors-visible; - z-index: 100; - position: fixed !important; - - &[popover] { - inset: auto; - margin: 0; - padding: 0; - border: 0; - max-width: none; + .ResponsiveCloseButton { + position: absolute; + top: var(--base-size-8); + right: var(--base-size-8); + display: none; + + @media screen and (--viewportRange-narrow) { + display: inline-grid; + } } - &[data-side='outside-bottom'] { - /* stylelint-disable primer/spacing */ - top: calc(anchor(bottom) + var(--base-size-4)); - left: anchor(left); + .AnchoredOverlay { + position-try-fallbacks: + flip-block, + flip-inline, + flip-block flip-inline, + --inline-end-center, + --inline-start-center, + --fit-block-bottom, + --fit-block-top; + position-visibility: anchors-visible; + z-index: 100; + position: fixed !important; + + &[popover] { + inset: auto; + margin: 0; + padding: 0; + border: 0; + max-width: none; + } - &[data-align='left'] { - left: auto; - right: calc(anchor(right) - var(--anchored-overlay-anchor-offset-left)); - /* stylelint-disable max-nesting-depth */ - &[data-responsive='fullscreen'] { - @media screen and (--viewportRange-narrow) { - right: auto; + &[data-side='outside-bottom'] { + /* stylelint-disable primer/spacing */ + top: calc(anchor(bottom) + var(--base-size-4)); + left: anchor(left); + + &[data-align='left'] { + left: auto; + right: calc(anchor(right) - var(--anchored-overlay-anchor-offset-left)); + /* stylelint-disable max-nesting-depth */ + &[data-responsive='fullscreen'] { + @media screen and (--viewportRange-narrow) { + right: auto; + } } } - } - &[data-align='right'] { - left: calc(anchor(left) - var(--anchored-overlay-anchor-offset-right)); + &[data-align='right'] { + left: calc(anchor(left) - var(--anchored-overlay-anchor-offset-right)); - &[data-responsive='fullscreen'] { - @media screen and (--viewportRange-narrow) { - left: auto; + &[data-responsive='fullscreen'] { + @media screen and (--viewportRange-narrow) { + left: auto; + } } } } - } - &[data-side='outside-top'] { - margin-bottom: var(--base-size-4); - bottom: anchor(top); - left: anchor(left); + &[data-side='outside-top'] { + margin-bottom: var(--base-size-4); + bottom: anchor(top); + left: anchor(left); - &[data-align='left'] { - left: auto; - right: anchor(right); - } + &[data-align='left'] { + left: auto; + right: anchor(right); + } - &[data-align='right'] { - left: calc(anchor(left) - var(--anchored-overlay-anchor-offset-right)); + &[data-align='right'] { + left: calc(anchor(left) - var(--anchored-overlay-anchor-offset-right)); - &[data-responsive='fullscreen'] { - @media screen and (--viewportRange-narrow) { - left: auto; + &[data-responsive='fullscreen'] { + @media screen and (--viewportRange-narrow) { + left: auto; + } } } } + + &[data-side='outside-left'] { + right: anchor(left); + /* Falls back to `anchor(top)` when JS hasn't overridden it. JS sets the + override when the overlay's bottom would overflow the viewport so we + can lift it up to keep the bottom edge on screen, mirroring the JS + anchored-positioning code path. + + This override only applies when CSS cannot find space using the default position - + or any of its defined fallbacks. + */ + top: var(--anchored-overlay-top-override, anchor(top)); + margin-right: var(--base-size-4); + position-try-fallbacks: flip-inline, flip-block, flip-start, --outside-left-to-bottom; + } + + &[data-side='outside-right'] { + left: anchor(right); + top: var(--anchored-overlay-top-override, anchor(top)); + margin-left: var(--base-size-4); + position-try-fallbacks: flip-inline, flip-block, flip-start, --outside-right-to-bottom; + } } - &[data-side='outside-left'] { - right: anchor(left); - /* Falls back to `anchor(top)` when JS hasn't overridden it. JS sets the - override when the overlay's bottom would overflow the viewport so we - can lift it up to keep the bottom edge on screen, mirroring the JS - anchored-positioning code path. - - This override only applies when CSS cannot find space using the default position - - or any of its defined fallbacks. - */ - top: var(--anchored-overlay-top-override, anchor(top)); - margin-right: var(--base-size-4); - position-try-fallbacks: flip-inline, flip-block, flip-start, --outside-left-to-bottom; + @position-try --outside-left-to-bottom { + right: anchor(right); + top: calc(anchor(bottom) + var(--base-size-4)); + margin: 0; + width: auto; + } + + @position-try --outside-right-to-bottom { + left: anchor(left); + top: calc(anchor(bottom) + var(--base-size-4)); + margin: 0; + width: auto; } - &[data-side='outside-right'] { + @position-try --inline-end-center { left: anchor(right); - top: var(--anchored-overlay-top-override, anchor(top)); + top: auto; + bottom: auto; margin-left: var(--base-size-4); - position-try-fallbacks: flip-inline, flip-block, flip-start, --outside-right-to-bottom; + align-self: anchor-center; } -} - -@position-try --outside-left-to-bottom { - right: anchor(right); - top: calc(anchor(bottom) + var(--base-size-4)); - margin: 0; - width: auto; -} - -@position-try --outside-right-to-bottom { - left: anchor(left); - top: calc(anchor(bottom) + var(--base-size-4)); - margin: 0; - width: auto; -} -@position-try --inline-end-center { - left: anchor(right); - top: auto; - bottom: auto; - margin-left: var(--base-size-4); - align-self: anchor-center; -} - -@position-try --inline-start-center { - right: anchor(left); - left: auto; - top: auto; - bottom: auto; - margin-right: var(--base-size-4); - align-self: anchor-center; -} + @position-try --inline-start-center { + right: anchor(left); + left: auto; + top: auto; + bottom: auto; + margin-right: var(--base-size-4); + align-self: anchor-center; + } -@position-try --fit-block-bottom { - top: calc(anchor(bottom) + var(--base-size-4)); - bottom: var(--base-size-8); - height: auto; - max-height: none; -} + @position-try --fit-block-bottom { + top: calc(anchor(bottom) + var(--base-size-4)); + bottom: var(--base-size-8); + height: auto; + max-height: none; + } -@position-try --fit-block-top { - top: var(--base-size-8); - bottom: calc(100vh - anchor(top) + var(--base-size-4)); - height: auto; - max-height: none; + @position-try --fit-block-top { + top: var(--base-size-8); + bottom: calc(100vh - anchor(top) + var(--base-size-4)); + height: auto; + max-height: none; + } } diff --git a/packages/react/src/Autocomplete/AutocompleteMenu.module.css b/packages/react/src/Autocomplete/AutocompleteMenu.module.css index 5806e54c560..a4556c671c4 100644 --- a/packages/react/src/Autocomplete/AutocompleteMenu.module.css +++ b/packages/react/src/Autocomplete/AutocompleteMenu.module.css @@ -1,9 +1,11 @@ -.SpinnerWrapper { - display: flex; - justify-content: center; - padding: var(--base-size-16); -} +@layer primer.components.Autocomplete { + .SpinnerWrapper { + display: flex; + justify-content: center; + padding: var(--base-size-16); + } -.EmptyStateWrapper { - padding: var(--base-size-16); + .EmptyStateWrapper { + padding: var(--base-size-16); + } } diff --git a/packages/react/src/Autocomplete/AutocompleteOverlay.module.css b/packages/react/src/Autocomplete/AutocompleteOverlay.module.css index 67d9578c7c1..53601fe1350 100644 --- a/packages/react/src/Autocomplete/AutocompleteOverlay.module.css +++ b/packages/react/src/Autocomplete/AutocompleteOverlay.module.css @@ -1,3 +1,5 @@ -.Overlay { - overflow: auto; +@layer primer.components.Autocomplete { + .Overlay { + overflow: auto; + } } diff --git a/packages/react/src/Banner/Banner.module.css b/packages/react/src/Banner/Banner.module.css index 2a2964de77a..736e35fbf98 100644 --- a/packages/react/src/Banner/Banner.module.css +++ b/packages/react/src/Banner/Banner.module.css @@ -1,52 +1,22 @@ -.Banner { - display: grid; - padding: var(--base-size-8); - /* stylelint-disable-next-line primer/colors */ - background-color: var(--banner-bgColor); - /* stylelint-disable-next-line primer/colors */ - border: var(--borderWidth-thin) solid var(--banner-borderColor); - border-radius: var(--borderRadius-medium); - grid-template-columns: auto minmax(0, 1fr) auto; - align-items: start; - - &[data-actions-layout='default'] { - @supports (container-type: inline-size) { - container: banner / inline-size; - } - } - - &[data-actions-layout='stacked'] { - & .BannerContainer { - flex-direction: column; - } - - & .BannerActions :where([data-primary-action='trailing']) { - display: none; - } - - & .BannerActions :where([data-primary-action='leading']) { - display: flex; - } - } - - &[data-actions-layout='inline'] { - & .BannerContainer { - flex-wrap: nowrap; - } - - & .BannerActions { - flex: 0 0 auto; - } - - & .BannerActions :where([data-primary-action='trailing']) { - display: flex; - } - - & .BannerActions :where([data-primary-action='leading']) { - display: none; +@layer primer.components.Banner { + .Banner { + display: grid; + padding: var(--base-size-8); + /* stylelint-disable-next-line primer/colors */ + background-color: var(--banner-bgColor); + /* stylelint-disable-next-line primer/colors */ + border: var(--borderWidth-thin) solid var(--banner-borderColor); + border-radius: var(--borderRadius-medium); + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: start; + + &[data-actions-layout='default'] { + @supports (container-type: inline-size) { + container: banner / inline-size; + } } - @media screen and (--viewportRange-narrow) { + &[data-actions-layout='stacked'] { & .BannerContainer { flex-direction: column; } @@ -59,207 +29,239 @@ display: flex; } } - } - &[data-layout='compact'] { - padding: var(--base-size-4); - } + &[data-actions-layout='inline'] { + & .BannerContainer { + flex-wrap: nowrap; + } - &[data-flush] { - border-left: none; - border-right: none; - border-radius: 0; - } + & .BannerActions { + flex: 0 0 auto; + } - &[data-variant='critical'] { - --banner-bgColor: var(--bgColor-danger-muted); - --banner-borderColor: var(--borderColor-danger-muted); - --banner-icon-fgColor: var(--fgColor-danger); - } + & .BannerActions :where([data-primary-action='trailing']) { + display: flex; + } - &[data-variant='info'] { - --banner-bgColor: var(--bgColor-accent-muted); - --banner-borderColor: var(--borderColor-accent-muted); - --banner-icon-fgColor: var(--fgColor-accent); - } + & .BannerActions :where([data-primary-action='leading']) { + display: none; + } - &[data-variant='success'] { - --banner-bgColor: var(--bgColor-success-muted); - --banner-borderColor: var(--borderColor-success-muted); - --banner-icon-fgColor: var(--fgColor-success); - } + @media screen and (--viewportRange-narrow) { + & .BannerContainer { + flex-direction: column; + } - &[data-variant='upsell'] { - --banner-bgColor: var(--bgColor-upsell-muted); - --banner-borderColor: var(--borderColor-upsell-muted); - --banner-icon-fgColor: var(--fgColor-upsell); - } + & .BannerActions :where([data-primary-action='trailing']) { + display: none; + } - &[data-variant='warning'] { - --banner-bgColor: var(--bgColor-attention-muted); - --banner-borderColor: var(--borderColor-attention-muted); - --banner-icon-fgColor: var(--fgColor-attention); - } -} + & .BannerActions :where([data-primary-action='leading']) { + display: flex; + } + } + } -/* BannerContainer -------------------------------------------------------- */ + &[data-layout='compact'] { + padding: var(--base-size-4); + } -.BannerContainer { - font-size: var(--text-body-size-medium); - align-items: start; - line-height: var(--text-body-lineHeight-medium); - row-gap: var(--base-size-4); - column-gap: var(--base-size-4); -} + &[data-flush] { + border-left: none; + border-right: none; + border-radius: 0; + } -.Banner :where(.BannerContainer) { - display: flex; - flex-wrap: wrap; - justify-content: space-between; -} + &[data-variant='critical'] { + --banner-bgColor: var(--bgColor-danger-muted); + --banner-borderColor: var(--borderColor-danger-muted); + --banner-icon-fgColor: var(--fgColor-danger); + } -.Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) .BannerContainer { - display: grid; - grid-template-columns: auto; - grid-template-rows: auto; -} + &[data-variant='info'] { + --banner-bgColor: var(--bgColor-accent-muted); + --banner-borderColor: var(--borderColor-accent-muted); + --banner-icon-fgColor: var(--fgColor-accent); + } -/* BannerContent ---------------------------------------------------------- */ + &[data-variant='success'] { + --banner-bgColor: var(--bgColor-success-muted); + --banner-borderColor: var(--borderColor-success-muted); + --banner-icon-fgColor: var(--fgColor-success); + } -.BannerContent { - display: grid; - row-gap: var(--base-size-4); - grid-column-start: 1; - margin-block: var(--base-size-8); -} + &[data-variant='upsell'] { + --banner-bgColor: var(--bgColor-upsell-muted); + --banner-borderColor: var(--borderColor-upsell-muted); + --banner-icon-fgColor: var(--fgColor-upsell); + } -.Banner[data-title-hidden]:not([data-has-actions]) .BannerContent { - margin-block: var(--base-size-6); -} + &[data-variant='warning'] { + --banner-bgColor: var(--bgColor-attention-muted); + --banner-borderColor: var(--borderColor-attention-muted); + --banner-icon-fgColor: var(--fgColor-attention); + } + } -@media screen and (min-width: 544px) { - .BannerContent { - flex: 1 1 0%; + /* BannerContainer -------------------------------------------------------- */ + + .BannerContainer { + font-size: var(--text-body-size-medium); + align-items: start; + line-height: var(--text-body-lineHeight-medium); + row-gap: var(--base-size-4); + column-gap: var(--base-size-4); } -} -.BannerTitle { - margin: 0; - font-size: inherit; - font-weight: var(--base-text-weight-semibold); -} + .Banner :where(.BannerContainer) { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + } -/* BannerIcon ------------------------------------------------------------- */ + .Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) .BannerContainer { + display: grid; + grid-template-columns: auto; + grid-template-rows: auto; + } -.BannerIcon { - display: grid; - place-items: center; - padding: var(--base-size-8); -} + /* BannerContent ---------------------------------------------------------- */ -.BannerIcon svg { - /* 20px is the line box height of the trailing action buttons */ - height: var(--base-size-20); - /* stylelint-disable-next-line primer/colors */ - color: var(--banner-icon-fgColor); - /* stylelint-disable-next-line primer/colors */ - fill: var(--banner-icon-fgColor); -} + .BannerContent { + display: grid; + row-gap: var(--base-size-4); + grid-column-start: 1; + margin-block: var(--base-size-8); + } -/* stylelint-disable-next-line selector-max-specificity */ -.Banner[data-title-hidden]:not([data-has-actions]) .BannerIcon svg { - height: var(--base-size-16); -} + .Banner[data-title-hidden]:not([data-has-actions]) .BannerContent { + margin-block: var(--base-size-6); + } -/* BannerDismiss ---------------------------------------------------------- */ + @media screen and (min-width: 544px) { + .BannerContent { + flex: 1 1 0%; + } + } -.BannerDismiss { - display: grid; - place-items: center; - padding: var(--base-size-8); - margin-inline-start: var(--base-size-4); -} + .BannerTitle { + margin: 0; + font-size: inherit; + font-weight: var(--base-text-weight-semibold); + } -:where(.Banner)[data-has-actions] .BannerDismiss { - margin-block: var(--base-size-2); -} + /* BannerIcon ------------------------------------------------------------- */ -.BannerDismiss svg { - /* stylelint-disable-next-line primer/colors */ - color: var(--banner-icon-fgColor); -} + .BannerIcon { + display: grid; + place-items: center; + padding: var(--base-size-8); + } -/* BannerActions ---------------------------------------------------------- */ + .BannerIcon svg { + /* 20px is the line box height of the trailing action buttons */ + height: var(--base-size-20); + /* stylelint-disable-next-line primer/colors */ + color: var(--banner-icon-fgColor); + /* stylelint-disable-next-line primer/colors */ + fill: var(--banner-icon-fgColor); + } -.BannerActionsContainer { - display: flex; - column-gap: var(--base-size-12); - align-items: center; - margin-block: var(--base-size-2); -} + /* stylelint-disable-next-line selector-max-specificity */ + .Banner[data-title-hidden]:not([data-has-actions]) .BannerIcon svg { + height: var(--base-size-16); + } -.BannerActions :where([data-primary-action='trailing']) { - display: none; -} + /* BannerDismiss ---------------------------------------------------------- */ -.Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) .BannerActions { - margin-block-end: var(--base-size-6); -} + .BannerDismiss { + display: grid; + place-items: center; + padding: var(--base-size-8); + margin-inline-start: var(--base-size-4); + } -/* stylelint-disable-next-line selector-max-specificity */ -.Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) - .BannerActionsContainer[data-primary-action='trailing'] { - display: none; -} + :where(.Banner)[data-has-actions] .BannerDismiss { + margin-block: var(--base-size-2); + } -/* stylelint-disable-next-line selector-max-specificity */ -.Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) - .BannerActionsContainer[data-primary-action='leading'] { - display: flex; -} + .BannerDismiss svg { + /* stylelint-disable-next-line primer/colors */ + color: var(--banner-icon-fgColor); + } -/* Layout ------------------------------------------------------------------- */ + /* BannerActions ---------------------------------------------------------- */ -@container banner (max-width: 500px) { - .BannerContainer { - display: grid; + .BannerActionsContainer { + display: flex; + column-gap: var(--base-size-12); + align-items: center; + margin-block: var(--base-size-2); } - :where(.Banner)[data-has-actions] .BannerContainer { - grid-template-rows: auto auto; + .BannerActions :where([data-primary-action='trailing']) { + display: none; } - .BannerActions { + .Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) .BannerActions { margin-block-end: var(--base-size-6); } - .BannerActions [data-primary-action='trailing'] { + /* stylelint-disable-next-line selector-max-specificity */ + .Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) + .BannerActionsContainer[data-primary-action='trailing'] { display: none; } - .BannerActions [data-primary-action='leading'] { + /* stylelint-disable-next-line selector-max-specificity */ + .Banner[data-dismissible]:not([data-title-hidden], [data-actions-layout='inline']) + .BannerActionsContainer[data-primary-action='leading'] { display: flex; } -} -@container banner (min-width: 500px) { - .BannerContainer { - display: grid; - grid-template-columns: auto auto; - } + /* Layout ------------------------------------------------------------------- */ - :where(.Banner):not([data-dismissible]) - :where(.BannerActionsContainer[data-primary-action='trailing']) - :where([data-variant='link']:only-child) { - padding-inline: 0 var(--base-size-12); - } + @container banner (max-width: 500px) { + .BannerContainer { + display: grid; + } - .BannerActions [data-primary-action='trailing'] { - display: flex; - min-height: var(--base-size-32, 2rem); + :where(.Banner)[data-has-actions] .BannerContainer { + grid-template-rows: auto auto; + } + + .BannerActions { + margin-block-end: var(--base-size-6); + } + + .BannerActions [data-primary-action='trailing'] { + display: none; + } + + .BannerActions [data-primary-action='leading'] { + display: flex; + } } - .BannerActions [data-primary-action='leading'] { - display: none; + @container banner (min-width: 500px) { + .BannerContainer { + display: grid; + grid-template-columns: auto auto; + } + + :where(.Banner):not([data-dismissible]) + :where(.BannerActionsContainer[data-primary-action='trailing']) + :where([data-variant='link']:only-child) { + padding-inline: 0 var(--base-size-12); + } + + .BannerActions [data-primary-action='trailing'] { + display: flex; + min-height: var(--base-size-32, 2rem); + } + + .BannerActions [data-primary-action='leading'] { + display: none; + } } } diff --git a/packages/react/src/Blankslate/Blankslate.module.css b/packages/react/src/Blankslate/Blankslate.module.css index 791e17e4c8d..9539ed461f5 100644 --- a/packages/react/src/Blankslate/Blankslate.module.css +++ b/packages/react/src/Blankslate/Blankslate.module.css @@ -1,135 +1,137 @@ -.Container { - container: blankslate / inline-size; -} - -.Blankslate { - display: grid; - justify-items: center; - /* stylelint-disable-next-line primer/spacing */ - padding: var(--blankslate-padding); - - &:where([data-border]) { - border: var(--borderWidth-thin) solid var(--borderColor-default); - border-radius: var(--borderRadius-medium); - } - - &:where([data-narrow]) { - max-width: 485px; - margin: 0 auto; - } - - &:where([data-size='medium']) { - --blankslate-heading-text: var(--text-title-shorthand-medium); - --blankslate-heading-margin-block: 0 var(--base-size-4); - --blankslate-description-text: var(--text-body-shorthand-large); - --blankslate-padding: var(--base-size-32); - --blankslate-action-margin-block-end: var(--base-size-16); +@layer primer.components.Blankslate { + .Container { + container: blankslate / inline-size; } - &:where([data-size='medium'][data-spacious]) { - --blankslate-padding: var(--base-size-80) var(--base-size-40); - } - - &:where([data-size='small']) { - --blankslate-heading-text: var(--text-title-shorthand-small); - --blankslate-heading-margin-block: 0 var(--base-size-4); - --blankslate-description-text: var(--text-body-shorthand-medium); - --blankslate-padding: var(--base-size-32) var(--base-size-20); - --blankslate-action-margin-block-end: var(--base-size-12); - --blankslate-visual-size: var(--base-size-24); - } + .Blankslate { + display: grid; + justify-items: center; + /* stylelint-disable-next-line primer/spacing */ + padding: var(--blankslate-padding); - &:where([data-size='small'][data-spacious]) { - --blankslate-padding: var(--base-size-44) var(--base-size-28); - } + &:where([data-border]) { + border: var(--borderWidth-thin) solid var(--borderColor-default); + border-radius: var(--borderRadius-medium); + } - &:where([data-size='large']) { - --blankslate-heading-text: var(--text-title-shorthand-large); - --blankslate-heading-margin-block: var(--base-size-8) var(--base-size-4); - --blankslate-description-text: var(--text-body-shorthand-large); - --blankslate-description-margin-block: 0 var(--base-size-8); - --blankslate-padding: var(--base-size-32); - --blankslate-action-margin-block-end: var(--base-size-16); - } + &:where([data-narrow]) { + max-width: 485px; + margin: 0 auto; + } - &:where([data-size='large'][data-spacious]) { - --blankslate-padding: var(--base-size-80) var(--base-size-40); - } -} + &:where([data-size='medium']) { + --blankslate-heading-text: var(--text-title-shorthand-medium); + --blankslate-heading-margin-block: 0 var(--base-size-4); + --blankslate-description-text: var(--text-body-shorthand-large); + --blankslate-padding: var(--base-size-32); + --blankslate-action-margin-block-end: var(--base-size-16); + } -.Heading, -.Description { - margin: 0; - text-align: center; - text-wrap: balance; -} + &:where([data-size='medium'][data-spacious]) { + --blankslate-padding: var(--base-size-80) var(--base-size-40); + } -.Heading { - /* stylelint-disable-next-line primer/typography */ - font: var(--blankslate-heading-text); - /* stylelint-disable-next-line primer/spacing */ - margin-block: var(--blankslate-heading-margin-block); -} + &:where([data-size='small']) { + --blankslate-heading-text: var(--text-title-shorthand-small); + --blankslate-heading-margin-block: 0 var(--base-size-4); + --blankslate-description-text: var(--text-body-shorthand-medium); + --blankslate-padding: var(--base-size-32) var(--base-size-20); + --blankslate-action-margin-block-end: var(--base-size-12); + --blankslate-visual-size: var(--base-size-24); + } -.Description { - /* stylelint-disable-next-line primer/typography */ - font: var(--blankslate-description-text); - color: var(--fgColor-muted); - /* stylelint-disable-next-line primer/spacing */ - margin-block: var(--blankslate-description-margin-block); -} + &:where([data-size='small'][data-spacious]) { + --blankslate-padding: var(--base-size-44) var(--base-size-28); + } -.Visual { - color: var(--fgColor-muted); - /* This display property exists so that the container matches the size of the inner svg element */ - display: inline-flex; - margin-block-end: var(--base-size-8); - max-width: var(--blankslate-visual-size); + &:where([data-size='large']) { + --blankslate-heading-text: var(--text-title-shorthand-large); + --blankslate-heading-margin-block: var(--base-size-8) var(--base-size-4); + --blankslate-description-text: var(--text-body-shorthand-large); + --blankslate-description-margin-block: 0 var(--base-size-8); + --blankslate-padding: var(--base-size-32); + --blankslate-action-margin-block-end: var(--base-size-16); + } - & svg { - width: 100%; + &:where([data-size='large'][data-spacious]) { + --blankslate-padding: var(--base-size-80) var(--base-size-40); + } } -} -.Action { - /* stylelint-disable-next-line primer/typography */ - font: var(--blankslate-description-text); - margin-block-start: var(--base-size-16); + .Heading, + .Description { + margin: 0; + text-align: center; + text-wrap: balance; + } - &:where(:last-of-type) { + .Heading { + /* stylelint-disable-next-line primer/typography */ + font: var(--blankslate-heading-text); /* stylelint-disable-next-line primer/spacing */ - margin-block-end: var(--blankslate-action-margin-block-end); + margin-block: var(--blankslate-heading-margin-block); } -} -/* At the time these styles were written, 34rem was our "small" breakpoint width */ -@container blankslate (max-width: 34rem) { - .Blankslate { - --blankslate-padding: var(--base-size-20); - - &:where([data-spacious='true']) { - --blankslate-padding: var(--base-size-44) var(--base-size-28); - } - - --blankslate-heading-text: var(--text-title-shorthand-small); - --blankslate-description-text: var(--text-body-shorthand-medium); + .Description { + /* stylelint-disable-next-line primer/typography */ + font: var(--blankslate-description-text); + color: var(--fgColor-muted); + /* stylelint-disable-next-line primer/spacing */ + margin-block: var(--blankslate-description-margin-block); } .Visual { - max-width: var(--base-size-24); - margin-bottom: var(--base-size-8); color: var(--fgColor-muted); + /* This display property exists so that the container matches the size of the inner svg element */ + display: inline-flex; + margin-block-end: var(--base-size-8); + max-width: var(--blankslate-visual-size); + + & svg { + width: 100%; + } } .Action { - margin-top: var(--base-size-8); + /* stylelint-disable-next-line primer/typography */ + font: var(--blankslate-description-text); + margin-block-start: var(--base-size-16); + + &:where(:last-of-type) { + /* stylelint-disable-next-line primer/spacing */ + margin-block-end: var(--blankslate-action-margin-block-end); + } + } - &:first-of-type { - margin-top: var(--base-size-16); + /* At the time these styles were written, 34rem was our "small" breakpoint width */ + @container blankslate (max-width: 34rem) { + .Blankslate { + --blankslate-padding: var(--base-size-20); + + &:where([data-spacious='true']) { + --blankslate-padding: var(--base-size-44) var(--base-size-28); + } + + --blankslate-heading-text: var(--text-title-shorthand-small); + --blankslate-description-text: var(--text-body-shorthand-medium); + } + + .Visual { + max-width: var(--base-size-24); + margin-bottom: var(--base-size-8); + color: var(--fgColor-muted); } - &:last-of-type { - margin-bottom: calc(var(--base-size-8) / 2); + .Action { + margin-top: var(--base-size-8); + + &:first-of-type { + margin-top: var(--base-size-16); + } + + &:last-of-type { + margin-bottom: calc(var(--base-size-8) / 2); + } } } } diff --git a/packages/react/src/Breadcrumbs/Breadcrumbs.module.css b/packages/react/src/Breadcrumbs/Breadcrumbs.module.css index bd1691f28f0..4888ce7c3f2 100644 --- a/packages/react/src/Breadcrumbs/Breadcrumbs.module.css +++ b/packages/react/src/Breadcrumbs/Breadcrumbs.module.css @@ -1,166 +1,168 @@ -.BreadcrumbsBase { - display: flex; - justify-content: space-between; - width: 100%; -} - -.BreadcrumbsList { - padding-left: 0; - margin-top: 0; - margin-bottom: 0; -} - -[data-overflow='menu'], -[data-overflow='menu-with-root'] { - & .BreadcrumbsList { - white-space: nowrap; +@layer primer.components.Breadcrumbs { + .BreadcrumbsBase { display: flex; - flex-direction: row; + justify-content: space-between; + width: 100%; } -} - -.ItemSeparator { - color: var(--fgColor-muted); - display: flex; - align-self: center; - justify-content: center; - white-space: nowrap; - user-select: none; -} -.ItemWrapper { - display: inline-block; - font-size: var(--text-body-size-medium); - list-style: none; + .BreadcrumbsList { + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + } - &::after { - display: inline-block; - height: 0.8em; - /* stylelint-disable-next-line primer/spacing */ - margin: 0 0.5em; - font-size: var(--text-body-size-medium); - content: ''; - /* stylelint-disable-next-line primer/borders, primer/colors */ - border-right: 0.1em solid var(--fgColor-muted); - transform: rotate(15deg) translateY(0.0625em); + [data-overflow='menu'], + [data-overflow='menu-with-root'] { + & .BreadcrumbsList { + white-space: nowrap; + display: flex; + flex-direction: row; + } } - &:first-child { - margin-left: 0; + .ItemSeparator { + color: var(--fgColor-muted); + display: flex; + align-self: center; + justify-content: center; + white-space: nowrap; + user-select: none; } - &:last-child { + .ItemWrapper { + display: inline-block; + font-size: var(--text-body-size-medium); + list-style: none; + &::after { - content: none; + display: inline-block; + height: 0.8em; + /* stylelint-disable-next-line primer/spacing */ + margin: 0 0.5em; + font-size: var(--text-body-size-medium); + content: ''; + /* stylelint-disable-next-line primer/borders, primer/colors */ + border-right: 0.1em solid var(--fgColor-muted); + transform: rotate(15deg) translateY(0.0625em); + } + + &:first-child { + margin-left: 0; + } + + &:last-child { + &::after { + content: none; + } } } -} -.Item { - display: inline-block; - font-size: var(--text-body-size-medium); + .Item { + display: inline-block; + font-size: var(--text-body-size-medium); - &:focus-visible { - border-radius: var(--borderRadius-small); + &:focus-visible { + border-radius: var(--borderRadius-small); - @mixin focusOutline 2px; + @mixin focusOutline 2px; + } } -} -[data-variant='normal'] { - & .Item { - color: var(--fgColor-link); - text-decoration: none; + [data-variant='normal'] { + & .Item { + color: var(--fgColor-link); + text-decoration: none; - &:not([aria-current]) { - &:hover { - text-decoration: underline; + &:not([aria-current]) { + &:hover { + text-decoration: underline; + } } - } - &:focus-visible { - text-decoration: none; - } + &:focus-visible { + text-decoration: none; + } - &[aria-current] { - color: var(--fgColor-default); + &[aria-current] { + color: var(--fgColor-default); + } } } -} -[data-variant='spacious'] { - & .Item { - color: var(--fgColor-default); - text-decoration: none; - padding-inline: var(--base-size-6); - padding-block: var(--base-size-4); - border-radius: var(--borderRadius-medium); - - &:hover { - background: var(--control-transparent-bgColor-hover); + [data-variant='spacious'] { + & .Item { + color: var(--fgColor-default); text-decoration: none; - } + padding-inline: var(--base-size-6); + padding-block: var(--base-size-4); + border-radius: var(--borderRadius-medium); - &[aria-current] { - font-weight: var(--base-text-weight-semibold); + &:hover { + background: var(--control-transparent-bgColor-hover); + text-decoration: none; + } + + &[aria-current] { + font-weight: var(--base-text-weight-semibold); + } } } -} -.BreadcrumbsItem { - display: inline-grid; - grid-auto-flow: column; - align-items: center; - flex: 0 99999 auto; - min-width: auto; - white-space: nowrap; - list-style: none; - - /* allow menu items to wrap line */ - /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ - &:has(.MenuOverlay) { - white-space: normal; - } + .BreadcrumbsItem { + display: inline-grid; + grid-auto-flow: column; + align-items: center; + flex: 0 99999 auto; + min-width: auto; + white-space: nowrap; + list-style: none; - &:first-child { - margin-left: 0; - } + /* allow menu items to wrap line */ + /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ + &:has(.MenuOverlay) { + white-space: normal; + } - &:last-child { - .ItemSeparator { - display: none; + &:first-child { + margin-left: 0; } - } - .MenuDetails { - position: relative; - display: inline-block; + &:last-child { + .ItemSeparator { + display: none; + } + } - & summary { - list-style: none; - cursor: pointer; + .MenuDetails { + position: relative; + display: inline-block; - &::-webkit-details-marker { - display: none; + & summary { + list-style: none; + cursor: pointer; + + &::-webkit-details-marker { + display: none; + } } } - } - .MenuOverlay { - position: absolute; - z-index: 1; - box-shadow: var(--shadow-floating-small); - border-radius: var(--borderRadius-large); - background-color: var(--overlay-bgColor); - min-width: var(--overlay-width-xsmall); - max-height: 100vh; - max-width: var(--overlay-width-small); - overflow: hidden; - /* stylelint-disable-next-line primer/spacing */ - top: calc(var(--overlay-offset) + var(--control-small-size)); - - @media (prefers-reduced-motion: no-preference) { - animation: overlay-appear 200ms cubic-bezier(0.33, 1, 0.68, 1); + .MenuOverlay { + position: absolute; + z-index: 1; + box-shadow: var(--shadow-floating-small); + border-radius: var(--borderRadius-large); + background-color: var(--overlay-bgColor); + min-width: var(--overlay-width-xsmall); + max-height: 100vh; + max-width: var(--overlay-width-small); + overflow: hidden; + /* stylelint-disable-next-line primer/spacing */ + top: calc(var(--overlay-offset) + var(--control-small-size)); + + @media (prefers-reduced-motion: no-preference) { + animation: overlay-appear 200ms cubic-bezier(0.33, 1, 0.68, 1); + } } } } diff --git a/packages/react/src/Dialog/Dialog.module.css b/packages/react/src/Dialog/Dialog.module.css index 8387d2fba81..6cd58665763 100644 --- a/packages/react/src/Dialog/Dialog.module.css +++ b/packages/react/src/Dialog/Dialog.module.css @@ -1,114 +1,96 @@ -/* The --prc-dialog-scrollgutter property is used only on the body element to - * simulate scrollbar-gutter:stable. This property is not and should not - * be used elsewhere in the DOM. There is a performance penalty to - * setting inherited properties which can cause a large style recalc to - * occur, so it benefits us to prevent inheritance for this property. - * See https://web.dev/blog/at-property-performance - */ -@property --prc-dialog-scrollgutter { - initial-value: 0; - inherits: false; - syntax: ''; -} - -@keyframes dialog-backdrop-appear { - 0% { - opacity: 0; +@layer primer.components.Dialog { + /* The --prc-dialog-scrollgutter property is used only on the body element to + * simulate scrollbar-gutter:stable. This property is not and should not + * be used elsewhere in the DOM. There is a performance penalty to + * setting inherited properties which can cause a large style recalc to + * occur, so it benefits us to prevent inheritance for this property. + * See https://web.dev/blog/at-property-performance + */ + @property --prc-dialog-scrollgutter { + initial-value: 0; + inherits: false; + syntax: ''; } - 100% { - opacity: 1; - } -} + @keyframes dialog-backdrop-appear { + 0% { + opacity: 0; + } -@keyframes Overlay--motion-scaleFade { - 0% { - opacity: 0; - transform: scale(0.5); + 100% { + opacity: 1; + } } - 100% { - opacity: 1; - transform: scale(1); - } -} + @keyframes Overlay--motion-scaleFade { + 0% { + opacity: 0; + transform: scale(0.5); + } -@keyframes Overlay--motion-slideUp { - from { - transform: translateY(100%); + 100% { + opacity: 1; + transform: scale(1); + } } -} -@keyframes Overlay--motion-slideInRight { - from { - transform: translateX(-100%); - } -} - -@keyframes Overlay--motion-slideInLeft { - from { - transform: translateX(100%); + @keyframes Overlay--motion-slideUp { + from { + transform: translateY(100%); + } } -} -/* Used to determine whether there should be a border between the body and footer */ -@keyframes detect-scroll { - from, - to { - --can-scroll: 1; + @keyframes Overlay--motion-slideInRight { + from { + transform: translateX(-100%); + } } -} -.Backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: flex; - background-color: var(--overlay-backdrop-bgColor); - animation: dialog-backdrop-appear 200ms cubic-bezier(0.33, 1, 0.68, 1); - align-items: center; - justify-content: center; - - &[data-position-regular='center'] { - align-items: center; - justify-content: center; + @keyframes Overlay--motion-slideInLeft { + from { + transform: translateX(100%); + } } - &[data-position-regular='left'] { - align-items: center; - justify-content: flex-start; + /* Used to determine whether there should be a border between the body and footer */ + @keyframes detect-scroll { + from, + to { + --can-scroll: 1; + } } - &[data-position-regular='right'] { + .Backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + background-color: var(--overlay-backdrop-bgColor); + animation: dialog-backdrop-appear 200ms cubic-bezier(0.33, 1, 0.68, 1); align-items: center; - justify-content: flex-end; - } - - /* align only applies when regular position is center (or absent). - * :where() zeroes out the :not() specificity so narrow-position rules (coming later) - * always win when data-position-narrow is bottom or fullscreen. */ - &:where(:not([data-position-regular='left']):not([data-position-regular='right'])) { - &[data-align='top'] { - align-items: flex-start; - } + justify-content: center; - &[data-align='center'] { + &[data-position-regular='center'] { align-items: center; + justify-content: center; } - &[data-align='bottom'] { - align-items: flex-end; + &[data-position-regular='left'] { + align-items: center; + justify-content: flex-start; } - } - @media (max-width: 767px) { - &[data-position-narrow='center'] { + &[data-position-regular='right'] { align-items: center; - justify-content: center; + justify-content: flex-end; + } - /* align still applies when narrow position is center */ + /* align only applies when regular position is center (or absent). + * :where() zeroes out the :not() specificity so narrow-position rules (coming later) + * always win when data-position-narrow is bottom or fullscreen. */ + &:where(:not([data-position-regular='left']):not([data-position-regular='right'])) { &[data-align='top'] { align-items: flex-start; } @@ -122,259 +104,279 @@ } } - &[data-position-narrow='bottom'] { - align-items: end; - justify-content: center; - } - } -} - -.Dialog { - display: flex; - /* stylelint-disable-next-line primer/responsive-widths */ - width: var(--dialog-width, 640px); - min-width: 296px; - max-width: calc(100dvw - 64px); - height: auto; - max-height: calc(100dvh - 64px); - flex-direction: column; - background-color: var(--overlay-bgColor); - border-radius: var(--borderRadius-large); - border-radius: var(--borderRadius-large, var(--borderRadius-large)); - box-shadow: var(--shadow-floating-small); - opacity: 1; - - &:where([data-width='small']) { - width: 296px; - } - - &:where([data-width='medium']) { - width: 320px; - } + @media (max-width: 767px) { + &[data-position-narrow='center'] { + align-items: center; + justify-content: center; - &:where([data-width='large']) { - /* stylelint-disable-next-line primer/responsive-widths */ - width: 480px; - } + /* align still applies when narrow position is center */ + &[data-align='top'] { + align-items: flex-start; + } - &:where([data-height='small']) { - height: 480px; - } + &[data-align='center'] { + align-items: center; + } - &:where([data-height='large']) { - height: 640px; - } + &[data-align='bottom'] { + align-items: flex-end; + } + } - @media screen and (prefers-reduced-motion: no-preference) { - animation: Overlay--motion-scaleFade 0.2s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + &[data-position-narrow='bottom'] { + align-items: end; + justify-content: center; + } + } } - &[data-position-regular='center'] { + .Dialog { + display: flex; + /* stylelint-disable-next-line primer/responsive-widths */ + width: var(--dialog-width, 640px); + min-width: 296px; + max-width: calc(100dvw - 64px); + height: auto; + max-height: calc(100dvh - 64px); + flex-direction: column; + background-color: var(--overlay-bgColor); + border-radius: var(--borderRadius-large); border-radius: var(--borderRadius-large, var(--borderRadius-large)); + box-shadow: var(--shadow-floating-small); + opacity: 1; - @media screen and (prefers-reduced-motion: no-preference) { - animation: Overlay--motion-scaleFade 0.2s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + &:where([data-width='small']) { + width: 296px; } - /* align margins only apply when regular position is center */ - &[data-align='top'] { - margin-top: var(--base-size-64); + &:where([data-width='medium']) { + width: 320px; } - &[data-align='bottom'] { - margin-bottom: var(--base-size-64); + &:where([data-width='large']) { + /* stylelint-disable-next-line primer/responsive-widths */ + width: 480px; } - } - &[data-position-regular='left'] { - height: 100dvh; - max-height: unset; - border-radius: var(--borderRadius-large, var(--borderRadius-large)); - border-top-left-radius: 0; - border-bottom-left-radius: 0; - - @media screen and (prefers-reduced-motion: no-preference) { - animation: Overlay--motion-slideInRight 0.25s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + &:where([data-height='small']) { + height: 480px; } - } - &[data-position-regular='right'] { - height: 100dvh; - max-height: unset; - border-radius: var(--borderRadius-large, var(--borderRadius-large)); - border-top-right-radius: 0; - border-bottom-right-radius: 0; + &:where([data-height='large']) { + height: 640px; + } @media screen and (prefers-reduced-motion: no-preference) { - animation: Overlay--motion-slideInLeft 0.25s cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running; + animation: Overlay--motion-scaleFade 0.2s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; } - } - @media (max-width: 767px) { - &[data-position-narrow='center'] { - /* stylelint-disable-next-line primer/responsive-widths */ - width: var(--dialog-width, 640px); - height: auto; + &[data-position-regular='center'] { border-radius: var(--borderRadius-large, var(--borderRadius-large)); - &:where([data-width='small']) { - width: 296px; + @media screen and (prefers-reduced-motion: no-preference) { + animation: Overlay--motion-scaleFade 0.2s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; } - &:where([data-width='medium']) { - width: 320px; + /* align margins only apply when regular position is center */ + &[data-align='top'] { + margin-top: var(--base-size-64); } - &:where([data-width='large']) { - /* stylelint-disable-next-line primer/responsive-widths */ - width: 480px; + &[data-align='bottom'] { + margin-bottom: var(--base-size-64); } + } - &:where([data-height='small']) { - height: 480px; - } + &[data-position-regular='left'] { + height: 100dvh; + max-height: unset; + border-radius: var(--borderRadius-large, var(--borderRadius-large)); + border-top-left-radius: 0; + border-bottom-left-radius: 0; - &:where([data-height='large']) { - height: 640px; + @media screen and (prefers-reduced-motion: no-preference) { + animation: Overlay--motion-slideInRight 0.25s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; } } - @media (max-height: 280px) { - max-height: calc(100dvh - 12px); - max-width: calc(100dvw - 12px); - } - - &[data-position-narrow='bottom'] { - width: 100dvw; - max-width: 100dvw; - height: auto; - max-height: calc(100dvh - 64px); + &[data-position-regular='right'] { + height: 100dvh; + max-height: unset; border-radius: var(--borderRadius-large, var(--borderRadius-large)); + border-top-right-radius: 0; border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - - /* reset align margins since position wins at narrow */ - &[data-align] { - margin-top: 0; - margin-bottom: 0; - } @media screen and (prefers-reduced-motion: no-preference) { - animation: Overlay--motion-slideUp 0.25s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + animation: Overlay--motion-slideInLeft 0.25s cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running; } } - &[data-position-narrow='fullscreen'] { - width: 100%; - max-width: 100dvw; - height: 100%; - max-height: 100dvh; - border-radius: unset !important; - flex-grow: 1; - - /* reset align margins since fullscreen wins at narrow */ - &[data-align] { - margin-top: 0; - margin-bottom: 0; + @media (max-width: 767px) { + &[data-position-narrow='center'] { + /* stylelint-disable-next-line primer/responsive-widths */ + width: var(--dialog-width, 640px); + height: auto; + border-radius: var(--borderRadius-large, var(--borderRadius-large)); + + &:where([data-width='small']) { + width: 296px; + } + + &:where([data-width='medium']) { + width: 320px; + } + + &:where([data-width='large']) { + /* stylelint-disable-next-line primer/responsive-widths */ + width: 480px; + } + + &:where([data-height='small']) { + height: 480px; + } + + &:where([data-height='large']) { + height: 640px; + } } - @media screen and (prefers-reduced-motion: no-preference) { - animation: Overlay--motion-scaleFade 0.2s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + @media (max-height: 280px) { + max-height: calc(100dvh - 12px); + max-width: calc(100dvw - 12px); } - } - } -} -/* - * PERFORMANCE OPTIMIZATION: Direct attribute on body - O(1) lookup - */ -/* stylelint-disable-next-line selector-no-qualifying-type */ -body[data-dialog-scroll-disabled] { - /* stylelint-disable-next-line primer/spacing */ - padding-right: var(--prc-dialog-scrollgutter) !important; - overflow: hidden !important; -} + &[data-position-narrow='bottom'] { + width: 100dvw; + max-width: 100dvw; + height: auto; + max-height: calc(100dvh - 64px); + border-radius: var(--borderRadius-large, var(--borderRadius-large)); + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + + /* reset align margins since position wins at narrow */ + &[data-align] { + margin-top: 0; + margin-bottom: 0; + } + + @media screen and (prefers-reduced-motion: no-preference) { + animation: Overlay--motion-slideUp 0.25s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + } + } -.DialogOverflowWrapper { - flex-grow: 1; -} + &[data-position-narrow='fullscreen'] { + width: 100%; + max-width: 100dvw; + height: 100%; + max-height: 100dvh; + border-radius: unset !important; + flex-grow: 1; + + /* reset align margins since fullscreen wins at narrow */ + &[data-align] { + margin-top: 0; + margin-bottom: 0; + } + + @media screen and (prefers-reduced-motion: no-preference) { + animation: Overlay--motion-scaleFade 0.2s cubic-bezier(0.33, 1, 0.68, 1) 1ms 1 normal none running; + } + } + } + } -/* -Add a border between the body and footer if: -- the dialog has a footer -- the dialog has a body that can scroll -- the browser supports the `animation-timeline` property and its `scroll()` function -*/ -.Dialog[data-has-footer] { - --can-scroll: 0; + /* + * PERFORMANCE OPTIMIZATION: Direct attribute on body - O(1) lookup + */ + /* stylelint-disable-next-line selector-no-qualifying-type */ + body[data-dialog-scroll-disabled] { + /* stylelint-disable-next-line primer/spacing */ + padding-right: var(--prc-dialog-scrollgutter) !important; + overflow: hidden !important; + } .DialogOverflowWrapper { - /* If the browser does not support the `animation-timeline` property, always show a border */ - border-bottom: var(--borderWidth-default) solid var(--borderColor-default); - animation: detect-scroll; - animation-timeline: scroll(self); + flex-grow: 1; + } - @supports (animation-timeline: scroll(self)) { - border-bottom: calc(var(--borderWidth-thin) * var(--can-scroll)) solid var(--borderColor-default); + /* + Add a border between the body and footer if: + - the dialog has a footer + - the dialog has a body that can scroll + - the browser supports the `animation-timeline` property and its `scroll()` function + */ + .Dialog[data-has-footer] { + --can-scroll: 0; + + .DialogOverflowWrapper { + /* If the browser does not support the `animation-timeline` property, always show a border */ + border-bottom: var(--borderWidth-default) solid var(--borderColor-default); + animation: detect-scroll; + animation-timeline: scroll(self); + + @supports (animation-timeline: scroll(self)) { + border-bottom: calc(var(--borderWidth-thin) * var(--can-scroll)) solid var(--borderColor-default); + } } } -} -.Header { - z-index: 1; - max-height: 35vh; - padding: var(--base-size-8); - overflow-y: auto; - /* stylelint-disable-next-line primer/box-shadow */ - box-shadow: 0 1px 0 var(--borderColor-default); - flex-shrink: 0; -} + .Header { + z-index: 1; + max-height: 35vh; + padding: var(--base-size-8); + overflow-y: auto; + /* stylelint-disable-next-line primer/box-shadow */ + box-shadow: 0 1px 0 var(--borderColor-default); + flex-shrink: 0; + } -.HeaderInner { - display: flex; -} + .HeaderInner { + display: flex; + } -.HeaderContent { - display: flex; - padding-inline: var(--base-size-8); - padding-block: var(--base-size-6); - flex-direction: column; - flex-grow: 1; -} + .HeaderContent { + display: flex; + padding-inline: var(--base-size-8); + padding-block: var(--base-size-6); + flex-direction: column; + flex-grow: 1; + } -.Title { - margin: 0; /* override default margin */ - font-size: var(--text-body-size-medium); - font-weight: var(--text-title-weight-large); -} + .Title { + margin: 0; /* override default margin */ + font-size: var(--text-body-size-medium); + font-weight: var(--text-title-weight-large); + } -.Subtitle { - margin: 0; /* override default margin */ - margin-top: var(--base-size-4); - font-size: var(--text-body-size-small); - font-weight: var(--base-text-weight-normal); - color: var(--fgColor-muted); -} + .Subtitle { + margin: 0; /* override default margin */ + margin-top: var(--base-size-4); + font-size: var(--text-body-size-small); + font-weight: var(--base-text-weight-normal); + color: var(--fgColor-muted); + } -.Body { - padding: var(--base-size-16); - overflow: auto; - flex-grow: 1; -} + .Body { + padding: var(--base-size-16); + overflow: auto; + flex-grow: 1; + } -.Footer { - z-index: 1; - display: flex; - flex-flow: wrap; - justify-content: flex-end; - padding: var(--base-size-16); - gap: var(--base-size-8); - flex-shrink: 0; -} + .Footer { + z-index: 1; + display: flex; + flex-flow: wrap; + justify-content: flex-end; + padding: var(--base-size-16); + gap: var(--base-size-8); + flex-shrink: 0; + } -.Dialog[data-footer-button-layout='scroll'] .Footer { - flex-wrap: nowrap; - overflow-x: scroll; - flex-direction: row; - justify-content: unset; + .Dialog[data-footer-button-layout='scroll'] .Footer { + flex-wrap: nowrap; + overflow-x: scroll; + flex-direction: row; + justify-content: unset; + } } diff --git a/packages/react/src/__tests__/css-layers.test.ts b/packages/react/src/__tests__/css-layers.test.ts index da9b787ff6a..1e234139ba2 100644 --- a/packages/react/src/__tests__/css-layers.test.ts +++ b/packages/react/src/__tests__/css-layers.test.ts @@ -88,6 +88,17 @@ const allowlist = new Set([ path.resolve(import.meta.dirname, '../ActionList/ActionList.module.css'), path.resolve(import.meta.dirname, '../ActionList/Group.module.css'), path.resolve(import.meta.dirname, '../ActionList/Heading.module.css'), + path.resolve(import.meta.dirname, '../AnchoredOverlay/AnchoredOverlay.module.css'), + path.resolve(import.meta.dirname, '../Autocomplete/AutocompleteMenu.module.css'), + path.resolve(import.meta.dirname, '../Autocomplete/AutocompleteOverlay.module.css'), + path.resolve(import.meta.dirname, '../Banner/Banner.module.css'), + path.resolve(import.meta.dirname, '../Blankslate/Blankslate.module.css'), + path.resolve(import.meta.dirname, '../Breadcrumbs/Breadcrumbs.module.css'), + path.resolve(import.meta.dirname, '../deprecated/DialogV1/Dialog.module.css'), + path.resolve(import.meta.dirname, '../Dialog/Dialog.module.css'), + path.resolve(import.meta.dirname, '../ActionMenu/ActionMenu.module.css'), + path.resolve(import.meta.dirname, '../ActionBar/ActionBar.module.css'), + path.resolve(import.meta.dirname, '../experimental/SelectPanel2/SelectPanel.module.css'), ]) const files = Array.from(allowlist).map(file => { return [path.relative(path.resolve(import.meta.dirname, '..'), file), file] diff --git a/packages/react/src/deprecated/DialogV1/Dialog.module.css b/packages/react/src/deprecated/DialogV1/Dialog.module.css index 8d446fb47fe..00eb1e915a3 100644 --- a/packages/react/src/deprecated/DialogV1/Dialog.module.css +++ b/packages/react/src/deprecated/DialogV1/Dialog.module.css @@ -1,72 +1,74 @@ -.Overlay { - &::before { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 99; - display: block; - cursor: default; - content: ' '; - background: var(--overlay-backdrop-bgColor); +@layer primer.components.DeprecatedDialogV1 { + .Overlay { + &::before { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99; + display: block; + cursor: default; + content: ' '; + background: var(--overlay-backdrop-bgColor); + } } -} -.CloseIcon { - position: absolute; - top: var(--base-size-8); - right: var(--base-size-16); -} + .CloseIcon { + position: absolute; + top: var(--base-size-8); + right: var(--base-size-16); + } -.Dialog { - position: fixed; - top: 0; - left: 50%; - z-index: 999; - max-height: 80vh; - margin: 10vh auto; - background-color: var(--bgColor-default); - border-radius: var(--borderRadius-medium); - outline: none; - box-shadow: var(--shadow-floating-large); - transform: translateX(-50%); + .Dialog { + position: fixed; + top: 0; + left: 50%; + z-index: 999; + max-height: 80vh; + margin: 10vh auto; + background-color: var(--bgColor-default); + border-radius: var(--borderRadius-medium); + outline: none; + box-shadow: var(--shadow-floating-large); + transform: translateX(-50%); - &:where([data-width='default']) { - /* stylelint-disable-next-line primer/responsive-widths */ - width: 440px; - } + &:where([data-width='default']) { + /* stylelint-disable-next-line primer/responsive-widths */ + width: 440px; + } - &:where([data-width='narrow']) { - width: 320px; - } + &:where([data-width='narrow']) { + width: 320px; + } - &:where([data-width='wide']) { - /* stylelint-disable-next-line primer/responsive-widths */ - width: 640px; - } + &:where([data-width='wide']) { + /* stylelint-disable-next-line primer/responsive-widths */ + width: 640px; + } - @media screen and (max-width: 750px) { - width: 100dvw; - height: 100dvh; - margin: 0; - border-radius: 0; + @media screen and (max-width: 750px) { + width: 100dvw; + height: 100dvh; + margin: 0; + border-radius: 0; + } } -} -.Header { - display: flex; - padding: var(--base-size-16); - background: var(--bgColor-muted); - border-bottom: var(--borderWidth-thin) solid var(--borderColor-default); - border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0; + .Header { + display: flex; + padding: var(--base-size-16); + background: var(--bgColor-muted); + border-bottom: var(--borderWidth-thin) solid var(--borderColor-default); + border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0; - @media screen and (max-width: 750px) { - border-radius: 0; + @media screen and (max-width: 750px) { + border-radius: 0; + } } -} -.HeaderChild { - font-size: var(--text-body-size-medium); - font-weight: var(--base-text-weight-semibold); + .HeaderChild { + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-semibold); + } } diff --git a/packages/react/src/experimental/SelectPanel2/SelectPanel.module.css b/packages/react/src/experimental/SelectPanel2/SelectPanel.module.css index 16afc9dd10a..362b0be7d4b 100644 --- a/packages/react/src/experimental/SelectPanel2/SelectPanel.module.css +++ b/packages/react/src/experimental/SelectPanel2/SelectPanel.module.css @@ -1,290 +1,292 @@ -.Overlay { - padding: 0; - color: var(--fgColor-default); - border: none; - - /* CSS variables values are passed in via styles */ - --max-height: 0; - --position-top: 0; - --position-left: 0; - - &:where([open]) { - display: flex; /* to fit children */ - } +@layer primer.components.SelectPanel2 { + .Overlay { + padding: 0; + color: var(--fgColor-default); + border: none; + + /* CSS variables values are passed in via styles */ + --max-height: 0; + --position-top: 0; + --position-left: 0; + + &:where([open]) { + display: flex; /* to fit children */ + } - &:where([data-variant='anchored']), - &:where([data-variant='full-screen']) { - /* stylelint-disable-next-line primer/spacing */ - top: var(--position-top); - /* stylelint-disable-next-line primer/spacing */ - left: var(--position-left); - margin: 0; + &:where([data-variant='anchored']), + &:where([data-variant='full-screen']) { + /* stylelint-disable-next-line primer/spacing */ + top: var(--position-top); + /* stylelint-disable-next-line primer/spacing */ + left: var(--position-left); + margin: 0; + + &::backdrop { + background-color: transparent; + } + } - &::backdrop { - background-color: transparent; + &:where([data-variant='modal']) { + top: 0; + left: 0; + right: 0; + bottom: 0; } - } - &:where([data-variant='modal']) { - top: 0; - left: 0; - right: 0; - bottom: 0; - } + &:where([data-variant='modal'])::backdrop { + background-color: var(--overlay-backdrop-bgColor); + } - &:where([data-variant='modal'])::backdrop { - background-color: var(--overlay-backdrop-bgColor); - } + &:where([data-variant='full-screen']) { + top: 0; + left: 0; + width: 100%; + max-width: 100vw; + height: 100%; + max-height: 100vh; + margin: 0; + border-radius: unset; + } - &:where([data-variant='full-screen']) { - top: 0; - left: 0; - width: 100%; - max-width: 100vw; - height: 100%; - max-height: 100vh; - margin: 0; - border-radius: unset; + &:where([data-variant='bottom-sheet']) { + top: auto; + bottom: 0; + left: 0; + width: 100%; + max-width: 100vw; + max-height: calc(100vh - 64px); + margin: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } } - &:where([data-variant='bottom-sheet']) { - top: auto; - bottom: 0; - left: 0; + .Form { + display: flex; width: 100%; - max-width: 100vw; - max-height: calc(100vh - 64px); - margin: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; + flex-direction: column; } -} -.Form { - display: flex; - width: 100%; - flex-direction: column; -} + .Container { + display: flex; + overflow: hidden; + flex-direction: column; + flex-shrink: 1; + flex-grow: 1; + justify-content: space-between; -.Container { - display: flex; - overflow: hidden; - flex-direction: column; - flex-shrink: 1; - flex-grow: 1; - justify-content: space-between; + ul { + overflow-y: auto; + flex-grow: 1; + } - ul { - overflow-y: auto; - flex-grow: 1; + /* Allow the browser to skip rendering for off-screen items, reducing style recalc and layout costs in long lists. + Exclude items that show the active indicator line, as content-visibility: auto applies paint containment + which clips the absolutely-positioned ::after pseudo-element that renders outside the item bounds. */ + /* stylelint-disable-next-line selector-no-qualifying-type */ + li:not(:focus, [data-is-active-descendant], [data-active]) { + content-visibility: auto; + contain-intrinsic-size: auto 32px; + } } - /* Allow the browser to skip rendering for off-screen items, reducing style recalc and layout costs in long lists. - Exclude items that show the active indicator line, as content-visibility: auto applies paint containment - which clips the absolutely-positioned ::after pseudo-element that renders outside the item bounds. */ - /* stylelint-disable-next-line selector-no-qualifying-type */ - li:not(:focus, [data-is-active-descendant], [data-active]) { - content-visibility: auto; - contain-intrinsic-size: auto 32px; - } -} + .HeaderContent { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0; -.HeaderContent { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 0; + &:where([data-description]) { + align-items: flex-start; + } - &:where([data-description]) { - align-items: flex-start; + &:where([data-search-input]) { + margin-bottom: var(--base-size-8); + } } - &:where([data-search-input]) { - margin-bottom: var(--base-size-8); - } -} + .TitleWrapper { + margin-top: 0; + margin-left: var(--base-size-8); -.TitleWrapper { - margin-top: 0; - margin-left: var(--base-size-8); + &:where([data-description]) { + /* stylelint-disable-next-line primer/spacing */ + margin-top: 2px; + } - &:where([data-description]) { - /* stylelint-disable-next-line primer/spacing */ - margin-top: 2px; + &:where([data-on-back]) { + margin-left: var(--base-size-4); + } } - &:where([data-on-back]) { - margin-left: var(--base-size-4); + .TextInput { + padding-left: var(--base-size-8) !important; + + /* stylelint-disable-next-line selector-class-pattern, selector-no-qualifying-type, selector-pseudo-class-disallowed-list -- :has() scoped to CSS Module, audited (github/github-ui#17224) */ + &:has(input:placeholder-shown) :global(.TextInput-action) { + display: none; + } } -} -.TextInput { - padding-left: var(--base-size-8) !important; + .Checkbox { + margin-top: 0; + } - /* stylelint-disable-next-line selector-class-pattern, selector-no-qualifying-type, selector-pseudo-class-disallowed-list -- :has() scoped to CSS Module, audited (github/github-ui#17224) */ - &:has(input:placeholder-shown) :global(.TextInput-action) { - display: none; + .FlexBox { + display: flex; } -} -.Checkbox { - margin-top: 0; -} + .Title { + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-semibold); + } -.FlexBox { - display: flex; -} + .Description { + display: block; + font-size: var(--text-body-size-small); + color: var(--fgColor-muted); + } -.Title { - font-size: var(--text-body-size-medium); - font-weight: var(--base-text-weight-semibold); -} + .ClearAction { + color: var(--fgColor-muted); + background: none; + } -.Description { - display: block; - font-size: var(--text-body-size-small); - color: var(--fgColor-muted); -} + .Footer { + display: flex; + min-height: 44px; + padding: var(--base-size-16); + border-top: var(--borderWidth-thin) solid; + border-top-color: var(--borderColor-default); + justify-content: space-between; + align-items: center; + flex-shrink: 0; + + &:where([data-hide-primary-actions]) { + padding: var(--base-size-8); + } + } -.ClearAction { - color: var(--fgColor-muted); - background: none; -} + .FooterContent { + flex-grow: 0; -.Footer { - display: flex; - min-height: 44px; - padding: var(--base-size-16); - border-top: var(--borderWidth-thin) solid; - border-top-color: var(--borderColor-default); - justify-content: space-between; - align-items: center; - flex-shrink: 0; - - &:where([data-hide-primary-actions]) { - padding: var(--base-size-8); + &:where([data-hide-primary-actions]) { + flex-grow: 1; + } } -} -.FooterContent { - flex-grow: 0; + .FooterActions { + display: flex; + gap: var(--stack-gap-condensed); + } - &:where([data-hide-primary-actions]) { - flex-grow: 1; + .SecondaryCheckbox { + display: flex; + align-items: center; + gap: var(--stack-gap-condensed); } -} -.FooterActions { - display: flex; - gap: var(--stack-gap-condensed); -} + .SmallText { + font-size: var(--text-body-size-small); + } -.SecondaryCheckbox { - display: flex; - align-items: center; - gap: var(--stack-gap-condensed); -} + .SelectPanelLoading { + display: flex; + height: 100%; -.SmallText { - font-size: var(--text-body-size-small); -} + /* maxHeight of dialog - (header & footer) */ + min-height: min(calc(var(--max-height) - 150px), 324px); + flex-direction: column; + justify-content: center; + align-items: center; + gap: var(--stack-gap-normal); + } -.SelectPanelLoading { - display: flex; - height: 100%; + .LoadingText { + font-size: var(--text-body-size-medium); + color: var(--fgColor-muted); + } - /* maxHeight of dialog - (header & footer) */ - min-height: min(calc(var(--max-height) - 150px), 324px); - flex-direction: column; - justify-content: center; - align-items: center; - gap: var(--stack-gap-normal); -} + .MessageFull { + display: flex; + height: 100%; -.LoadingText { - font-size: var(--text-body-size-medium); - color: var(--fgColor-muted); -} + /* maxHeight of dialog - (header & footer) */ + min-height: min(calc(var(--max-height) - 150px), 324px); + padding-right: var(--base-size-24); + padding-left: var(--base-size-24); + text-align: center; + flex-direction: column; + justify-content: center; + align-items: center; + flex-grow: 1; + gap: var(--base-size-4); -.MessageFull { - display: flex; - height: 100%; - - /* maxHeight of dialog - (header & footer) */ - min-height: min(calc(var(--max-height) - 150px), 324px); - padding-right: var(--base-size-24); - padding-left: var(--base-size-24); - text-align: center; - flex-direction: column; - justify-content: center; - align-items: center; - flex-grow: 1; - gap: var(--base-size-4); - - a { - color: inherit; - text-decoration: underline; + a { + color: inherit; + text-decoration: underline; + } } -} -.Octicon { - margin-bottom: var(--base-size-8); + .Octicon { + margin-bottom: var(--base-size-8); - &.Error { - color: var(--fgColor-danger); + &.Error { + color: var(--fgColor-danger); + } + + &.Warning { + color: var(--fgColor-attention); + } } - &.Warning { - color: var(--fgColor-attention); + .MessageTitle { + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-medium); } -} -.MessageTitle { - font-size: var(--text-body-size-medium); - font-weight: var(--base-text-weight-medium); -} + .MessageContent { + display: flex; + font-size: var(--text-body-size-medium); + color: var(--fgColor-muted); + flex-direction: column; + gap: var(--stack-gap-condensed); + align-items: center; + } -.MessageContent { - display: flex; - font-size: var(--text-body-size-medium); - color: var(--fgColor-muted); - flex-direction: column; - gap: var(--stack-gap-condensed); - align-items: center; -} + .MessageInline { + display: flex; + padding-top: var(--base-size-12); + padding-right: var(--base-size-16); + padding-bottom: var(--base-size-12); + padding-left: var(--base-size-16); + font-size: var(--text-body-size-small); + border-bottom: var(--borderWidth-thin) solid; + gap: var(--stack-gap-condensed); + + a { + color: inherit; + text-decoration: underline; + } -.MessageInline { - display: flex; - padding-top: var(--base-size-12); - padding-right: var(--base-size-16); - padding-bottom: var(--base-size-12); - padding-left: var(--base-size-16); - font-size: var(--text-body-size-small); - border-bottom: var(--borderWidth-thin) solid; - gap: var(--stack-gap-condensed); - - a { - color: inherit; - text-decoration: underline; - } + &:where([data-variant='error']) { + color: var(--fgColor-danger); + background-color: var(--bgColor-danger-muted); + border-color: var(--borderColor-danger-muted); + } - &:where([data-variant='error']) { - color: var(--fgColor-danger); - background-color: var(--bgColor-danger-muted); - border-color: var(--borderColor-danger-muted); + &:where([data-variant='warning']) { + color: var(--fgColor-attention); + background-color: var(--bgColor-attention-muted); + border-color: var(--borderColor-attention-muted); + } } - &:where([data-variant='warning']) { - color: var(--fgColor-attention); - background-color: var(--bgColor-attention-muted); - border-color: var(--borderColor-attention-muted); + .Header { + display: flex; + padding: var(--base-size-8); + flex-direction: column; + border-bottom: var(--borderWidth-thin) solid; + border-bottom-color: var(--borderColor-default); } } - -.Header { - display: flex; - padding: var(--base-size-8); - flex-direction: column; - border-bottom: var(--borderWidth-thin) solid; - border-bottom-color: var(--borderColor-default); -} From a37f74ce2c5c7e2b2d2ce8fe20705ed1ecc3ed18 Mon Sep 17 00:00:00 2001 From: Josh Black Date: Tue, 9 Jun 2026 15:13:40 -0500 Subject: [PATCH 2/2] chore: standardize CSS layer changeset wording Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/css-layers-overlay-consumers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/css-layers-overlay-consumers.md b/.changeset/css-layers-overlay-consumers.md index 509970ce935..7e32723fb50 100644 --- a/.changeset/css-layers-overlay-consumers.md +++ b/.changeset/css-layers-overlay-consumers.md @@ -2,4 +2,4 @@ '@primer/react': patch --- -AnchoredOverlay, Autocomplete, Banner, Blankslate, Breadcrumbs, Dialog, ActionMenu, ActionBar, SelectPanel2: Improve custom class override behavior for component styles +AnchoredOverlay, Autocomplete, Banner, Blankslate, Breadcrumbs, Dialog, ActionMenu, ActionBar, SelectPanel2: Add CSS layer support for component styles