diff --git a/.changeset/css-layers-button-action-list.md b/.changeset/css-layers-button-action-list.md new file mode 100644 index 00000000000..14b5572b526 --- /dev/null +++ b/.changeset/css-layers-button-action-list.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Button, ActionList: Add CSS layer support for component styles diff --git a/packages/react/src/ActionList/ActionList.module.css b/packages/react/src/ActionList/ActionList.module.css index e6f148da4a7..562e277eb51 100644 --- a/packages/react/src/ActionList/ActionList.module.css +++ b/packages/react/src/ActionList/ActionList.module.css @@ -1,52 +1,35 @@ -/* stylelint-disable max-nesting-depth, selector-max-specificity */ +@layer primer.components.ActionList { + /* stylelint-disable max-nesting-depth, selector-max-specificity */ -.ActionList { - padding: 0; - margin: 0; - list-style: none; - - ul { + .ActionList { padding: 0; margin: 0; list-style: none; - } - &:where([data-variant='inset']) { - padding-block: var(--base-size-8); - } - - &:where([data-variant='inset'], [data-variant='horizontal-inset']) { - /* this is only to match default experience */ - & .ActionListItem { - margin-inline: var(--base-size-8); + ul { + padding: 0; + margin: 0; + list-style: none; } - } - - &:where([data-variant='horizontal-inset']) { - padding-bottom: var(--base-size-8); - } - &:where([data-dividers='true']) { - /* place dividers on the wrapper that excludes leading visuals/actions */ - & .ActionListSubContent::before { - position: absolute; + &:where([data-variant='inset']) { + padding-block: var(--base-size-8); + } - /* use this top size after FF removed */ + &:where([data-variant='inset'], [data-variant='horizontal-inset']) { + /* this is only to match default experience */ + & .ActionListItem { + margin-inline: var(--base-size-8); + } + } - /* top: calc(-1 * var(--control-medium-paddingBlock)); */ - /* stylelint-disable-next-line primer/spacing */ - top: -7px; - display: block; - width: 100%; - height: 1px; - content: ''; - /* stylelint-disable-next-line primer/colors */ - background: var(--borderColor-muted); + &:where([data-variant='horizontal-inset']) { + padding-bottom: var(--base-size-8); } - /* if inline description, move pseudo divider to description wrapper */ - & [data-description-variant='inline'] { - &::before { + &:where([data-dividers='true']) { + /* place dividers on the wrapper that excludes leading visuals/actions */ + & .ActionListSubContent::before { position: absolute; /* use this top size after FF removed */ @@ -56,121 +39,155 @@ top: -7px; display: block; width: 100%; - height: var(--borderWidth-thin); + height: 1px; content: ''; /* stylelint-disable-next-line primer/colors */ background: var(--borderColor-muted); } - /* remove the default divider */ - & .ActionListSubContent::before { - content: unset; + /* if inline description, move pseudo divider to description wrapper */ + & [data-description-variant='inline'] { + &::before { + position: absolute; + + /* use this top size after FF removed */ + + /* top: calc(-1 * var(--control-medium-paddingBlock)); */ + /* stylelint-disable-next-line primer/spacing */ + top: -7px; + display: block; + width: 100%; + height: var(--borderWidth-thin); + content: ''; + /* stylelint-disable-next-line primer/colors */ + background: var(--borderColor-muted); + } + + /* remove the default divider */ + & .ActionListSubContent::before { + content: unset; + } } - } - /* hide if item is first of type with label::before, or is the first item after a sectionDivider */ - .ActionListItem:first-of-type .ActionListSubContent::before, - .Divider + .ActionListItem .ActionListSubContent::before { - visibility: hidden; - } + /* hide if item is first of type with label::before, or is the first item after a sectionDivider */ + .ActionListItem:first-of-type .ActionListSubContent::before, + .Divider + .ActionListItem .ActionListSubContent::before { + visibility: hidden; + } - /* hide if item is first of type with label::before, or is the first item after a sectionDivider */ - .ActionListItem:first-of-type [data-description-variant='inline']::before, - .Divider + .ActionListItem [data-description-variant='inline']::before { - visibility: hidden; + /* hide if item is first of type with label::before, or is the first item after a sectionDivider */ + .ActionListItem:first-of-type [data-description-variant='inline']::before, + .Divider + .ActionListItem [data-description-variant='inline']::before { + visibility: hidden; + } } - } - /* Make sure that the first visible item isn't a divider */ - & .Divider:first-child { - display: none; - } + /* Make sure that the first visible item isn't a divider */ + & .Divider:first-child { + display: none; + } - /* if a list has a mix of items with and without descriptions, reset the label font-weight to normal */ - &[data-mixed-descriptions='true'] { - & .ItemLabel { - font-weight: var(--base-text-weight-normal); + /* if a list has a mix of items with and without descriptions, reset the label font-weight to normal */ + &[data-mixed-descriptions='true'] { + & .ItemLabel { + font-weight: var(--base-text-weight-normal); + } } } -} -/* ActionListItem is a li that handles visual state, while ActionListItemContent controls actual state via button or link */ + /* ActionListItem is a li that handles visual state, while ActionListItemContent controls actual state via button or link */ -.ActionListItem { - position: relative; - list-style: none; - background-color: var(--control-transparent-bgColor-rest); - border-radius: var(--borderRadius-medium); + .ActionListItem { + position: relative; + list-style: none; + background-color: var(--control-transparent-bgColor-rest); + border-radius: var(--borderRadius-medium); - /* apply flex if trailing action exists as an immediate child */ - &[data-has-trailing-action] { - display: flex; - flex-wrap: nowrap; - } + /* apply flex if trailing action exists as an immediate child */ + &[data-has-trailing-action] { + display: flex; + flex-wrap: nowrap; + } - /* state */ + /* state */ - @media (forced-colors: active) { - :focus, - &:focus-visible, - /* stylelint-disable-next-line selector-no-qualifying-type */ - >a.focus-visible, - &[data-is-active-descendant] { - /* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips */ - outline: solid 1px transparent !important; + @media (forced-colors: active) { + :focus, + &:focus-visible, + /* stylelint-disable-next-line selector-no-qualifying-type */ + >a.focus-visible, + &[data-is-active-descendant] { + /* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips */ + outline: solid 1px transparent !important; + } } - } - &:not([data-is-disabled], [data-has-subitem='true']) { - @media (hover: hover) { - &:hover, - &:active { - cursor: pointer; + &:not([data-is-disabled], [data-has-subitem='true']) { + @media (hover: hover) { + &:hover, + &:active { + cursor: pointer; + } + + &:hover { + background-color: var(--control-transparent-bgColor-hover); + + &:not([data-active], :focus-visible) { + /* Support for "Windows high contrast mode" https:sarahmhigley.com/writing/whcm-quick-tips/ */ + outline: solid var(--borderWidth-thin) transparent; + outline-offset: calc(-1 * var(--borderWidth-thin)); + box-shadow: var(--boxShadow-thin) var(--control-transparent-borderColor-active); + } + } } - &:hover { - background-color: var(--control-transparent-bgColor-hover); + &:active { + background-color: var(--control-transparent-bgColor-active); - &:not([data-active], :focus-visible) { + &:not([data-active]) { /* Support for "Windows high contrast mode" https:sarahmhigley.com/writing/whcm-quick-tips/ */ outline: solid var(--borderWidth-thin) transparent; outline-offset: calc(-1 * var(--borderWidth-thin)); box-shadow: var(--boxShadow-thin) var(--control-transparent-borderColor-active); } } - } - &:active { - background-color: var(--control-transparent-bgColor-active); + &:focus-visible { + @mixin focusOutline 0; - &:not([data-active]) { - /* Support for "Windows high contrast mode" https:sarahmhigley.com/writing/whcm-quick-tips/ */ - outline: solid var(--borderWidth-thin) transparent; - outline-offset: calc(-1 * var(--borderWidth-thin)); - box-shadow: var(--boxShadow-thin) var(--control-transparent-borderColor-active); + & .ActionListSubContent::before, + & + .ActionListItem .ActionListSubContent::before { + visibility: hidden; + } } - } - &:focus-visible { - @mixin focusOutline 0; + /* danger */ + &:where([data-variant='danger']) { + & .LeadingAction, + .LeadingVisual, + .ItemLabel { + color: var(--control-danger-fgColor-rest); + } - & .ActionListSubContent::before, - & + .ActionListItem .ActionListSubContent::before { - visibility: hidden; - } - } + @media (hover: hover) { + &:hover { + background: var(--control-danger-bgColor-hover); - /* danger */ - &:where([data-variant='danger']) { - & .LeadingAction, - .LeadingVisual, - .ItemLabel { - color: var(--control-danger-fgColor-rest); - } + & .LeadingAction, + .LeadingVisual, + .ItemLabel { + color: var(--control-danger-fgColor-hover); + } - @media (hover: hover) { - &:hover { - background: var(--control-danger-bgColor-hover); + & [data-kbd-chord] { + background-color: var(--bgColor-default); + transition: none; + } + } + } + + &:active { + background: var(--control-danger-bgColor-active); & .LeadingAction, .LeadingVisual, @@ -185,617 +202,602 @@ } } - &:active { - background: var(--control-danger-bgColor-active); + /* active state [aria-current] */ + &:where([data-active]) { + background: var(--control-transparent-bgColor-selected); - & .LeadingAction, - .LeadingVisual, - .ItemLabel { - color: var(--control-danger-fgColor-hover); - } + /* provides a visual indication of the current item for Windows high-contrast mode */ + outline: 2px solid transparent; - & [data-kbd-chord] { - background-color: var(--bgColor-default); - transition: none; + & .ItemLabel { + font-weight: var(--base-text-weight-semibold); + color: var(--control-fgColor-rest); } - } - } - /* active state [aria-current] */ - &:where([data-active]) { - background: var(--control-transparent-bgColor-selected); + @media (hover: hover) { + &:hover { + background-color: var(--control-transparent-bgColor-hover); + } + } - /* provides a visual indication of the current item for Windows high-contrast mode */ - outline: 2px solid transparent; + /* hide dividers if showDividers is true and item is active */ - & .ItemLabel { - font-weight: var(--base-text-weight-semibold); - color: var(--control-fgColor-rest); - } + & .ActionListSubContent::before, + & + .ActionListItem .ActionListSubContent::before { + visibility: hidden; + } - @media (hover: hover) { - &:hover { - background-color: var(--control-transparent-bgColor-hover); + /* blue accent line */ + &::after { + @mixin activeIndicatorLine; } } - /* hide dividers if showDividers is true and item is active */ + &:where([data-is-active-descendant]) { + background: var(--control-transparent-bgColor-selected); - & .ActionListSubContent::before, - & + .ActionListItem .ActionListSubContent::before { - visibility: hidden; - } + /* provides a visual indication of the current item for Windows high-contrast mode */ + outline: 2px solid transparent; - /* blue accent line */ - &::after { - @mixin activeIndicatorLine; - } - } + /* hide dividers if showDividers is true and item is active */ - &:where([data-is-active-descendant]) { - background: var(--control-transparent-bgColor-selected); + /* add back in after FF ship */ - /* provides a visual indication of the current item for Windows high-contrast mode */ - outline: 2px solid transparent; + /* & .ActionListSubContent::before, + & + .ActionListItem .ActionListSubContent::before { + visibility: hidden; + } */ + + /* blue accent line */ + &::after { + @mixin activeIndicatorLine; + } + } - /* hide dividers if showDividers is true and item is active */ + /* inactive */ + &:where([data-inactive='true']) { + /* ignore tooltip */ + & * :not([popover], .InactiveWarning) { + color: var(--fgColor-muted); + } - /* add back in after FF ship */ + @media (hover: hover) { + &:hover { + cursor: not-allowed; + background-color: transparent; - /* & .ActionListSubContent::before, - & + .ActionListItem .ActionListSubContent::before { - visibility: hidden; - } */ + & * :not([popover], .InactiveWarning) { + color: var(--fgColor-muted); + } + } + } - /* blue accent line */ - &::after { - @mixin activeIndicatorLine; + &:active { + background: transparent; + } } - } - /* inactive */ - &:where([data-inactive='true']) { - /* ignore tooltip */ - & * :not([popover], .InactiveWarning) { - color: var(--fgColor-muted); + &:where([data-loading='true']), + & > [data-loading='true'] { + & .ItemLabel, + & .Description, + & .LeadingVisual, + & .TrailingVisual, + & .LeadingAction, + & .VisualWrap { + color: var(--fgColor-muted); + } } + /* hide dividers */ @media (hover: hover) { &:hover { - cursor: not-allowed; - background-color: transparent; + & .ActionListSubContent::before, + & + .ActionListItem .ActionListSubContent::before { + visibility: hidden; + } - & * :not([popover], .InactiveWarning) { - color: var(--fgColor-muted); + & [data-description-variant='inline']::before, + & + .ActionListItem [data-description-variant='inline']::before { + visibility: hidden; } } } - - &:active { - background: transparent; - } } - &:where([data-loading='true']), - & > [data-loading='true'] { - & .ItemLabel, - & .Description, - & .LeadingVisual, - & .TrailingVisual, - & .LeadingAction, - & .VisualWrap { - color: var(--fgColor-muted); - } - } + /* if item has subitem, move hover styles to ActionListContent */ + &[data-has-subitem='true'] { + /* first child */ + & > .ActionListContent { + z-index: 1; - /* hide dividers */ - @media (hover: hover) { - &:hover { - & .ActionListSubContent::before, - & + .ActionListItem .ActionListSubContent::before { - visibility: hidden; + @media (hover: hover) { + &:hover { + cursor: pointer; + background-color: var(--control-transparent-bgColor-hover); + } } - & [data-description-variant='inline']::before, - & + .ActionListItem [data-description-variant='inline']::before { - visibility: hidden; + &:active { + background-color: var(--control-transparent-bgColor-active); } } + + & .Spacer { + display: block; + } } - } - /* if item has subitem, move hover styles to ActionListContent */ - &[data-has-subitem='true'] { - /* first child */ - & > .ActionListContent { - z-index: 1; + /* disabled */ + + &[aria-disabled='true'], + &[data-is-disabled] { + & .ActionListContent * { + color: var(--control-fgColor-disabled); + } + + & .ActionListContent { + @media (hover: hover) { + &:hover { + cursor: not-allowed; + background-color: transparent; + } + } + } @media (hover: hover) { &:hover { - cursor: pointer; - background-color: var(--control-transparent-bgColor-hover); + background-color: transparent; } } - &:active { - background-color: var(--control-transparent-bgColor-active); + & .MultiSelectCheckbox { + background-color: var(--control-bgColor-disabled); + border-color: var(--control-borderColor-disabled); } - } - - & .Spacer { - display: block; - } - } - /* disabled */ - - &[aria-disabled='true'], - &[data-is-disabled] { - & .ActionListContent * { - color: var(--control-fgColor-disabled); - } + &[aria-checked='true'], + &[aria-selected='true'] { + & .MultiSelectCheckbox { + background-color: var(--control-checked-bgColor-disabled); + /* stylelint-disable-next-line primer/colors */ + border-color: var(--control-checked-bgColor-disabled); - & .ActionListContent { - @media (hover: hover) { - &:hover { - cursor: not-allowed; - background-color: transparent; + &::before { + /* stylelint-disable-next-line primer/colors */ + background-color: var(--control-checked-fgColor-disabled); + } } } } - @media (hover: hover) { - &:hover { - background-color: transparent; + /* When TrailingAction is in loading state, keep labels and descriptions accessible */ + &[data-trailing-action-loading]:not([data-is-disabled]) { + /* Ensure labels and descriptions maintain accessibility contrast */ + & .ItemLabel { + color: var(--fgColor-default); + } + + & .Description { + color: var(--fgColor-default); } } + /* Make sure that the first visible item isn't a divider */ + &[aria-hidden] + .Divider { + display: none; + } + + /* + * checkbox item [aria-checked] + * listbox [aria-selected] + */ + & .MultiSelectCheckbox { - background-color: var(--control-bgColor-disabled); - border-color: var(--control-borderColor-disabled); + position: relative; + display: grid; + width: var(--base-size-16); + height: var(--base-size-16); + margin: 0; + cursor: pointer; + background-color: var(--bgColor-default); + border: var(--borderWidth-thin) solid var(--control-borderColor-emphasis); + border-radius: var(--borderRadius-small); + transition: + background-color, + border-color 80ms cubic-bezier(0.33, 1, 0.68, 1); + /* checked -> unchecked - add 120ms delay to fully see animation-out */ + + place-content: center; + + &::before { + width: var(--base-size-16); + height: var(--base-size-16); + content: ''; + /* stylelint-disable-next-line primer/colors */ + background-color: var(--control-checked-fgColor-rest); + transition: visibility 0s linear 230ms; + clip-path: inset(var(--base-size-16) 0 0 0); + + /* octicon checkmark image */ + mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTEuNzgwMyAwLjIxOTYyNUMxMS45MjEgMC4zNjA0MjcgMTIgMC41NTEzMDUgMTIgMC43NTAzMTNDMTIgMC45NDkzMjEgMTEuOTIxIDEuMTQwMTkgMTEuNzgwMyAxLjI4MUw0LjUxODYgOC41NDA0MkM0LjM3Nzc1IDguNjgxIDQuMTg2ODIgOC43NiAzLjk4Nzc0IDguNzZDMy43ODg2NyA4Ljc2IDMuNTk3NzMgOC42ODEgMy40NTY4OSA4LjU0MDQyTDAuMjAxNjIyIDUuMjg2MkMwLjA2ODkyNzcgNS4xNDM4MyAtMC4wMDMzMDkwNSA0Ljk1NTU1IDAuMDAwMTE2NDkzIDQuNzYwOThDMC4wMDM1NTIwNSA0LjU2NjQzIDAuMDgyMzg5NCA0LjM4MDgxIDAuMjIwMDMyIDQuMjQzMjFDMC4zNTc2NjUgNC4xMDU2MiAwLjU0MzM1NSA0LjAyNjgxIDAuNzM3OTcgNC4wMjMzOEMwLjkzMjU4NCA0LjAxOTk0IDEuMTIwOTMgNC4wOTIxNyAxLjI2MzM0IDQuMjI0ODJMMy45ODc3NCA2Ljk0ODM1TDEwLjcxODYgMC4yMTk2MjVDMTAuODU5NSAwLjA3ODk5MjMgMTEuMDUwNCAwIDExLjI0OTUgMEMxMS40NDg1IDAgMTEuNjM5NSAwLjA3ODk5MjMgMTEuNzgwMyAwLjIxOTYyNVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo='); + mask-size: 75%; + mask-repeat: no-repeat; + mask-position: center; + animation: checkmarkOut 80ms cubic-bezier(0.65, 0, 0.35, 1); + /* forwards; slightly snappier animation out */ + } + + @media (forced-colors: active) { + /* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips */ + + /* background-color will be overriden but border-width is a workaround */ + border-width: var(--borderWidth-thin); + } } &[aria-checked='true'], &[aria-selected='true'] { & .MultiSelectCheckbox { - background-color: var(--control-checked-bgColor-disabled); - /* stylelint-disable-next-line primer/colors */ - border-color: var(--control-checked-bgColor-disabled); + background-color: var(--control-checked-bgColor-rest); + border-color: var(--control-checked-borderColor-rest); + transition: + background-color, + border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; + /* unchecked -> checked */ &::before { - /* stylelint-disable-next-line primer/colors */ - background-color: var(--control-checked-fgColor-disabled); + visibility: visible; + transition: visibility 0s linear 0s; + animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms; + } + + @media (forced-colors: active) { + /* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips + background-color will be overriden but border-width is a workaround */ + /* stylelint-disable-next-line primer/borders */ + border-width: 8px; } } - } - } - /* When TrailingAction is in loading state, keep labels and descriptions accessible */ - &[data-trailing-action-loading]:not([data-is-disabled]) { - /* Ensure labels and descriptions maintain accessibility contrast */ - & .ItemLabel { - color: var(--fgColor-default); + & .SingleSelectCheckmark { + visibility: visible; + } } - & .Description { - color: var(--fgColor-default); + &[aria-checked='false'], + &[aria-selected='false'] { + & .MultiSelectCheckbox { + &::before { + visibility: hidden; + } + } + + & .SingleSelectCheckmark { + visibility: hidden; + } } } - /* Make sure that the first visible item isn't a divider */ - &[aria-hidden] + .Divider { - display: none; + /* hide by default to support inactive state where role cannot be menuitemradio or menuitemcheckbox */ + .SingleSelectCheckmark { + visibility: hidden; } - /* - * checkbox item [aria-checked] - * listbox [aria-selected] - */ + /* button or a tag */ + + /* [ [spacer] [leadingAction] [leadingVisual] [content] ] */ + .ActionListContent { + --subitem-depth: 0px; - & .MultiSelectCheckbox { position: relative; display: grid; - width: var(--base-size-16); - height: var(--base-size-16); - margin: 0; - cursor: pointer; - background-color: var(--bgColor-default); - border: var(--borderWidth-thin) solid var(--control-borderColor-emphasis); - border-radius: var(--borderRadius-small); - transition: - background-color, - border-color 80ms cubic-bezier(0.33, 1, 0.68, 1); - /* checked -> unchecked - add 120ms delay to fully see animation-out */ + width: 100%; + color: var(--control-fgColor-rest); + text-align: left; + user-select: none; + background-color: transparent; + border: none; + border-radius: var(--borderRadius-medium); + transition: background 33.333ms linear; + /* stylelint-disable-next-line primer/spacing */ + padding-block: var(--control-medium-paddingBlock); + /* stylelint-disable-next-line primer/spacing */ + padding-inline: var(--control-medium-paddingInline-condensed); + touch-action: manipulation; + -webkit-tap-highlight-color: transparent; + grid-template-rows: min-content; + grid-template-areas: 'spacer leadingAction leadingVisual content'; + grid-template-columns: min-content min-content min-content minmax(0, auto); + align-items: start; + + /* column-gap persists with empty grid-areas, margin applies only when children exist */ + & > :not(:last-child, .Spacer) { + /* stylelint-disable-next-line primer/spacing */ + margin-right: var(--control-medium-gap); + } - place-content: center; + &:hover { + text-decoration: none; + cursor: pointer; + } - &::before { - width: var(--base-size-16); - height: var(--base-size-16); - content: ''; - /* stylelint-disable-next-line primer/colors */ - background-color: var(--control-checked-fgColor-rest); - transition: visibility 0s linear 230ms; - clip-path: inset(var(--base-size-16) 0 0 0); + /* large */ - /* octicon checkmark image */ - mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTEuNzgwMyAwLjIxOTYyNUMxMS45MjEgMC4zNjA0MjcgMTIgMC41NTEzMDUgMTIgMC43NTAzMTNDMTIgMC45NDkzMjEgMTEuOTIxIDEuMTQwMTkgMTEuNzgwMyAxLjI4MUw0LjUxODYgOC41NDA0MkM0LjM3Nzc1IDguNjgxIDQuMTg2ODIgOC43NiAzLjk4Nzc0IDguNzZDMy43ODg2NyA4Ljc2IDMuNTk3NzMgOC42ODEgMy40NTY4OSA4LjU0MDQyTDAuMjAxNjIyIDUuMjg2MkMwLjA2ODkyNzcgNS4xNDM4MyAtMC4wMDMzMDkwNSA0Ljk1NTU1IDAuMDAwMTE2NDkzIDQuNzYwOThDMC4wMDM1NTIwNSA0LjU2NjQzIDAuMDgyMzg5NCA0LjM4MDgxIDAuMjIwMDMyIDQuMjQzMjFDMC4zNTc2NjUgNC4xMDU2MiAwLjU0MzM1NSA0LjAyNjgxIDAuNzM3OTcgNC4wMjMzOEMwLjkzMjU4NCA0LjAxOTk0IDEuMTIwOTMgNC4wOTIxNyAxLjI2MzM0IDQuMjI0ODJMMy45ODc3NCA2Ljk0ODM1TDEwLjcxODYgMC4yMTk2MjVDMTAuODU5NSAwLjA3ODk5MjMgMTEuMDUwNCAwIDExLjI0OTUgMEMxMS40NDg1IDAgMTEuNjM5NSAwLjA3ODk5MjMgMTEuNzgwMyAwLjIxOTYyNVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo='); - mask-size: 75%; - mask-repeat: no-repeat; - mask-position: center; - animation: checkmarkOut 80ms cubic-bezier(0.65, 0, 0.35, 1); - /* forwards; slightly snappier animation out */ + &[data-size='large'] { + /* stylelint-disable-next-line primer/spacing */ + padding-block: var(--control-large-paddingBlock); } - @media (forced-colors: active) { - /* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips */ + /* collapsible item [aria-expanded] */ - /* background-color will be overriden but border-width is a workaround */ - border-width: var(--borderWidth-thin); + &[aria-expanded='true'] { + & .ExpandIcon { + transform: scaleY(-1); + } } - } - - &[aria-checked='true'], - &[aria-selected='true'] { - & .MultiSelectCheckbox { - background-color: var(--control-checked-bgColor-rest); - border-color: var(--control-checked-borderColor-rest); - transition: - background-color, - border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; - /* unchecked -> checked */ - &::before { - visibility: visible; - transition: visibility 0s linear 0s; - animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms; + &[aria-expanded='false'] { + & .ExpandIcon { + transform: scaleY(1); } - @media (forced-colors: active) { - /* Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips - background-color will be overriden but border-width is a workaround */ - /* stylelint-disable-next-line primer/borders */ - border-width: 8px; + & ~ .SubGroup { + display: none; } - } - & .SingleSelectCheckmark { - visibility: visible; - } - } + /* show active indicator on parent collapse if child is active */ + /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ + &:has(~ .SubGroup [data-active='true']) { + background: var(--control-transparent-bgColor-selected); - &[aria-checked='false'], - &[aria-selected='false'] { - & .MultiSelectCheckbox { - &::before { - visibility: hidden; + & .ItemLabel { + font-weight: var(--base-text-weight-semibold); + } + + & .ActionListSubContent::before, + & + .ActionListItem .ActionListSubContent::before { + visibility: hidden; + } + + /* blue accent line */ + &::after { + @mixin activeIndicatorLine; + } } } + } - & .SingleSelectCheckmark { - visibility: hidden; + /* [ [content] [trailingVisual] [trailingAction] ] */ + .ActionListSubContent { + grid-area: content; + position: relative; + display: grid; + width: 100%; + grid-template-rows: min-content; + grid-template-areas: 'label trailingVisual trailingAction'; + grid-template-columns: minmax(0, auto) min-content min-content; + align-items: start; + + /* column-gap persists with empty grid-areas, margin applies only when children exist */ + & > :not(:last-child) { + /* stylelint-disable-next-line primer/spacing */ + margin-right: var(--control-medium-gap); } } -} -/* hide by default to support inactive state where role cannot be menuitemradio or menuitemcheckbox */ -.SingleSelectCheckmark { - visibility: hidden; -} + /* place children on grid */ -/* button or a tag */ - -/* [ [spacer] [leadingAction] [leadingVisual] [content] ] */ -.ActionListContent { - --subitem-depth: 0px; - - position: relative; - display: grid; - width: 100%; - color: var(--control-fgColor-rest); - text-align: left; - user-select: none; - background-color: transparent; - border: none; - border-radius: var(--borderRadius-medium); - transition: background 33.333ms linear; - /* stylelint-disable-next-line primer/spacing */ - padding-block: var(--control-medium-paddingBlock); - /* stylelint-disable-next-line primer/spacing */ - padding-inline: var(--control-medium-paddingInline-condensed); - touch-action: manipulation; - -webkit-tap-highlight-color: transparent; - grid-template-rows: min-content; - grid-template-areas: 'spacer leadingAction leadingVisual content'; - grid-template-columns: min-content min-content min-content minmax(0, auto); - align-items: start; - - /* column-gap persists with empty grid-areas, margin applies only when children exist */ - & > :not(:last-child, .Spacer) { - /* stylelint-disable-next-line primer/spacing */ - margin-right: var(--control-medium-gap); + /* spacer used to create depth for nested lists */ + + .Spacer { + display: none; + width: max(0px, var(--subitem-depth) * 8px); + grid-area: spacer; } - &:hover { - text-decoration: none; - cursor: pointer; + .LeadingAction { + grid-area: leadingAction; } - /* large */ + .LeadingVisual { + grid-area: leadingVisual; + } - &[data-size='large'] { - /* stylelint-disable-next-line primer/spacing */ - padding-block: var(--control-large-paddingBlock); + .TrailingVisual { + grid-area: trailingVisual; + font-size: var(--text-body-size-medium); } - /* collapsible item [aria-expanded] */ + .TrailingAction { + grid-area: trailingAction; - &[aria-expanded='true'] { - & .ExpandIcon { - transform: scaleY(-1); + /* if child is loading button */ + & > *[data-loading-wrapper] { + height: 100%; } } - &[aria-expanded='false'] { - & .ExpandIcon { - transform: scaleY(1); - } + /* wrapper span + default block */ + .ItemDescriptionWrap { + grid-area: label; + display: flex; + flex-direction: column; + gap: var(--base-size-4); - & ~ .SubGroup { - display: none; + & .ItemLabel { + font-weight: var(--base-text-weight-semibold); + /* stylelint-disable-next-line declaration-property-value-keyword-no-deprecated */ + word-break: break-word; } - /* show active indicator on parent collapse if child is active */ - /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ - &:has(~ .SubGroup [data-active='true']) { - background: var(--control-transparent-bgColor-selected); + /* inline */ + &:where([data-description-variant='inline']) { + position: relative; + word-break: normal; + flex-direction: row; + align-items: baseline; + gap: var(--base-size-8); & .ItemLabel { - font-weight: var(--base-text-weight-semibold); + word-break: normal; } - & .ActionListSubContent::before, - & + .ActionListItem .ActionListSubContent::before { - visibility: hidden; + /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ + &:has([data-truncate='true']) { + & .ItemLabel { + flex: 1 0 auto; + } } - /* blue accent line */ - &::after { - @mixin activeIndicatorLine; + & .Description { + /* stylelint-disable-next-line primer/typography */ + line-height: 16px; } } } -} - -/* [ [content] [trailingVisual] [trailingAction] ] */ -.ActionListSubContent { - grid-area: content; - position: relative; - display: grid; - width: 100%; - grid-template-rows: min-content; - grid-template-areas: 'label trailingVisual trailingAction'; - grid-template-columns: minmax(0, auto) min-content min-content; - align-items: start; - - /* column-gap persists with empty grid-areas, margin applies only when children exist */ - & > :not(:last-child) { - /* stylelint-disable-next-line primer/spacing */ - margin-right: var(--control-medium-gap); - } -} - -/* place children on grid */ - -/* spacer used to create depth for nested lists */ - -.Spacer { - display: none; - width: max(0px, var(--subitem-depth) * 8px); - grid-area: spacer; -} - -.LeadingAction { - grid-area: leadingAction; -} - -.LeadingVisual { - grid-area: leadingVisual; -} -.TrailingVisual { - grid-area: trailingVisual; - font-size: var(--text-body-size-medium); -} + /* description */ + .Description { + font-size: var(--text-body-size-small); + font-weight: var(--base-text-weight-normal); -.TrailingAction { - grid-area: trailingAction; + /* line-height: var(--text-caption-lineHeight); */ - /* if child is loading button */ - & > *[data-loading-wrapper] { - height: 100%; + /* remove after FF ships */ + /* stylelint-disable-next-line primer/typography */ + line-height: 16px; + color: var(--fgColor-muted); } -} - -/* wrapper span -default block */ -.ItemDescriptionWrap { - grid-area: label; - display: flex; - flex-direction: column; - gap: var(--base-size-4); - & .ItemLabel { - font-weight: var(--base-text-weight-semibold); + /* helper for grid alignment with multi-line content + span wrapping svg or text */ + .VisualWrap { + display: flex; + min-width: max-content; + min-height: var(--base-size-20); + /* stylelint-disable-next-line primer/typography */ + line-height: 20px; + /* temporary until we fix line-height rounding in primitives */ + color: var(--fgColor-muted); + pointer-events: none; + fill: var(--fgColor-muted); + align-items: center; + } + + /* text */ + .ItemLabel { + position: relative; + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-normal); + /* stylelint-disable-next-line primer/typography */ + line-height: 20px; + /* temporary until we fix line-height rounding in primitives */ + color: var(--fgColor-default); + grid-area: label; /* stylelint-disable-next-line declaration-property-value-keyword-no-deprecated */ word-break: break-word; } - /* inline */ - &:where([data-description-variant='inline']) { - position: relative; - word-break: normal; - flex-direction: row; - align-items: baseline; - gap: var(--base-size-8); - + .SubGroup { & .ItemLabel { - word-break: normal; - } - - /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ - &:has([data-truncate='true']) { - & .ItemLabel { - flex: 1 0 auto; - } + font-size: var(--text-body-size-small); } - & .Description { - /* stylelint-disable-next-line primer/typography */ - line-height: 16px; + & .ActionListItem { + margin-inline: 0; } } -} - -/* description */ -.Description { - font-size: var(--text-body-size-small); - font-weight: var(--base-text-weight-normal); - /* line-height: var(--text-caption-lineHeight); */ + /* trailing action icon button */ - /* remove after FF ships */ - /* stylelint-disable-next-line primer/typography */ - line-height: 16px; - color: var(--fgColor-muted); -} - -/* helper for grid alignment with multi-line content -span wrapping svg or text */ -.VisualWrap { - display: flex; - min-width: max-content; - min-height: var(--base-size-20); - /* stylelint-disable-next-line primer/typography */ - line-height: 20px; - /* temporary until we fix line-height rounding in primitives */ - color: var(--fgColor-muted); - pointer-events: none; - fill: var(--fgColor-muted); - align-items: center; -} - -/* text */ -.ItemLabel { - position: relative; - font-size: var(--text-body-size-medium); - font-weight: var(--base-text-weight-normal); - /* stylelint-disable-next-line primer/typography */ - line-height: 20px; - /* temporary until we fix line-height rounding in primitives */ - color: var(--fgColor-default); - grid-area: label; - /* stylelint-disable-next-line declaration-property-value-keyword-no-deprecated */ - word-break: break-word; -} + .TrailingActionButton { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + height: 100%; -.SubGroup { - & .ItemLabel { - font-size: var(--text-body-size-small); + /* Preserve width consistency when loading state is active for text buttons only */ + &[data-loading='true'][data-has-label='true'] { + /* Double the left padding to compensate for missing right padding */ + padding: 0 0 0 calc(var(--base-size-12) * 2); + + /* Position spinner at the end to align with IconButton */ + & [data-component='loadingSpinner'] { + place-self: end; + /* Match the IconButton spinner size */ + width: var(--control-medium-size, 2rem); + height: var(--control-medium-size, 2rem); + /* Ensure spinner is properly centered */ + display: flex; + align-items: center; + justify-content: center; + } + } } - & .ActionListItem { - margin-inline: 0; - } -} + .InactiveButtonWrap { + &[data-position='trailing'] { + grid-area: trailingVisual; + } -/* trailing action icon button */ - -.TrailingActionButton { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - height: 100%; - - /* Preserve width consistency when loading state is active for text buttons only */ - &[data-loading='true'][data-has-label='true'] { - /* Double the left padding to compensate for missing right padding */ - padding: 0 0 0 calc(var(--base-size-12) * 2); - - /* Position spinner at the end to align with IconButton */ - & [data-component='loadingSpinner'] { - place-self: end; - /* Match the IconButton spinner size */ - width: var(--control-medium-size, 2rem); - height: var(--control-medium-size, 2rem); - /* Ensure spinner is properly centered */ - display: flex; - align-items: center; - justify-content: center; + &[data-position='leading'] { + grid-area: leadingVisual; } } -} -.InactiveButtonWrap { - &[data-position='trailing'] { - grid-area: trailingVisual; + .Divider { + display: block; + height: var(--borderWidth-thin); + padding: 0; + /* stylelint-disable-next-line primer/spacing */ + margin-block-start: calc(var(--base-size-8) - var(--borderWidth-thin)); + margin-block-end: var(--base-size-8); + list-style: none; + /* stylelint-disable-next-line primer/colors */ + background: var(--borderColor-muted); + border: 0; } - &[data-position='leading'] { - grid-area: leadingVisual; + .InactiveButtonReset { + display: flex; + padding: 0; + font: inherit; + color: inherit; + cursor: pointer; + background: none; + border: none; } -} - -.Divider { - display: block; - height: var(--borderWidth-thin); - padding: 0; - /* stylelint-disable-next-line primer/spacing */ - margin-block-start: calc(var(--base-size-8) - var(--borderWidth-thin)); - margin-block-end: var(--base-size-8); - list-style: none; - /* stylelint-disable-next-line primer/colors */ - background: var(--borderColor-muted); - border: 0; -} -.InactiveButtonReset { - display: flex; - padding: 0; - font: inherit; - color: inherit; - cursor: pointer; - background: none; - border: none; -} - -.InactiveWarning { - font-size: var(--text-body-size-small); - - /* line-height: var(--text-caption-lineHeight); */ + .InactiveWarning { + font-size: var(--text-body-size-small); - /* use variable when FF removed */ - /* stylelint-disable-next-line primer/typography */ - line-height: 16px; - color: var(--fgColor-attention); - grid-row: 2/2; -} + /* line-height: var(--text-caption-lineHeight); */ -@keyframes checkmarkIn { - from { - clip-path: inset(var(--base-size-16) 0 0 0); + /* use variable when FF removed */ + /* stylelint-disable-next-line primer/typography */ + line-height: 16px; + color: var(--fgColor-attention); + grid-row: 2/2; } - to { - clip-path: inset(0 0 0 0); - } -} + @keyframes checkmarkIn { + from { + clip-path: inset(var(--base-size-16) 0 0 0); + } -@keyframes checkmarkOut { - from { - clip-path: inset(0 0 0 0); + to { + clip-path: inset(0 0 0 0); + } } - to { - clip-path: inset(var(--base-size-16) 0 0 0); + @keyframes checkmarkOut { + from { + clip-path: inset(0 0 0 0); + } + + to { + clip-path: inset(var(--base-size-16) 0 0 0); + } } } diff --git a/packages/react/src/ActionList/Group.module.css b/packages/react/src/ActionList/Group.module.css index 0273e901e77..bd85de75130 100644 --- a/packages/react/src/ActionList/Group.module.css +++ b/packages/react/src/ActionList/Group.module.css @@ -1,77 +1,79 @@ -.Group { - list-style: none; +@layer primer.components.ActionList { + .Group { + list-style: none; - &:not(:first-child) { - margin-block-start: var(--base-size-8); + &:not(:first-child) { + margin-block-start: var(--base-size-8); - /* If somebody tries to pass the `title` prop AND a `NavList.GroupHeading` as a child, hide the `ActionList.GroupHeading */ - /* stylelint-disable-next-line selector-max-specificity, selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ - &:has(.GroupHeadingWrap + ul > .GroupHeadingWrap) { - /* stylelint-disable-next-line selector-max-specificity */ - & > .GroupHeadingWrap { - display: none; + /* If somebody tries to pass the `title` prop AND a `NavList.GroupHeading` as a child, hide the `ActionList.GroupHeading */ + /* stylelint-disable-next-line selector-max-specificity, selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ + &:has(.GroupHeadingWrap + ul > .GroupHeadingWrap) { + /* stylelint-disable-next-line selector-max-specificity */ + & > .GroupHeadingWrap { + display: none; + } } } } -} - -.GroupList { - padding-inline-start: 0; -} -.GroupHeadingWrap { - display: flex; - font-size: var(--text-body-size-small); - font-weight: var(--base-text-weight-semibold); + .GroupList { + padding-inline-start: 0; + } - /* line-height: var(--text-body-lineHeight-small); use when FF rolls out */ - /* stylelint-disable-next-line primer/typography */ - line-height: 18px; - color: var(--fgColor-muted); - flex-direction: column; - padding-inline: var(--base-size-16); - padding-block: var(--base-size-6); + .GroupHeadingWrap { + display: flex; + font-size: var(--text-body-size-small); + font-weight: var(--base-text-weight-semibold); - &:where([data-variant='filled']) { - /* stylelint-disable-next-line primer/spacing */ - margin-block-start: calc(var(--base-size-8) - var(--borderWidth-thin)); - margin-block-end: var(--base-size-8); - background: var(--bgColor-muted); - border-top: solid var(--borderWidth-thin) var(--borderColor-muted); - border-bottom: solid var(--borderWidth-thin) var(--borderColor-muted); + /* line-height: var(--text-body-lineHeight-small); use when FF rolls out */ + /* stylelint-disable-next-line primer/typography */ + line-height: 18px; + color: var(--fgColor-muted); + flex-direction: column; padding-inline: var(--base-size-16); + padding-block: var(--base-size-6); - &:first-child { - margin-block-start: 0; + &:where([data-variant='filled']) { + /* stylelint-disable-next-line primer/spacing */ + margin-block-start: calc(var(--base-size-8) - var(--borderWidth-thin)); + margin-block-end: var(--base-size-8); + background: var(--bgColor-muted); + border-top: solid var(--borderWidth-thin) var(--borderColor-muted); + border-bottom: solid var(--borderWidth-thin) var(--borderColor-muted); + padding-inline: var(--base-size-16); + + &:first-child { + margin-block-start: 0; + } } - } - /* & + ul:has(.GroupHeadingWrap) { - outline: solid 1px red; - } */ -} + /* & + ul:has(.GroupHeadingWrap) { + outline: solid 1px red; + } */ + } -.GroupHeading { - margin: 0; - font-size: var(--text-body-size-small); - font-weight: var(--base-text-weight-semibold); - color: var(--fgColor-muted); - align-self: flex-start; -} + .GroupHeading { + margin: 0; + font-size: var(--text-body-size-small); + font-weight: var(--base-text-weight-semibold); + color: var(--fgColor-muted); + align-self: flex-start; + } -.GroupHeadingWrap[data-has-trailing-action] { - flex-direction: row; - align-items: center; - justify-content: space-between; - gap: var(--base-size-8); + .GroupHeadingWrap[data-has-trailing-action] { + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: var(--base-size-8); - & > .GroupHeading { - align-self: center; + & > .GroupHeading { + align-self: center; + } } -} -.GroupHeadingTrailingAction { - display: inline-flex; - align-items: center; - margin-inline-start: auto; + .GroupHeadingTrailingAction { + display: inline-flex; + align-items: center; + margin-inline-start: auto; + } } diff --git a/packages/react/src/ActionList/Heading.module.css b/packages/react/src/ActionList/Heading.module.css index 1a95511f228..be480b7b6c9 100644 --- a/packages/react/src/ActionList/Heading.module.css +++ b/packages/react/src/ActionList/Heading.module.css @@ -1,12 +1,14 @@ -.ActionListHeader { - margin-block-end: var(--base-size-8); +@layer primer.components.ActionList { + .ActionListHeader { + margin-block-end: var(--base-size-8); - &:where([data-list-variant='full']) { - margin-inline-start: var(--base-size-8); - } + &:where([data-list-variant='full']) { + margin-inline-start: var(--base-size-8); + } - &:where([data-list-variant='inset'], [data-list-variant='horizontal-inset']) { - /* stylelint-disable-next-line primer/spacing */ - margin-inline-start: calc(var(--control-medium-paddingInline-condensed) + var(--base-size-8)); + &:where([data-list-variant='inset'], [data-list-variant='horizontal-inset']) { + /* stylelint-disable-next-line primer/spacing */ + margin-inline-start: calc(var(--control-medium-paddingInline-condensed) + var(--base-size-8)); + } } } diff --git a/packages/react/src/Button/ButtonBase.module.css b/packages/react/src/Button/ButtonBase.module.css index b9c26348a66..52906b0a675 100644 --- a/packages/react/src/Button/ButtonBase.module.css +++ b/packages/react/src/Button/ButtonBase.module.css @@ -1,670 +1,676 @@ -/* Base styles */ -.ButtonBase { - display: flex; - min-width: max-content; - height: var(--control-medium-size); - /* stylelint-disable-next-line primer/spacing */ - padding: 0 var(--control-medium-paddingInline-normal); - font-family: inherit; - font-size: var(--text-body-size-medium); - font-weight: var(--base-text-weight-medium); - color: var(--button-default-fgColor-rest); - text-align: center; - text-decoration: none; - cursor: pointer; - user-select: none; - background-color: transparent; - border: var(--borderWidth-thin) solid; - border-color: var(--button-default-borderColor-rest); - border-radius: var(--borderRadius-medium); - transition: 80ms cubic-bezier(0.65, 0, 0.35, 1); - transition-property: color, fill, background-color, border-color; - appearance: none; - align-items: center; - justify-content: space-between; - gap: var(--base-size-8); - - /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ - &:has([data-kbd-chord]) { - padding-inline-end: var(--base-size-6); - } - - &:hover { - transition-duration: 80ms; - } - - &:focus-visible { - @mixin focusOutline; - } - - &:active { - transition: none; - } - - &:disabled, - &[aria-disabled='true']:not([data-loading='true']) { - cursor: not-allowed; - box-shadow: none; +@layer primer.components.Button { + /* Base styles */ + .ButtonBase { + display: flex; + min-width: max-content; + height: var(--control-medium-size); + /* stylelint-disable-next-line primer/spacing */ + padding: 0 var(--control-medium-paddingInline-normal); + font-family: inherit; + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-medium); + color: var(--button-default-fgColor-rest); + text-align: center; + text-decoration: none; + cursor: pointer; + user-select: none; + background-color: transparent; + border: var(--borderWidth-thin) solid; + border-color: var(--button-default-borderColor-rest); + border-radius: var(--borderRadius-medium); + transition: 80ms cubic-bezier(0.65, 0, 0.35, 1); + transition-property: color, fill, background-color, border-color; + appearance: none; + align-items: center; + justify-content: space-between; + gap: var(--base-size-8); - & .Visual, - & .CounterLabel { - color: inherit; + /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ + &:has([data-kbd-chord]) { + padding-inline-end: var(--base-size-6); } - } - @media (forced-colors: active) { - &:focus { - outline: solid 1px transparent; + &:hover { + transition-duration: 80ms; } - } - /* Visuals */ - & :where(.Visual) { - display: flex; - color: var(--fgColor-muted); - pointer-events: none; - } - - /* mostly for CounterLabel */ - & :where(.VisualWrap) { - display: flex; - pointer-events: none; - } + &:focus-visible { + @mixin focusOutline; + } - /* IconButton */ + &:active { + transition: none; + } - &:where(.IconButton) { - display: inline-grid; - width: var(--control-medium-size); - min-width: unset; - /* stylelint-disable-next-line primer/spacing */ - padding: unset; - place-content: center; - flex-shrink: 0; + &:disabled, + &[aria-disabled='true']:not([data-loading='true']) { + cursor: not-allowed; + box-shadow: none; - &:where([data-size='small']) { - width: var(--control-small-size); + & .Visual, + & .CounterLabel { + color: inherit; + } } - &:where([data-size='large']) { - width: var(--control-large-size); + @media (forced-colors: active) { + &:focus { + outline: solid 1px transparent; + } } - } - - /* LinkButton */ - &:where([href]) { - display: inline-flex; + /* Visuals */ + & :where(.Visual) { + display: flex; + color: var(--fgColor-muted); + pointer-events: none; + } - &:hover { - text-decoration: none; + /* mostly for CounterLabel */ + & :where(.VisualWrap) { + display: flex; + pointer-events: none; } - } - /* Button layout */ + /* IconButton */ - & :where(.ButtonContent) { - flex: 1 0 auto; - display: grid; - grid-template-areas: 'leadingVisual text trailingVisual'; - grid-template-columns: min-content minmax(0, auto) min-content; - align-items: center; - align-content: center; + &:where(.IconButton) { + display: inline-grid; + width: var(--control-medium-size); + min-width: unset; + /* stylelint-disable-next-line primer/spacing */ + padding: unset; + place-content: center; + flex-shrink: 0; - & > :not(:last-child) { - margin-right: var(--base-size-8); + &:where([data-size='small']) { + width: var(--control-small-size); + } + + &:where([data-size='large']) { + width: var(--control-large-size); + } } - /* Content alignment */ + /* LinkButton */ - &:where([data-align='center']) { - justify-content: center; - } + &:where([href]) { + display: inline-flex; - &:where([data-align='start']) { - justify-content: flex-start; + &:hover { + text-decoration: none; + } } - } - - & :where([data-component='leadingVisual']) { - grid-area: leadingVisual; - } - & :where(.Label) { - line-height: var(--text-body-lineHeight-medium); - white-space: nowrap; - grid-area: text; - } + /* Button layout */ - & :where([data-component='trailingVisual']) { - grid-area: trailingVisual; - } + & :where(.ButtonContent) { + flex: 1 0 auto; + display: grid; + grid-template-areas: 'leadingVisual text trailingVisual'; + grid-template-columns: min-content minmax(0, auto) min-content; + align-items: center; + align-content: center; - & :where([data-component='trailingAction']) { - margin-right: calc(var(--base-size-4) * -1); - } + & > :not(:last-child) { + margin-right: var(--base-size-8); + } - /* Size */ + /* Content alignment */ - &:where([data-size='small']) { - height: var(--control-small-size); - /* stylelint-disable-next-line primer/spacing */ - padding: 0 var(--control-small-paddingInline-condensed); - gap: var(--control-small-gap); - font-size: var(--text-body-size-small); + &:where([data-align='center']) { + justify-content: center; + } - & .ButtonContent > :not(:last-child) { - /* stylelint-disable-next-line primer/spacing */ - margin-right: var(--control-small-gap); + &:where([data-align='start']) { + justify-content: flex-start; + } } - & .Label { - line-height: var(--text-body-lineHeight-small); + & :where([data-component='leadingVisual']) { + grid-area: leadingVisual; } - } - &:where([data-size='large']) { - height: var(--control-large-size); - /* stylelint-disable-next-line primer/spacing */ - padding: 0 var(--control-large-paddingInline-spacious); - gap: var(--control-large-gap); - - & .ButtonContent > :not(:last-child) { - /* stylelint-disable-next-line primer/spacing */ - margin-right: var(--control-large-gap); + & :where(.Label) { + line-height: var(--text-body-lineHeight-medium); + white-space: nowrap; + grid-area: text; } - /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ - &:has([data-kbd-chord]) { - padding-inline-end: var(--base-size-8); + & :where([data-component='trailingVisual']) { + grid-area: trailingVisual; } - } - - /* Full width */ - &:where([data-block='block']) { - width: 100%; - } - - /* Wrap label text */ - - &:where([data-label-wrap='true']) { - min-width: fit-content; - height: unset; - min-height: var(--control-medium-size); - - & .ButtonContent { - flex: 1 1 auto; - align-self: stretch; - /* stylelint-disable-next-line primer/spacing */ - padding-block: calc(var(--control-medium-paddingBlock) - var(--base-size-2)); + & :where([data-component='trailingAction']) { + margin-right: calc(var(--base-size-4) * -1); } - & .Label { - /* stylelint-disable-next-line declaration-property-value-keyword-no-deprecated */ - word-break: break-word; - white-space: unset; - } + /* Size */ &:where([data-size='small']) { - height: unset; - min-height: var(--control-small-size); + height: var(--control-small-size); + /* stylelint-disable-next-line primer/spacing */ + padding: 0 var(--control-small-paddingInline-condensed); + gap: var(--control-small-gap); + font-size: var(--text-body-size-small); - & .ButtonContent { + & .ButtonContent > :not(:last-child) { /* stylelint-disable-next-line primer/spacing */ - padding-block: calc(var(--control-small-paddingBlock) - var(--base-size-2)); + margin-right: var(--control-small-gap); + } + + & .Label { + line-height: var(--text-body-lineHeight-small); } } &:where([data-size='large']) { - height: unset; - min-height: var(--control-large-size); + height: var(--control-large-size); /* stylelint-disable-next-line primer/spacing */ - padding-inline: var(--control-large-paddingInline-spacious); + padding: 0 var(--control-large-paddingInline-spacious); + gap: var(--control-large-gap); - & .ButtonContent { + & .ButtonContent > :not(:last-child) { /* stylelint-disable-next-line primer/spacing */ - padding-block: calc(var(--control-large-paddingBlock) - var(--base-size-2)); + margin-right: var(--control-large-gap); } - } - } - - /* Loading */ - /* only hide label if there's no leading/trailing visuals - * move spinner to label spot if not leading/trailing visuals - */ + /* stylelint-disable-next-line selector-pseudo-class-disallowed-list -- scoped to CSS Module, audited (github/github-ui#17224) */ + &:has([data-kbd-chord]) { + padding-inline-end: var(--base-size-8); + } + } - &:where([data-loading='true']) { - & - .LoadingSpinner:not( - [data-component='leadingVisual'], - [data-component='trailingVisual'], - [data-component='trailingAction'] - ) { - grid-area: text; - margin-right: 0 !important; - place-self: center; + /* Full width */ - & + .Label { - visibility: hidden; - } + &:where([data-block='block']) { + width: 100%; } - } - /* Styles for the spinner element displayed when the Button is in a loading state. - * Ensures the spinner is centered within its container. */ - .LoadingSpinner { - display: flex; - align-items: center; - justify-content: center; - } + /* Wrap label text */ - /* Default Variant */ + &:where([data-label-wrap='true']) { + min-width: fit-content; + height: unset; + min-height: var(--control-medium-size); - &:where([data-variant='default']) { - color: var(--button-default-fgColor-rest); - background-color: var(--button-default-bgColor-rest); - box-shadow: var(--button-default-shadow-resting); + & .ButtonContent { + flex: 1 1 auto; + align-self: stretch; + /* stylelint-disable-next-line primer/spacing */ + padding-block: calc(var(--control-medium-paddingBlock) - var(--base-size-2)); + } - &[aria-expanded='true'] { - background-color: var(--button-default-bgColor-active); - border-color: var(--button-default-borderColor-active); - } + & .Label { + /* stylelint-disable-next-line declaration-property-value-keyword-no-deprecated */ + word-break: break-word; + white-space: unset; + } - &:hover { - background-color: var(--button-default-bgColor-hover); - border-color: var(--button-default-borderColor-hover); - } + &:where([data-size='small']) { + height: unset; + min-height: var(--control-small-size); - &:active { - background-color: var(--button-default-bgColor-active); - border-color: var(--button-default-borderColor-active); - } + & .ButtonContent { + /* stylelint-disable-next-line primer/spacing */ + padding-block: calc(var(--control-small-paddingBlock) - var(--base-size-2)); + } + } - &:disabled, - &[aria-disabled='true']:not([data-loading='true']) { - color: var(--control-fgColor-disabled); - background-color: var(--button-default-bgColor-disabled); - border-color: var(--button-default-borderColor-disabled); - box-shadow: none; + &:where([data-size='large']) { + height: unset; + min-height: var(--control-large-size); + /* stylelint-disable-next-line primer/spacing */ + padding-inline: var(--control-large-paddingInline-spacious); - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-default-bgColor-disabled); - color: var(--buttonKeybindingHint-default-fgColor-disabled); - border-color: var(--buttonKeybindingHint-default-borderColor-disabled); + & .ButtonContent { + /* stylelint-disable-next-line primer/spacing */ + padding-block: calc(var(--control-large-paddingBlock) - var(--base-size-2)); + } } } - & .CounterLabel { - background-color: var(--buttonCounter-default-bgColor-rest) !important; /* temporarily override our own sx prop */ - } + /* Loading */ + + /* only hide label if there's no leading/trailing visuals + * move spinner to label spot if not leading/trailing visuals + */ + + &:where([data-loading='true']) { + & + .LoadingSpinner:not( + [data-component='leadingVisual'], + [data-component='trailingVisual'], + [data-component='trailingAction'] + ) { + grid-area: text; + margin-right: 0 !important; + place-self: center; - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-default-bgColor-rest); - color: var(--buttonKeybindingHint-default-fgColor-rest); - border-color: var(--buttonKeybindingHint-default-borderColor-rest); + & + .Label { + visibility: hidden; + } + } } - &:where(.IconButton) { - color: var(--fgColor-muted); + /* Styles for the spinner element displayed when the Button is in a loading state. + * Ensures the spinner is centered within its container. */ + .LoadingSpinner { + display: flex; + align-items: center; + justify-content: center; } - } - /* Primary variant */ + /* Default Variant */ - &:where([data-variant='primary']) { - color: var(--button-primary-fgColor-rest); - background-color: var(--button-primary-bgColor-rest); - border-color: var(--button-primary-borderColor-rest); - box-shadow: var(--shadow-resting-small); + &:where([data-variant='default']) { + color: var(--button-default-fgColor-rest); + background-color: var(--button-default-bgColor-rest); + box-shadow: var(--button-default-shadow-resting); - &[aria-expanded='true'] { - background-color: var(--button-primary-bgColor-active); - box-shadow: var(--button-primary-shadow-selected); - } + &[aria-expanded='true'] { + background-color: var(--button-default-bgColor-active); + border-color: var(--button-default-borderColor-active); + } - &:hover { - background-color: var(--button-primary-bgColor-hover); - border-color: var(--button-primary-borderColor-hover); - } + &:hover { + background-color: var(--button-default-bgColor-hover); + border-color: var(--button-default-borderColor-hover); + } - &:focus-visible { - @mixin focusOutlineOnEmphasis; - } + &:active { + background-color: var(--button-default-bgColor-active); + border-color: var(--button-default-borderColor-active); + } - &:active { - background-color: var(--button-primary-bgColor-active); - box-shadow: var(--button-primary-shadow-selected); - } + &:disabled, + &[aria-disabled='true']:not([data-loading='true']) { + color: var(--control-fgColor-disabled); + background-color: var(--button-default-bgColor-disabled); + border-color: var(--button-default-borderColor-disabled); + box-shadow: none; + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-default-bgColor-disabled); + color: var(--buttonKeybindingHint-default-fgColor-disabled); + border-color: var(--buttonKeybindingHint-default-borderColor-disabled); + } + } - &:disabled, - &[aria-disabled='true']:not([data-loading='true']) { - color: var(--button-primary-fgColor-disabled); - background-color: var(--button-primary-bgColor-disabled); - border-color: var(--button-primary-borderColor-disabled); - box-shadow: none; + & .CounterLabel { + background-color: var( + --buttonCounter-default-bgColor-rest + ) !important; /* temporarily override our own sx prop */ + } & [data-kbd-chord] { - background: var(--buttonKeybindingHint-primary-bgColor-disabled); - color: var(--buttonKeybindingHint-primary-fgColor-disabled); - border-color: var(--buttonKeybindingHint-primary-borderColor-disabled); + background: var(--buttonKeybindingHint-default-bgColor-rest); + color: var(--buttonKeybindingHint-default-fgColor-rest); + border-color: var(--buttonKeybindingHint-default-borderColor-rest); } - } - & .CounterLabel { - color: var(--button-primary-fgColor-rest) !important; /* temporarily override our own sx prop */ - background-color: var(--buttonCounter-primary-bgColor-rest) !important; /* temporarily override our own sx prop */ + &:where(.IconButton) { + color: var(--fgColor-muted); + } } - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-primary-bgColor-rest); - color: var(--buttonKeybindingHint-primary-fgColor-rest); - border-color: var(--buttonKeybindingHint-primary-borderColor-rest); - } + /* Primary variant */ - /* temporarily using the fgColor to match legacy and reduce visual changes- will eventually be iconColor */ - & .Visual { + &:where([data-variant='primary']) { color: var(--button-primary-fgColor-rest); - } - } + background-color: var(--button-primary-bgColor-rest); + border-color: var(--button-primary-borderColor-rest); + box-shadow: var(--shadow-resting-small); - /* Danger variant */ + &[aria-expanded='true'] { + background-color: var(--button-primary-bgColor-active); + box-shadow: var(--button-primary-shadow-selected); + } - &:where([data-variant='danger']) { - color: var(--button-danger-fgColor-rest); - background-color: var(--button-danger-bgColor-rest); - box-shadow: var(--button-default-shadow-resting); + &:hover { + background-color: var(--button-primary-bgColor-hover); + border-color: var(--button-primary-borderColor-hover); + } - &[aria-expanded='true'] { - color: var(--button-danger-fgColor-active); - background-color: var(--button-danger-bgColor-active); - border-color: var(--button-danger-borderColor-active); - box-shadow: var(--button-danger-shadow-selected); + &:focus-visible { + @mixin focusOutlineOnEmphasis; + } - & .Visual { - color: var(--button-danger-iconColor-hover); + &:active { + background-color: var(--button-primary-bgColor-active); + box-shadow: var(--button-primary-shadow-selected); } - } - &:hover { - color: var(--button-danger-fgColor-hover); - background-color: var(--button-danger-bgColor-hover); - border-color: var(--button-danger-borderColor-hover); - box-shadow: var(--shadow-resting-small); + &:disabled, + &[aria-disabled='true']:not([data-loading='true']) { + color: var(--button-primary-fgColor-disabled); + background-color: var(--button-primary-bgColor-disabled); + border-color: var(--button-primary-borderColor-disabled); + box-shadow: none; + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-primary-bgColor-disabled); + color: var(--buttonKeybindingHint-primary-fgColor-disabled); + border-color: var(--buttonKeybindingHint-primary-borderColor-disabled); + } + } & .CounterLabel { - color: var(--buttonCounter-danger-fgColor-hover) !important; /* temporarily override our own sx prop */ - background-color: var(--buttonCounter-danger-bgColor-hover) !important; + color: var(--button-primary-fgColor-rest) !important; /* temporarily override our own sx prop */ + background-color: var( + --buttonCounter-primary-bgColor-rest + ) !important; /* temporarily override our own sx prop */ } & [data-kbd-chord] { - background: var(--buttonKeybindingHint-danger-bgColor-hover); - color: var(--buttonKeybindingHint-danger-fgColor-hover); - border-color: var(--buttonKeybindingHint-danger-borderColor-hover); - transition: 80ms ease-out; + background: var(--buttonKeybindingHint-primary-bgColor-rest); + color: var(--buttonKeybindingHint-primary-fgColor-rest); + border-color: var(--buttonKeybindingHint-primary-borderColor-rest); } + /* temporarily using the fgColor to match legacy and reduce visual changes- will eventually be iconColor */ & .Visual { - color: var(--button-danger-iconColor-hover); + color: var(--button-primary-fgColor-rest); } } - &:active { - color: var(--button-danger-fgColor-active); - background-color: var(--button-danger-bgColor-active); - border-color: var(--button-danger-borderColor-active); - box-shadow: var(--button-danger-shadow-selected); + /* Danger variant */ - & .CounterLabel { - color: var(--buttonCounter-danger-fgColor-hover) !important; /* temporarily override our own sx prop */ - background-color: var(--buttonCounter-danger-bgColor-hover) !important; + &:where([data-variant='danger']) { + color: var(--button-danger-fgColor-rest); + background-color: var(--button-danger-bgColor-rest); + box-shadow: var(--button-default-shadow-resting); + + &[aria-expanded='true'] { + color: var(--button-danger-fgColor-active); + background-color: var(--button-danger-bgColor-active); + border-color: var(--button-danger-borderColor-active); + box-shadow: var(--button-danger-shadow-selected); + + & .Visual { + color: var(--button-danger-iconColor-hover); + } } - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-danger-bgColor-active); - color: var(--buttonKeybindingHint-danger-fgColor-active); - border-color: var(--buttonKeybindingHint-danger-borderColor-active); - transition: 80ms ease-out; + &:hover { + color: var(--button-danger-fgColor-hover); + background-color: var(--button-danger-bgColor-hover); + border-color: var(--button-danger-borderColor-hover); + box-shadow: var(--shadow-resting-small); + + & .CounterLabel { + color: var(--buttonCounter-danger-fgColor-hover) !important; /* temporarily override our own sx prop */ + background-color: var(--buttonCounter-danger-bgColor-hover) !important; + } + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-danger-bgColor-hover); + color: var(--buttonKeybindingHint-danger-fgColor-hover); + border-color: var(--buttonKeybindingHint-danger-borderColor-hover); + transition: 80ms ease-out; + } + + & .Visual { + color: var(--button-danger-iconColor-hover); + } } - & .Visual { - color: var(--button-danger-iconColor-hover); + &:active { + color: var(--button-danger-fgColor-active); + background-color: var(--button-danger-bgColor-active); + border-color: var(--button-danger-borderColor-active); + box-shadow: var(--button-danger-shadow-selected); + + & .CounterLabel { + color: var(--buttonCounter-danger-fgColor-hover) !important; /* temporarily override our own sx prop */ + background-color: var(--buttonCounter-danger-bgColor-hover) !important; + } + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-danger-bgColor-active); + color: var(--buttonKeybindingHint-danger-fgColor-active); + border-color: var(--buttonKeybindingHint-danger-borderColor-active); + transition: 80ms ease-out; + } + + & .Visual { + color: var(--button-danger-iconColor-hover); + } } - } - &:disabled, - &[aria-disabled='true']:not([data-loading='true']) { - color: var(--button-danger-fgColor-disabled); - background-color: var(--button-danger-bgColor-disabled); - border-color: var(--button-default-borderColor-disabled); - box-shadow: none; + &:disabled, + &[aria-disabled='true']:not([data-loading='true']) { + color: var(--button-danger-fgColor-disabled); + background-color: var(--button-danger-bgColor-disabled); + border-color: var(--button-default-borderColor-disabled); + box-shadow: none; + + & .CounterLabel { + color: var(--buttonCounter-danger-fgColor-disabled) !important; /* temporarily override our own sx prop */ + background-color: var(--buttonCounter-danger-bgColor-disabled) !important; + } + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-danger-bgColor-disabled); + color: var(--buttonKeybindingHint-danger-fgColor-disabled); + border-color: var(--buttonKeybindingHint-danger-borderColor-disabled); + } + } & .CounterLabel { - color: var(--buttonCounter-danger-fgColor-disabled) !important; /* temporarily override our own sx prop */ - background-color: var(--buttonCounter-danger-bgColor-disabled) !important; + color: var(--buttonCounter-danger-fgColor-rest) !important; /* temporarily override our own sx prop */ + background-color: var(--buttonCounter-danger-bgColor-rest) !important; } & [data-kbd-chord] { - background: var(--buttonKeybindingHint-danger-bgColor-disabled); - color: var(--buttonKeybindingHint-danger-fgColor-disabled); - border-color: var(--buttonKeybindingHint-danger-borderColor-disabled); + background: var(--buttonKeybindingHint-danger-bgColor-rest); + color: var(--buttonKeybindingHint-danger-fgColor-rest); + border-color: var(--buttonKeybindingHint-danger-borderColor-rest); } - } - - & .CounterLabel { - color: var(--buttonCounter-danger-fgColor-rest) !important; /* temporarily override our own sx prop */ - background-color: var(--buttonCounter-danger-bgColor-rest) !important; - } - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-danger-bgColor-rest); - color: var(--buttonKeybindingHint-danger-fgColor-rest); - border-color: var(--buttonKeybindingHint-danger-borderColor-rest); + & .Visual { + color: var(--button-danger-iconColor-rest); + } } - & .Visual { - color: var(--button-danger-iconColor-rest); - } - } + /* Invisible variant */ - /* Invisible variant */ + &:where([data-variant='invisible']) { + color: var(--button-default-fgColor-rest); + border-color: var(--button-invisible-borderColor-rest); + box-shadow: none; - &:where([data-variant='invisible']) { - color: var(--button-default-fgColor-rest); - border-color: var(--button-invisible-borderColor-rest); - box-shadow: none; + &[aria-expanded='true'] { + background-color: var(--button-invisible-bgColor-active); + } - &[aria-expanded='true'] { - background-color: var(--button-invisible-bgColor-active); - } + &:hover { + background-color: var(--button-invisible-bgColor-hover); + border-color: var(--button-invisible-borderColor-hover); - &:hover { - background-color: var(--button-invisible-bgColor-hover); - border-color: var(--button-invisible-borderColor-hover); + & .Visual { + color: var(--button-invisible-iconColor-hover); + } - & .Visual { - color: var(--button-invisible-iconColor-hover); + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-invisible-bgColor-hover); + transition: 80ms ease-out; + } } - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-invisible-bgColor-hover); - transition: 80ms ease-out; + &:active { + background-color: var(--button-invisible-bgColor-active); + + & .Visual { + color: var(--button-invisible-iconColor-hover); + } + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-invisible-bgColor-active); + transition: 80ms ease-out; + } } - } - &:active { - background-color: var(--button-invisible-bgColor-active); + &:disabled, + &[aria-disabled='true']:not([data-loading='true']) { + color: var(--button-invisible-fgColor-disabled); + background-color: var(--button-invisible-bgColor-disabled); + border-color: var(--button-invisible-borderColor-disabled); + box-shadow: none; + + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-invisible-bgColor-disabled); + color: var(--buttonKeybindingHint-invisible-fgColor-disabled); + border-color: var(--buttonKeybindingHint-invisible-borderColor-disabled); + } + } & .Visual { - color: var(--button-invisible-iconColor-hover); + color: var(--button-invisible-iconColor-rest); } - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-invisible-bgColor-active); - transition: 80ms ease-out; + & .CounterLabel { + background-color: var(--buttonCounter-invisible-bgColor-rest) !important; } - } - - &:disabled, - &[aria-disabled='true']:not([data-loading='true']) { - color: var(--button-invisible-fgColor-disabled); - background-color: var(--button-invisible-bgColor-disabled); - border-color: var(--button-invisible-borderColor-disabled); - box-shadow: none; & [data-kbd-chord] { - background: var(--buttonKeybindingHint-invisible-bgColor-disabled); - color: var(--buttonKeybindingHint-invisible-fgColor-disabled); - border-color: var(--buttonKeybindingHint-invisible-borderColor-disabled); + background: var(--buttonKeybindingHint-invisible-bgColor-rest); + color: var(--buttonKeybindingHint-invisible-fgColor-rest); + border-color: var(--buttonKeybindingHint-invisible-borderColor-rest); } - } - & .Visual { - color: var(--button-invisible-iconColor-rest); + &:where(.IconButton) { + color: var(--button-invisible-iconColor-rest); + } } - & .CounterLabel { - background-color: var(--buttonCounter-invisible-bgColor-rest) !important; - } + /* Link variant */ - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-invisible-bgColor-rest); - color: var(--buttonKeybindingHint-invisible-fgColor-rest); - border-color: var(--buttonKeybindingHint-invisible-borderColor-rest); - } + &:where([data-variant='link']) { + display: inline-flex; + min-width: fit-content; + height: unset; + padding: 0; + font-size: inherit; + color: var(--fgColor-link); + text-align: left; + border: unset; + border-radius: 0; - &:where(.IconButton) { - color: var(--button-invisible-iconColor-rest); - } - } + &:hover:not(:disabled, [data-inactive]) { + text-decoration: underline; + } - /* Link variant */ + &:focus-visible, + &:focus { + outline-offset: 2px; + } - &:where([data-variant='link']) { - display: inline-flex; - min-width: fit-content; - height: unset; - padding: 0; - font-size: inherit; - color: var(--fgColor-link); - text-align: left; - border: unset; - border-radius: 0; - - &:hover:not(:disabled, [data-inactive]) { - text-decoration: underline; - } + &:disabled, + &[aria-disabled='true']:not([data-loading='true']) { + color: var(--control-fgColor-disabled); + background-color: transparent; + border-color: transparent; + } - &:focus-visible, - &:focus { - outline-offset: 2px; - } + & .Label { + white-space: unset; + } - &:disabled, - &[aria-disabled='true']:not([data-loading='true']) { - color: var(--control-fgColor-disabled); - background-color: transparent; - border-color: transparent; - } + &:where([data-inactive]) { + color: var(--button-inactive-fgColor); + background: transparent !important; + } - & .Label { - white-space: unset; + & .Visual { + color: var(--fgColor-link); + } } - &:where([data-inactive]) { - color: var(--button-inactive-fgColor); - background: transparent !important; - } + [data-a11y-link-underlines='true'] &:where([data-variant='link']) { + &[data-no-visuals] { + text-decoration: underline; - & .Visual { - color: var(--fgColor-link); - } - } + &:hover { + text-decoration: none; + } + } - [data-a11y-link-underlines='true'] &:where([data-variant='link']) { - &[data-no-visuals] { - text-decoration: underline; + &:not([data-no-visuals]) { + background-image: linear-gradient(to right, currentColor, currentColor); + background-size: 100% 1.5px; + background-position: 0 calc(100% - 2px); + background-repeat: no-repeat; - &:hover { - text-decoration: none; + &:hover { + text-decoration: none; + } } } - &:not([data-no-visuals]) { - background-image: linear-gradient(to right, currentColor, currentColor); - background-size: 100% 1.5px; - background-position: 0 calc(100% - 2px); - background-repeat: no-repeat; - - &:hover { + [data-a11y-link-underlines='false'] &:where([data-variant='link']) { + &[data-no-visuals] { text-decoration: none; + background-image: none; } - } - } - [data-a11y-link-underlines='false'] &:where([data-variant='link']) { - &[data-no-visuals] { - text-decoration: none; - background-image: none; + &:not([data-no-visuals]) { + background-image: none; + } } - &:not([data-no-visuals]) { - background-image: none; - } - } + /* Inactive */ - /* Inactive */ - - &:where([data-inactive]), - &:where([data-inactive]):hover, - &:where([data-inactive]):active { - color: var(--button-inactive-fgColor); - cursor: auto; - background-color: var(--button-inactive-bgColor); - /* stylelint-disable-next-line primer/colors */ - border-color: var(--button-inactive-bgColor); - box-shadow: none; - - & .Visual, - & .CounterLabel { - color: inherit !important; - } + &:where([data-inactive]), + &:where([data-inactive]):hover, + &:where([data-inactive]):active { + color: var(--button-inactive-fgColor); + cursor: auto; + background-color: var(--button-inactive-bgColor); + /* stylelint-disable-next-line primer/colors */ + border-color: var(--button-inactive-bgColor); + box-shadow: none; - & [data-kbd-chord] { - background: var(--buttonKeybindingHint-inactive-bgColor); - color: var(--buttonKeybindingHint-inactive-fgColor); - border-color: var(--buttonKeybindingHint-inactive-borderColor); - } - } + & .Visual, + & .CounterLabel { + color: inherit !important; + } - /* Icon-only + Counter */ + & [data-kbd-chord] { + background: var(--buttonKeybindingHint-inactive-bgColor); + color: var(--buttonKeybindingHint-inactive-fgColor); + border-color: var(--buttonKeybindingHint-inactive-borderColor); + } + } - &:where([data-icon-only-counter]) { - /* stylelint-disable-next-line primer/spacing */ - padding-inline: var(--control-medium-paddingInline-condensed); + /* Icon-only + Counter */ - &:where([data-size='small']) { + &:where([data-icon-only-counter]) { /* stylelint-disable-next-line primer/spacing */ - padding-inline: var(--control-xsmall-paddingInline-condensed); - } + padding-inline: var(--control-medium-paddingInline-condensed); - &:where([data-size='large']) { - /* stylelint-disable-next-line primer/spacing */ - padding-inline: var(--control-large-paddingInline-normal); + &:where([data-size='small']) { + /* stylelint-disable-next-line primer/spacing */ + padding-inline: var(--control-xsmall-paddingInline-condensed); + } + + &:where([data-size='large']) { + /* stylelint-disable-next-line primer/spacing */ + padding-inline: var(--control-large-paddingInline-normal); + } } } -} -.ConditionalWrapper { - display: block; -} + .ConditionalWrapper { + display: block; + } -.ConditionalWrapperLink { - display: inline-flex; -} + .ConditionalWrapperLink { + display: inline-flex; + } -[data-kbd-chord] { - transition: 80ms ease-in; - transition-property: color, background-color, border-color; + [data-kbd-chord] { + transition: 80ms ease-in; + transition-property: color, background-color, border-color; + } } diff --git a/packages/react/src/__tests__/css-layers.test.ts b/packages/react/src/__tests__/css-layers.test.ts index 7b72598fba5..da9b787ff6a 100644 --- a/packages/react/src/__tests__/css-layers.test.ts +++ b/packages/react/src/__tests__/css-layers.test.ts @@ -84,6 +84,10 @@ const allowlist = new Set([ path.resolve(import.meta.dirname, '../Token/_TokenTextContainer.module.css'), path.resolve(import.meta.dirname, '../TextInputWithTokens/TextInputWithTokens.module.css'), path.resolve(import.meta.dirname, '../TooltipV2/Tooltip.module.css'), + path.resolve(import.meta.dirname, '../Button/ButtonBase.module.css'), + 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'), ]) const files = Array.from(allowlist).map(file => { return [path.relative(path.resolve(import.meta.dirname, '..'), file), file]