From 8f6cfff4e3ba477f3c39ab6a63db30cc7843bead Mon Sep 17 00:00:00 2001 From: NriotHrreion Date: Fri, 4 Sep 2026 16:37:55 +0800 Subject: [PATCH 1/4] refactor(styles): introduce nesting stylesheet syntax --- packages/styles/dist/gitlab-ui.css | 394 ++++++------ packages/styles/package.json | 1 + packages/styles/postcss.config.mjs | 9 +- .../styles/scripts/fixtures/nesting-forms.css | 39 ++ packages/styles/scripts/fixtures/nesting.css | 5 + .../styles/scripts/form-foundations.test.mjs | 8 +- .../styles/scripts/legacy-prefix.test.mjs | 133 +++- .../scripts/postcss-gitlab-tailwind.mjs | 17 +- .../styles/src/dropdowns/new-dropdown.css | 465 +++++++------- .../src/forms/bootstrap-custom-forms.css | 368 ++++++----- packages/styles/src/forms/bootstrap-forms.css | 4 +- .../src/forms/gitlab-check-controls.css | 171 +++--- .../styles/src/forms/gitlab-text-controls.css | 119 ++-- .../styles/src/tables/bootstrap-tables.css | 578 ++++++++---------- packages/styles/src/typography.css | 20 +- packages/ui/src/base/accordion/accordion.css | 6 +- packages/ui/src/base/alert/alert.css | 6 +- .../base/attribute-list/attribute-list.css | 18 +- .../base/avatar-labeled/avatar-labeled.css | 26 +- .../ui/src/base/avatar-link/avatar-link.css | 48 +- packages/ui/src/base/badge/badge.css | 430 ++++++------- .../broadcast-message/broadcast-message.css | 52 +- .../ui/src/base/button-group/button-group.css | 218 +++---- packages/ui/src/base/button/button.css | 86 +-- .../disclosure-dropdown.css | 20 +- .../src/base/form-checkbox/form-checkbox.css | 83 ++- packages/ui/src/base/form-date/form-date.css | 10 +- .../ui/src/base/form-input/form-input.css | 105 ++-- .../ui/src/base/form-select/form-select.css | 144 +++-- packages/ui/src/base/icon/icon.css | 62 +- packages/ui/src/base/label/label.css | 192 +++--- packages/ui/src/base/link/link.css | 112 ++-- .../ui/src/base/loading-icon/loading-icon.css | 44 +- packages/ui/src/base/table/table.css | 158 ++--- packages/ui/src/base/toggle/toggle.css | 471 +++++++------- packages/ui/src/base/tooltip/tooltip.css | 44 +- pnpm-lock.yaml | 23 + 37 files changed, 2339 insertions(+), 2350 deletions(-) create mode 100644 packages/styles/scripts/fixtures/nesting-forms.css create mode 100644 packages/styles/scripts/fixtures/nesting.css diff --git a/packages/styles/dist/gitlab-ui.css b/packages/styles/dist/gitlab-ui.css index eec152b..effaa30 100644 --- a/packages/styles/dist/gitlab-ui.css +++ b/packages/styles/dist/gitlab-ui.css @@ -2773,31 +2773,31 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { a { color: var(--gl-text-color-link); text-decoration-line: none; - &:hover { - @media (hover: hover) { - color: var(--gl-text-color-link); - } +} +@media (hover: hover) { +a:hover { + color: var(--gl-text-color-link) } - &:hover { - @media (hover: hover) { - text-decoration-line: underline; } +@media (hover: hover) { +a:hover { + text-decoration-line: underline } -} + } a:not([href]):not([class]) { color: inherit; text-decoration-line: none; - &:hover { - @media (hover: hover) { - color: inherit; - } +} +@media (hover: hover) { +a:not([href]):not([class]):hover { + color: inherit } - &:hover { - @media (hover: hover) { - text-decoration-line: none; } +@media (hover: hover) { +a:not([href]):not([class]):hover { + text-decoration-line: none } -} + } caption { color: var(--gl-text-color-subtle); } @@ -4032,21 +4032,23 @@ table.gl-table:is( .b-table-stacked, .b-table-stacked-sm, .b-table-stacked-md, . border-radius: var(--gl-alert-border-radius); padding-inline: calc(3rem + var(--gl-alert-padding-x, 0px)); position: relative; - @media (forced-colors: active) { +} +@media (forced-colors: active) { + .gl-alert { border: 1px solid transparent; } - &::before { - content: ""; - display: block; - width: 100%; - height: 2px; - position: absolute; - top: -1px; - left: 0; - } - .gl-link:not(.gl-label-link) { - text-decoration-line: underline; - } +} +.gl-alert::before { + content: ""; + display: block; + width: 100%; + height: 2px; + position: absolute; + top: -1px; + left: 0; +} +.gl-alert .gl-link:not(.gl-label-link) { + text-decoration-line: underline; } .gl-alert-not-dismissible { padding-right: calc(1rem + var(--gl-alert-padding-x, 0px)); @@ -4072,9 +4074,9 @@ table.gl-table:is( .b-table-stacked, .b-table-stacked-sm, .b-table-stacked-md, . display: flex; align-items: center; height: 1.25rem; - .gl-alert-has-title & { - top: calc(0.75rem + 2px); - } +} +.gl-alert-has-title .gl-alert-icon-container { + top: calc(0.75rem + 2px); } .gl-alert-body { --tw-leading: var(--gl-line-height-20); @@ -4117,83 +4119,83 @@ table.gl-table:is( .b-table-stacked, .b-table-stacked-sm, .b-table-stacked-md, . position: absolute; top: calc(0.75rem + 2px); right: calc(0.75rem + var(--gl-alert-padding-x, 0px)); - .gl-alert-has-title & { - top: 0.75rem; - } +} +.gl-alert-has-title .gl-dismiss-btn { + top: 0.75rem; } .gl-alert-danger { background-color: var(--gl-alert-danger-background-color); border-bottom: 1px solid var(--gl-alert-danger-border-bottom-color); - &::before { - background: linear-gradient( to right, transparent 0%, var(--gl-alert-danger-border-top-color) 50%, transparent 100% ); - } - .gl-alert-title { - color: var(--gl-alert-danger-title-color); - } - @media (forced-colors: none) { - .gl-alert-icon { - color: var(--gl-feedback-danger-icon-color); - } +} +.gl-alert-danger::before { + background: linear-gradient( to right, transparent 0%, var(--gl-alert-danger-border-top-color) 50%, transparent 100% ); +} +.gl-alert-danger .gl-alert-title { + color: var(--gl-alert-danger-title-color); +} +@media (forced-colors: none) { + .gl-alert-danger .gl-alert-icon { + color: var(--gl-feedback-danger-icon-color); } } .gl-alert-warning { background-color: var(--gl-alert-warning-background-color); border-bottom: 1px solid var(--gl-alert-warning-border-bottom-color); - &::before { - background: linear-gradient( to right, transparent 0%, var(--gl-alert-warning-border-top-color) 50%, transparent 100% ); - } - .gl-alert-title { - color: var(--gl-alert-warning-title-color); - } - @media (forced-colors: none) { - .gl-alert-icon { - color: var(--gl-feedback-warning-icon-color); - } +} +.gl-alert-warning::before { + background: linear-gradient( to right, transparent 0%, var(--gl-alert-warning-border-top-color) 50%, transparent 100% ); +} +.gl-alert-warning .gl-alert-title { + color: var(--gl-alert-warning-title-color); +} +@media (forced-colors: none) { + .gl-alert-warning .gl-alert-icon { + color: var(--gl-feedback-warning-icon-color); } } .gl-alert-tip { background-color: var(--gl-alert-neutral-background-color); border-bottom: 1px solid var(--gl-alert-neutral-border-bottom-color); - &::before { - background: linear-gradient( to right, transparent 0%, var(--gl-alert-neutral-border-top-color) 50%, transparent 100% ); - } - .gl-alert-title { - color: var(--gl-alert-neutral-title-color); - } - @media (forced-colors: none) { - .gl-alert-icon { - color: var(--gl-feedback-neutral-icon-color); - } +} +.gl-alert-tip::before { + background: linear-gradient( to right, transparent 0%, var(--gl-alert-neutral-border-top-color) 50%, transparent 100% ); +} +.gl-alert-tip .gl-alert-title { + color: var(--gl-alert-neutral-title-color); +} +@media (forced-colors: none) { + .gl-alert-tip .gl-alert-icon { + color: var(--gl-feedback-neutral-icon-color); } } .gl-alert-info { background-color: var(--gl-alert-info-background-color); border-bottom: 1px solid var(--gl-alert-info-border-bottom-color); - &::before { - background: linear-gradient( to right, transparent 0%, var(--gl-alert-info-border-top-color) 50%, transparent 100% ); - } - .gl-alert-title { - color: var(--gl-alert-info-title-color); - } - @media (forced-colors: none) { - .gl-alert-icon { - color: var(--gl-feedback-info-icon-color); - } +} +.gl-alert-info::before { + background: linear-gradient( to right, transparent 0%, var(--gl-alert-info-border-top-color) 50%, transparent 100% ); +} +.gl-alert-info .gl-alert-title { + color: var(--gl-alert-info-title-color); +} +@media (forced-colors: none) { + .gl-alert-info .gl-alert-icon { + color: var(--gl-feedback-info-icon-color); } } .gl-alert-success { background-color: var(--gl-alert-success-background-color); border-bottom: 1px solid var(--gl-alert-success-border-bottom-color); - &::before { - background: linear-gradient( to right, transparent 0%, var(--gl-alert-success-border-top-color) 50%, transparent 100% ); - } - .gl-alert-title { - color: var(--gl-alert-success-title-color); - } - @media (forced-colors: none) { - .gl-alert-icon { - color: var(--gl-feedback-success-icon-color); - } +} +.gl-alert-success::before { + background: linear-gradient( to right, transparent 0%, var(--gl-alert-success-border-top-color) 50%, transparent 100% ); +} +.gl-alert-success .gl-alert-title { + color: var(--gl-alert-success-title-color); +} +@media (forced-colors: none) { + .gl-alert-success .gl-alert-icon { + color: var(--gl-feedback-success-icon-color); } } .gl-attribute-list-container { @@ -4902,104 +4904,104 @@ a.gl-badge.badge-tier:not(.disabled):active, a.gl-badge.badge-tier:not(.disabled padding-left: calc(1rem + var(--gl-broadcast-message-padding-x, 0px)); padding-right: calc(0.75rem + var(--gl-broadcast-message-padding-x, 0px)); padding-block: var(--gl-spacing-scale-5); - &.indigo { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-indigo); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-indigo); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-indigo); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-indigo); - } - &.light-indigo { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightindigo); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightindigo); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightindigo); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightindigo); - } - &.blue { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-blue); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-blue); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-blue); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-blue); - } - &.light-blue { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightblue); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightblue); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightblue); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightblue); - } - &.green { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-green); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-green); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-green); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-green); - } - &.light-green { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightgreen); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightgreen); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightgreen); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightgreen); - } - &.red { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-red); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-red); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-red); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-red); - } - &.light-red { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightred); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightred); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightred); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightred); - } - &.dark { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-dark); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-dark); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-dark); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-dark); - } - &.light { - --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-light); - --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-light); - --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-light); - --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-light); - } - &[class~="banner"] { - background-color: var(--gl-broadcast-message-bg-color); - box-shadow: inset 0 -1px 0 0 var(--gl-broadcast-message-border-color); - color: var(--gl-broadcast-message-text-color); - .gl-broadcast-message-icon { - color: var(--gl-broadcast-message-icon-color); - } - } - &.notification { - border-style: var(--tw-border-style); - border-width: 1px; - border-style: solid; - border-color: var(--gl-border-color-default); - --tw-shadow: var(--gl-shadow-md); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - background-color: var(--gl-background-color-overlap); - color: var(--gl-text-color-default); - border-radius: var(--gl-broadcast-banner-border-radius); - max-width: 18.75rem; - } +} +.gl-broadcast-message.indigo { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-indigo); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-indigo); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-indigo); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-indigo); +} +.gl-broadcast-message.light-indigo { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightindigo); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightindigo); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightindigo); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightindigo); +} +.gl-broadcast-message.blue { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-blue); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-blue); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-blue); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-blue); +} +.gl-broadcast-message.light-blue { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightblue); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightblue); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightblue); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightblue); +} +.gl-broadcast-message.green { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-green); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-green); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-green); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-green); +} +.gl-broadcast-message.light-green { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightgreen); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightgreen); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightgreen); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightgreen); +} +.gl-broadcast-message.red { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-red); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-red); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-red); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-red); +} +.gl-broadcast-message.light-red { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-lightred); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-lightred); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-lightred); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-lightred); +} +.gl-broadcast-message.dark { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-dark); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-dark); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-dark); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-dark); +} +.gl-broadcast-message.light { + --gl-broadcast-message-bg-color: var(--gl-broadcast-banner-background-color-light); + --gl-broadcast-message-border-color: var(--gl-broadcast-banner-border-color-light); + --gl-broadcast-message-text-color: var(--gl-broadcast-banner-text-color-light); + --gl-broadcast-message-icon-color: var(--gl-broadcast-banner-icon-color-light); +} +.gl-broadcast-message[class~="banner"] { + background-color: var(--gl-broadcast-message-bg-color); + box-shadow: inset 0 -1px 0 0 var(--gl-broadcast-message-border-color); + color: var(--gl-broadcast-message-text-color); +} +.gl-broadcast-message[class~="banner"] .gl-broadcast-message-icon { + color: var(--gl-broadcast-message-icon-color); +} +.gl-broadcast-message.notification { + border-style: var(--tw-border-style); + border-width: 1px; + border-style: solid; + border-color: var(--gl-border-color-default); + --tw-shadow: var(--gl-shadow-md); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + background-color: var(--gl-background-color-overlap); + color: var(--gl-text-color-default); + border-radius: var(--gl-broadcast-banner-border-radius); + max-width: 18.75rem; } .gl-broadcast-message-content { display: flex; justify-content: center; - a { - color: inherit; - text-decoration-line: underline; - } - p:last-of-type { - margin-bottom: var(--gl-spacing-scale-0); - } +} +.gl-broadcast-message-content a { + color: inherit; + text-decoration-line: underline; +} +.gl-broadcast-message-content p:last-of-type { + margin-bottom: var(--gl-spacing-scale-0); } .gl-broadcast-message-icon { margin-right: var(--gl-spacing-scale-5); line-height: 1rem; - > svg { - vertical-align: bottom; - } +} +.gl-broadcast-message-icon > svg { + vertical-align: bottom; } .gl-broadcast-message-text { margin-top: -0.125rem; @@ -5481,9 +5483,13 @@ a.gl-badge.badge-tier:not(.disabled):active, a.gl-badge.badge-tier:not(.disabled --tw-border-style: solid; border-style: solid; border-color: transparent; - @media (prefers-contrast: more) { +} +@media (prefers-contrast: more) { +.gl-card { border-color: var(--gl-border-color-strong); +} } +.gl-card{ display: flex; flex-direction: column; overflow-wrap: break-word; @@ -5502,32 +5508,42 @@ a.gl-badge.badge-tier:not(.disabled):active, a.gl-badge.badge-tier:not(.disabled margin-block: var(--gl-spacing-scale-1); border-top-left-radius: calc(var(--gl-card-border-radius) - 1px); border-top-right-radius: calc(var(--gl-card-border-radius) - 1px); - h2, h3, h4, h5, h6 { - font-size: var(--gl-font-size-base); - color: var(--gl-text-color-heading); - margin: var(--gl-spacing-scale-0); - } +} +.gl-card-header h2, .gl-card-header h3, .gl-card-header h4, .gl-card-header h5, .gl-card-header h6 { + font-size: var(--gl-font-size-base); + color: var(--gl-text-color-heading); + margin: var(--gl-spacing-scale-0); } .gl-card-body { flex-grow: 1; padding: var(--gl-spacing-scale-3); background-color: var(--gl-background-color-default); - @media (prefers-contrast: more) { +} +@media (prefers-contrast: more) { +.gl-card-body { border-style: var(--tw-border-style); border-width: 1px; +} } - @media (prefers-contrast: more) { +@media (prefers-contrast: more) { +.gl-card-body { border-style: solid; border-color: var(--gl-border-color-default); +} } - @media (forced-colors: active) { +@media (forced-colors: active) { +.gl-card-body { border-style: var(--tw-border-style); border-width: 1px; +} } - @media (forced-colors: active) { +@media (forced-colors: active) { +.gl-card-body { border-style: solid; border-color: var(--gl-border-color-default); +} } +.gl-card-body{ border-radius: calc(var(--gl-card-border-radius) - 0.25rem); } .gl-card-footer { @@ -6904,12 +6920,14 @@ table.gl-table.table-borderless tr > :is(th, td) { background-color: var(--gl-skeleton-loader-background-color); background-image: linear-gradient(to right, var(--gl-skeleton-loader-background-color) 0, var(--gl-skeleton-loader-shimmer-color) 23%, var(--gl-skeleton-loader-shimmer-color) 27%, var(--gl-skeleton-loader-background-color) 50%); background-repeat: no-repeat; - @media (prefers-reduced-motion: no-preference) { +} +@media (prefers-reduced-motion: no-preference) { +.gl-animate-skeleton-loader { animation: gl-keyframes-skeleton-loader 2.5s linear; animation-delay: inherit; - animation-iteration-count: 3; - } + animation-iteration-count: 3 } + } .\!gl-max-w-20 { max-width: var(--gl-spacing-scale-20) !important; } diff --git a/packages/styles/package.json b/packages/styles/package.json index 2f28905..ecac0af 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -23,6 +23,7 @@ "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "postcss": "^8.5.26", + "postcss-nested": "^8.0.1", "postcss-selector-parser": "7.1.0", "tailwindcss": "^4.3.3" }, diff --git a/packages/styles/postcss.config.mjs b/packages/styles/postcss.config.mjs index 79aff69..ee9aacc 100644 --- a/packages/styles/postcss.config.mjs +++ b/packages/styles/postcss.config.mjs @@ -1,5 +1,12 @@ +import postcssNested from "postcss-nested"; + import gitlabTailwind from "./scripts/postcss-gitlab-tailwind.mjs"; +/** @internal */ +export function createPostcssPlugins(tailwindOptions) { + return [gitlabTailwind(tailwindOptions), postcssNested()]; +} + export default { - plugins: [gitlabTailwind()], + plugins: createPostcssPlugins(), }; diff --git a/packages/styles/scripts/fixtures/nesting-forms.css b/packages/styles/scripts/fixtures/nesting-forms.css new file mode 100644 index 0000000..19e065f --- /dev/null +++ b/packages/styles/scripts/fixtures/nesting-forms.css @@ -0,0 +1,39 @@ +.nesting-fixture, +.nesting-alternate { + color: black; + + &:hover, + &.selected { + color: blue; + } + + &-suffix { + color: green; + } + + .descendant { + display: inline; + } + + > .child, + + .adjacent, + ~ .sibling { + display: block; + } + + .ancestor & { + color: red; + } + + @media (width >= 40rem) { + color: purple; + } + + @supports (display: grid) { + display: grid; + } + + @container (width >= 20rem) { + inline-size: 100%; + } +} diff --git a/packages/styles/scripts/fixtures/nesting.css b/packages/styles/scripts/fixtures/nesting.css new file mode 100644 index 0000000..5d38431 --- /dev/null +++ b/packages/styles/scripts/fixtures/nesting.css @@ -0,0 +1,5 @@ +.imported-nesting-fixture { + &-suffix { + color: green; + } +} diff --git a/packages/styles/scripts/form-foundations.test.mjs b/packages/styles/scripts/form-foundations.test.mjs index 8ae1f15..1c403dd 100644 --- a/packages/styles/scripts/form-foundations.test.mjs +++ b/packages/styles/scripts/form-foundations.test.mjs @@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url"; import postcss from "postcss"; import selectorParser from "postcss-selector-parser"; import { expect, test } from "vitest"; -import gitlabTailwind from "./postcss-gitlab-tailwind.mjs"; +import { createPostcssPlugins } from "../postcss.config.mjs"; const packageDirectory = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const inputPath = path.join(packageDirectory, "src/index.css"); @@ -12,11 +12,11 @@ const fixtureDirectory = path.join(packageDirectory, "scripts/fixtures"); async function compile() { const input = await readFile(inputPath, "utf8"); - const result = await postcss([ - gitlabTailwind({ + const result = await postcss( + createPostcssPlugins({ sources: [{ base: fixtureDirectory, pattern: "*.html", negated: false }], }), - ]).process(input, { from: inputPath }); + ).process(input, { from: inputPath }); return postcss.parse(result.css); } diff --git a/packages/styles/scripts/legacy-prefix.test.mjs b/packages/styles/scripts/legacy-prefix.test.mjs index d519770..e5a4698 100644 --- a/packages/styles/scripts/legacy-prefix.test.mjs +++ b/packages/styles/scripts/legacy-prefix.test.mjs @@ -2,9 +2,10 @@ import { readFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import postcss from "postcss"; +import selectorParser from "postcss-selector-parser"; import { expect, test } from "vitest"; +import { createPostcssPlugins } from "../postcss.config.mjs"; import { toTailwindCandidate } from "./legacy-prefix.mjs"; -import gitlabTailwind from "./postcss-gitlab-tailwind.mjs"; const packageDirectory = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const inputPath = path.join(packageDirectory, "src/index.css"); @@ -22,11 +23,11 @@ test("converts upstream gl-* candidates without changing variant order", () => { test("compiles @apply and restores upstream gl-* selectors", async () => { const input = await readFile(inputPath, "utf8"); - const result = await postcss([ - gitlabTailwind({ + const result = await postcss( + createPostcssPlugins({ sources: [{ base: fixtureDirectory, pattern: "*.html", negated: false }], }), - ]).process(input, { from: inputPath }); + ).process(input, { from: inputPath }); expect(result.css).not.toMatch(/@apply/u); expect(result.css).toMatch(/body\s*\{[^}]*background-color:/su); @@ -40,11 +41,11 @@ test("compiles @apply and restores upstream gl-* selectors", async () => { expect(result.css).not.toMatch(/:where\(\.gl-dark \*\)/u); }, 30000); -test("hoists plugin keyframes while preserving nested media rules", async () => { +test("hoists plugin keyframes and expands nested media rules", async () => { const input = await readFile(inputPath, "utf8"); - const result = await postcss([ - gitlabTailwind({ candidates: ["animate-skeleton-loader"] }), - ]).process(input, { from: inputPath }); + const result = await postcss( + createPostcssPlugins({ candidates: ["animate-skeleton-loader"] }), + ).process(input, { from: inputPath }); const root = postcss.parse(result.css); const skeletonRule = root.nodes.find( (node) => node.type === "rule" && node.selector === ".gl-animate-skeleton-loader", @@ -56,14 +57,124 @@ test("hoists plugin keyframes while preserving nested media rules", async () => ); expect(skeletonRule).toBeDefined(); - expect(skeletonRule.nodes.some( - (node) => node.type === "atrule" && node.name === "media", - )).toBe(true); + expect(skeletonRule.nodes.some((node) => node.type === "atrule")).toBe(false); expect(skeletonRule.nodes.some( (node) => node.type === "atrule" && node.name === "keyframes", )).toBe(false); expect(keyframes).toBeDefined(); + const reducedMotionRules = root.nodes + .filter( + (node) => node.type === "atrule" + && node.name === "media" + && node.params.includes("prefers-reduced-motion"), + ) + .flatMap((node) => node.nodes ?? []); + expect(reducedMotionRules.some( + (node) => node.type === "rule" && node.selector === ".gl-animate-skeleton-loader", + )).toBe(true); expect(result.css).toContain( "\n@keyframes gl-keyframes-skeleton-loader {\n 0% {", ); }, 30000); + +test("expands the Sass-like nesting forms used by upstream styles", async () => { + const inputPath = path.join(fixtureDirectory, "nesting-forms.css"); + const input = await readFile(inputPath, "utf8"); + const result = await postcss(createPostcssPlugins()).process(input, { from: inputPath }); + const root = postcss.parse(result.css); + const selectorsForDeclaration = (property, value, container = root) => { + const selectors = []; + container.walkRules((rule) => { + if(rule.nodes.some( + (node) => node.type === "decl" && node.prop === property && node.value === value, + )) selectors.push(...rule.selectors); + }); + return selectors.sort(); + }; + const findAtRule = (name) => root.nodes.find( + (node) => node.type === "atrule" && node.name === name, + ); + + expect(selectorsForDeclaration("color", "blue")).toEqual([ + ".nesting-alternate.selected", + ".nesting-alternate:hover", + ".nesting-fixture.selected", + ".nesting-fixture:hover", + ]); + expect(selectorsForDeclaration("color", "green")).toEqual([ + ".nesting-alternate-suffix", + ".nesting-fixture-suffix", + ]); + expect(selectorsForDeclaration("display", "inline")).toEqual([ + ".nesting-alternate .descendant", + ".nesting-fixture .descendant", + ]); + expect(selectorsForDeclaration("display", "block")).toEqual([ + ".nesting-alternate + .adjacent", + ".nesting-alternate > .child", + ".nesting-alternate ~ .sibling", + ".nesting-fixture + .adjacent", + ".nesting-fixture > .child", + ".nesting-fixture ~ .sibling", + ]); + expect(selectorsForDeclaration("color", "red")).toEqual([ + ".ancestor .nesting-alternate", + ".ancestor .nesting-fixture", + ]); + + const media = findAtRule("media"); + const supports = findAtRule("supports"); + const container = findAtRule("container"); + expect(media?.params).toBe("(width >= 40rem)"); + expect(supports?.params).toBe("(display: grid)"); + expect(container?.params).toBe("(width >= 20rem)"); + expect(selectorsForDeclaration("color", "purple", media)).toEqual([ + ".nesting-alternate", + ".nesting-fixture", + ]); + expect(selectorsForDeclaration("display", "grid", supports)).toEqual([ + ".nesting-alternate", + ".nesting-fixture", + ]); + expect(selectorsForDeclaration("inline-size", "100%", container)).toEqual([ + ".nesting-alternate", + ".nesting-fixture", + ]); +}); + +test("expands suffix nesting in imported stylesheets before Tailwind parses it", async () => { + const from = path.join(packageDirectory, "scripts/nesting-entry.css"); + const result = await postcss(createPostcssPlugins()).process( + "@import \"./fixtures/nesting.css\";", + { from }, + ); + + expect(result.css).toContain(".imported-nesting-fixture-suffix {"); + expect(result.css).not.toContain(":is(.imported-nesting-fixture)-suffix"); +}); + +test("published stylesheet contains only expanded rules", async () => { + const input = await readFile(inputPath, "utf8"); + const result = await postcss(createPostcssPlugins()).process(input, { from: inputPath }); + const root = postcss.parse(result.css); + const nestedRules = []; + const nestedAtRules = []; + const nestingSelectors = []; + + root.walkRules((rule) => { + if(rule.parent?.type === "rule") nestedRules.push(rule.selector); + selectorParser((selectorRoot) => { + selectorRoot.walkNesting(() => nestingSelectors.push(rule.selector)); + }).processSync(rule.selector); + }); + root.walkAtRules((atRule) => { + if(atRule.parent?.type === "rule") nestedAtRules.push(`@${atRule.name} ${atRule.params}`); + }); + + expect(result.css).not.toMatch(/@apply/u); + expect(result.css).toContain(".gl-alert-danger {"); + expect(result.css).not.toContain(":is(.gl-alert)-danger"); + expect(nestedRules).toEqual([]); + expect(nestedAtRules).toEqual([]); + expect(nestingSelectors).toEqual([]); +}, 30000); diff --git a/packages/styles/scripts/postcss-gitlab-tailwind.mjs b/packages/styles/scripts/postcss-gitlab-tailwind.mjs index fd9a078..3925e50 100644 --- a/packages/styles/scripts/postcss-gitlab-tailwind.mjs +++ b/packages/styles/scripts/postcss-gitlab-tailwind.mjs @@ -4,6 +4,7 @@ import path from "node:path"; import { loadModule } from "@tailwindcss/node"; import { Scanner } from "@tailwindcss/oxide"; +import postcssNested from "postcss-nested"; import { compile } from "tailwindcss"; import { @@ -33,6 +34,20 @@ function compilerSources(compiler, base) { return sources; } +async function prepareStylesheet(postcss, content, from) { + // Tailwind parses imported stylesheets before downstream PostCSS plugins run. + // Expand source nesting here so Sass-style selectors such as `&-suffix` + // survive that import step; the configured postcss-nested pass still handles + // any nesting left in Tailwind's completed AST. + const rewritten = rewriteLegacyApplyDirectives(content, from); + const result = await postcss([postcssNested()]).process(rewritten, { + from, + map: false, + }); + + return result.css; +} + function removeOneIndentLevel(node) { for(const property of ["before", "after"]) { const rawValue = node.raws[property]; @@ -89,7 +104,7 @@ export default function gitlabTailwind({ candidates = [], sources: additionalSou return { path: stylesheetPath, base: path.dirname(stylesheetPath), - content: rewriteLegacyApplyDirectives(content, stylesheetPath), + content: await prepareStylesheet(postcss, content, stylesheetPath), }; }, }); diff --git a/packages/styles/src/dropdowns/new-dropdown.css b/packages/styles/src/dropdowns/new-dropdown.css index a6b63ff..a04d33d 100644 --- a/packages/styles/src/dropdowns/new-dropdown.css +++ b/packages/styles/src/dropdowns/new-dropdown.css @@ -15,52 +15,58 @@ @apply gl-block gl-w-full; } -.gl-new-dropdown .gl-new-dropdown-toggle.gl-button:not(.gl-new-dropdown-toggle-no-caret, .btn-icon) { - @apply gl-pr-3; -} +.gl-new-dropdown { + .gl-new-dropdown-toggle.gl-button:not(.gl-new-dropdown-toggle-no-caret, .btn-icon) { + @apply gl-pr-3; + } -.gl-new-dropdown .gl-new-dropdown-toggle.gl-button.btn-sm:not(.gl-new-dropdown-toggle-no-caret, .btn-icon) { - @apply gl-pr-2; -} + .gl-new-dropdown-toggle.gl-button.btn-sm:not(.gl-new-dropdown-toggle-no-caret, .btn-icon) { + @apply gl-pr-2; + } -.gl-new-dropdown .gl-new-dropdown-toggle .gl-button-text { - @apply gl-inline-flex gl-items-center; -} + .gl-new-dropdown-toggle { + .gl-button-text { + @apply gl-inline-flex gl-items-center; -.gl-new-dropdown .gl-new-dropdown-toggle .gl-button-text:has(.gl-sr-only) { - width: auto; -} + &:has(.gl-sr-only) { + width: auto; + } + } + } -.gl-new-dropdown .gl-new-dropdown-button-text { - @apply gl-mr-auto gl-overflow-hidden gl-text-ellipsis; -} + .gl-new-dropdown-button-text { + @apply gl-mr-auto gl-overflow-hidden gl-text-ellipsis; + } -.gl-new-dropdown .gl-button:not(.gl-new-dropdown-caret-only) .gl-button-icon.gl-new-dropdown-chevron { - @apply gl-ml-2 gl-mr-0; -} + .gl-button:not(.gl-new-dropdown-caret-only) .gl-button-icon.gl-new-dropdown-chevron { + @apply gl-ml-2 gl-mr-0; + } -.gl-new-dropdown .gl-new-dropdown-icon-only.gl-button:not(.gl-new-dropdown-toggle-no-caret) { - @apply gl-pl-3 gl-pr-2; -} + .gl-new-dropdown-icon-only { + &.gl-button:not(.gl-new-dropdown-toggle-no-caret) { + @apply gl-pl-3 gl-pr-2; + } -.gl-new-dropdown .gl-new-dropdown-icon-only.gl-button.btn-sm:not(.gl-new-dropdown-toggle-no-caret) { - @apply gl-pr-0; -} + &.gl-button.btn-sm:not(.gl-new-dropdown-toggle-no-caret) { + @apply gl-pr-0; + } -.gl-new-dropdown .gl-new-dropdown-icon-only .gl-button-icon.gl-button-icon { - @apply gl-mr-0; -} + .gl-button-icon.gl-button-icon { + @apply gl-mr-0; + } -.gl-new-dropdown .gl-new-dropdown-icon-only .gl-button-icon.gl-button-loading-indicator { - @apply gl-mr-2; -} + .gl-button-icon.gl-button-loading-indicator { + @apply gl-mr-2; + } + } -.gl-new-dropdown .gl-new-dropdown-caret-only { - @apply gl-pl-2; -} + .gl-new-dropdown-caret-only { + @apply gl-pl-2; -.gl-new-dropdown .gl-new-dropdown-caret-only.btn-sm { - @apply gl-pl-0; + &.btn-sm { + @apply gl-pl-0; + } + } } .gl-new-dropdown-container { @@ -122,89 +128,91 @@ - 0.5rem ) ); -} -.gl-new-dropdown-contents:focus-visible { - box-shadow: - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color); - outline: none; -} + &:focus-visible { + box-shadow: + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color); + outline: none; + } -.gl-new-dropdown-contents ul { - @apply gl-list-none; + ul { + @apply gl-list-none; + } } .gl-new-dropdown-contents-with-scrim-overlay { padding: 0; } -.gl-new-dropdown-contents .top-scrim-wrapper, -.gl-new-dropdown-contents .bottom-scrim-wrapper { - position: sticky; - right: 1px; - left: 1px; - z-index: 1; - display: block; - height: 0.25rem; - overflow: visible; - pointer-events: none; - opacity: 0; - transition: opacity 0.1s; -} +.gl-new-dropdown-contents { + .top-scrim-wrapper, + .bottom-scrim-wrapper { + position: sticky; + right: 1px; + left: 1px; + z-index: 1; + display: block; + height: 0.25rem; + overflow: visible; + pointer-events: none; + opacity: 0; + transition: opacity 0.1s; + } -.gl-new-dropdown-contents .top-scrim-wrapper { - top: 0; -} + .top-scrim-wrapper { + top: 0; + } -.gl-new-dropdown-contents .top-scrim { - position: absolute; - right: 0; - left: 0; -} + .top-scrim { + position: absolute; + right: 0; + left: 0; + } -.gl-new-dropdown-contents .top-scrim-light { - height: 2.25rem; - background: linear-gradient( - 180deg, - var(--gl-dropdown-background-color) 0%, - var(--gl-color-alpha-0) - ); - border-radius: 0.375rem 0.375rem 0 0; -} + .top-scrim-light { + height: 2.25rem; + background: linear-gradient( + 180deg, + var(--gl-dropdown-background-color) 0%, + var(--gl-color-alpha-0) + ); + border-radius: 0.375rem 0.375rem 0 0; + } -.gl-new-dropdown-contents .top-scrim-dark { - height: 0.25rem; - background: linear-gradient( - 180deg, - var(--gl-shadow-color-default) 0%, - var(--gl-color-alpha-0) 100% - ); -} + .top-scrim-dark { + height: 0.25rem; + background: linear-gradient( + 180deg, + var(--gl-shadow-color-default) 0%, + var(--gl-color-alpha-0) 100% + ); + } -.gl-new-dropdown-contents .bottom-scrim-wrapper { - bottom: 0; -} + .bottom-scrim-wrapper { + bottom: 0; + } -.gl-new-dropdown-contents .bottom-scrim { - position: relative; - top: -2rem; - height: 0; - background: linear-gradient( - 180deg, - var(--gl-color-alpha-0) 0%, - var(--gl-dropdown-background-color) - ); - border-radius: 0 0 0.375rem 0.375rem; -} + .bottom-scrim { + position: relative; + top: -2rem; + height: 0; + background: linear-gradient( + 180deg, + var(--gl-color-alpha-0) 0%, + var(--gl-dropdown-background-color) + ); + border-radius: 0 0 0.375rem 0.375rem; + } -.gl-new-dropdown-contents.top-scrim-visible .top-scrim-wrapper, -.gl-new-dropdown-contents.bottom-scrim-visible .bottom-scrim-wrapper { - opacity: 1; -} + &.top-scrim-visible .top-scrim-wrapper, + &.bottom-scrim-visible .bottom-scrim-wrapper { + opacity: 1; + } -.gl-new-dropdown-contents.bottom-scrim-visible .bottom-scrim { - height: 2.25rem; + &.bottom-scrim-visible .bottom-scrim { + height: 2.25rem; + } } .gl-new-dropdown-arrow { @@ -273,102 +281,96 @@ box-shadow 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); } -.gl-new-dropdown-item:not([data-disabled]):hover > .gl-new-dropdown-item-content { - color: var(--gl-dropdown-option-text-color-hover); - background-color: var(--gl-dropdown-option-background-color-unselected-hover); -} - -.gl-new-dropdown-item:not([data-disabled])[data-highlighted] > .gl-new-dropdown-item-content, -.gl-new-dropdown-item:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content { - color: var(--gl-dropdown-option-text-color-focus); - background-color: var(--gl-dropdown-option-background-color-unselected-focus); -} - -.gl-new-dropdown-item:not([data-disabled]):active > .gl-new-dropdown-item-content, -.gl-new-dropdown-item:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content, -.gl-new-dropdown-item:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { - box-shadow: - inset 0 0 0 2px var(--gl-focus-ring-outer-color), - inset 0 0 0 3px var(--gl-focus-ring-inner-color), - inset 0 0 0 1px var(--gl-focus-ring-inner-color); -} - -.gl-new-dropdown-item:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content { - z-index: 1; -} - -.gl-new-dropdown-item:not([data-disabled]):active > .gl-new-dropdown-item-content, -.gl-new-dropdown-item:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { - color: var(--gl-dropdown-option-text-color-active); - background-color: var(--gl-dropdown-option-background-color-unselected-active); -} - -.gl-new-dropdown-item[data-disabled] { - @apply gl-cursor-not-allowed gl-select-none; -} - -.gl-new-dropdown-item[data-disabled] > .gl-new-dropdown-item-content { - color: var(--gl-text-color-disabled); - pointer-events: none; -} - -.gl-new-dropdown-item[aria-selected="true"] > .gl-new-dropdown-item-content { - background-color: var(--gl-dropdown-option-background-color-selected-default); -} +.gl-new-dropdown-item { + &:not([data-disabled]):hover > .gl-new-dropdown-item-content { + color: var(--gl-dropdown-option-text-color-hover); + background-color: var(--gl-dropdown-option-background-color-unselected-hover); + } -.gl-new-dropdown-item[aria-selected="true"][data-disabled] - > .gl-new-dropdown-item-content, -.gl-new-dropdown-item[aria-selected="true"].disabled - > .gl-new-dropdown-item-content { - background-color: var(--gl-background-color-disabled); -} + &:not([data-disabled])[data-highlighted] > .gl-new-dropdown-item-content, + &:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content { + color: var(--gl-dropdown-option-text-color-focus); + background-color: var(--gl-dropdown-option-background-color-unselected-focus); + } -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):hover - > .gl-new-dropdown-item-content { - background-color: var(--gl-dropdown-option-background-color-selected-hover); -} + &:not([data-disabled]):active > .gl-new-dropdown-item-content, + &:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content, + &:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { + box-shadow: + inset 0 0 0 2px var(--gl-focus-ring-outer-color), + inset 0 0 0 3px var(--gl-focus-ring-inner-color), + inset 0 0 0 1px var(--gl-focus-ring-inner-color); + } -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):hover - .gl-new-dropdown-item-check-icon { - color: var(--gl-dropdown-option-indicator-color-selected-hover); -} + &:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content { + z-index: 1; + } -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled)[data-highlighted] - > .gl-new-dropdown-item-content, -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):focus-visible - > .gl-new-dropdown-item-content { - background-color: var(--gl-dropdown-option-background-color-selected-focus); -} + &:not([data-disabled]):active > .gl-new-dropdown-item-content, + &:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { + color: var(--gl-dropdown-option-text-color-active); + background-color: var(--gl-dropdown-option-background-color-unselected-active); + } -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled)[data-highlighted] - .gl-new-dropdown-item-check-icon, -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):focus-visible - .gl-new-dropdown-item-check-icon { - color: var(--gl-dropdown-option-indicator-color-selected-focus); -} + &[data-disabled] { + @apply gl-cursor-not-allowed gl-select-none; -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):active - > .gl-new-dropdown-item-content, -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):focus-visible:active - > .gl-new-dropdown-item-content { - background-color: var(--gl-dropdown-option-background-color-selected-active); -} + > .gl-new-dropdown-item-content { + color: var(--gl-text-color-disabled); + pointer-events: none; + } + } -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):active - .gl-new-dropdown-item-check-icon, -.gl-new-dropdown-item[aria-selected="true"]:not([data-disabled], .disabled):focus-visible:active - .gl-new-dropdown-item-check-icon { - color: var(--gl-dropdown-option-indicator-color-selected-active); -} + &[aria-selected="true"] { + > .gl-new-dropdown-item-content { + background-color: var(--gl-dropdown-option-background-color-selected-default); + } + + &[data-disabled] > .gl-new-dropdown-item-content, + &.disabled > .gl-new-dropdown-item-content { + background-color: var(--gl-background-color-disabled); + } + + &:not([data-disabled], .disabled):hover { + > .gl-new-dropdown-item-content { + background-color: var(--gl-dropdown-option-background-color-selected-hover); + } + + .gl-new-dropdown-item-check-icon { + color: var(--gl-dropdown-option-indicator-color-selected-hover); + } + } + + &:not([data-disabled], .disabled)[data-highlighted] > .gl-new-dropdown-item-content, + &:not([data-disabled], .disabled):focus-visible > .gl-new-dropdown-item-content { + background-color: var(--gl-dropdown-option-background-color-selected-focus); + } + + &:not([data-disabled], .disabled)[data-highlighted] .gl-new-dropdown-item-check-icon, + &:not([data-disabled], .disabled):focus-visible .gl-new-dropdown-item-check-icon { + color: var(--gl-dropdown-option-indicator-color-selected-focus); + } + + &:not([data-disabled], .disabled):active > .gl-new-dropdown-item-content, + &:not([data-disabled], .disabled):focus-visible:active > .gl-new-dropdown-item-content { + background-color: var(--gl-dropdown-option-background-color-selected-active); + } + + &:not([data-disabled], .disabled):active .gl-new-dropdown-item-check-icon, + &:not([data-disabled], .disabled):focus-visible:active .gl-new-dropdown-item-check-icon { + color: var(--gl-dropdown-option-indicator-color-selected-active); + } + } -.gl-new-dropdown-item.gl-new-dropdown-item-highlighted:not([data-disabled], .disabled) - > .gl-new-dropdown-item-content { - color: var(--gl-dropdown-option-text-color-focus); - background-color: var(--gl-dropdown-option-background-color-unselected-focus); - box-shadow: - inset 0 0 0 2px var(--gl-focus-ring-outer-color), - inset 0 0 0 3px var(--gl-focus-ring-inner-color), - inset 0 0 0 1px var(--gl-focus-ring-inner-color); + &.gl-new-dropdown-item-highlighted:not([data-disabled], .disabled) + > .gl-new-dropdown-item-content { + color: var(--gl-dropdown-option-text-color-focus); + background-color: var(--gl-dropdown-option-background-color-unselected-focus); + box-shadow: + inset 0 0 0 2px var(--gl-focus-ring-outer-color), + inset 0 0 0 3px var(--gl-focus-ring-inner-color), + inset 0 0 0 1px var(--gl-focus-ring-inner-color); + } } .gl-new-dropdown-item-check-icon { @@ -376,9 +378,11 @@ color: var(--gl-dropdown-option-indicator-color-selected-default); } -.gl-new-dropdown-item[data-disabled] .gl-new-dropdown-item-check-icon, -.gl-new-dropdown-item.disabled .gl-new-dropdown-item-check-icon { - color: var(--gl-icon-color-disabled); +.gl-new-dropdown-item { + &[data-disabled] .gl-new-dropdown-item-check-icon, + &.disabled .gl-new-dropdown-item-check-icon { + color: var(--gl-icon-color-disabled); + } } .gl-new-dropdown-item-text-wrapper { @@ -387,50 +391,58 @@ .gl-new-dropdown-item-icon { @apply gl-mr-2 gl-inline-block gl-h-5 gl-w-5 gl-shrink-0; -} -.gl-new-dropdown-item-icon .gl-icon { - vertical-align: -3px; + .gl-icon { + vertical-align: -3px; + } } -.gl-new-dropdown-item-danger > .gl-new-dropdown-item-content { - color: var(--gl-action-danger-foreground-color-default); - background-color: var(--gl-action-danger-background-color-default); -} +.gl-new-dropdown-item-danger { + > .gl-new-dropdown-item-content { + color: var(--gl-action-danger-foreground-color-default); + background-color: var(--gl-action-danger-background-color-default); + } -.gl-new-dropdown-item-danger:not([data-disabled]):hover > .gl-new-dropdown-item-content { - color: var(--gl-action-danger-foreground-color-hover); - background-color: var(--gl-action-danger-background-color-hover); -} + &:not([data-disabled]):hover > .gl-new-dropdown-item-content { + color: var(--gl-action-danger-foreground-color-hover); + background-color: var(--gl-action-danger-background-color-hover); + } -.gl-new-dropdown-item-danger:not([data-disabled])[data-highlighted] > .gl-new-dropdown-item-content, -.gl-new-dropdown-item-danger:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content { - color: var(--gl-action-danger-foreground-color-focus); - background-color: var(--gl-action-danger-background-color-focus); -} + &:not([data-disabled])[data-highlighted] > .gl-new-dropdown-item-content, + &:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content { + color: var(--gl-action-danger-foreground-color-focus); + background-color: var(--gl-action-danger-background-color-focus); + } -.gl-new-dropdown-item-danger:not([data-disabled]):active > .gl-new-dropdown-item-content, -.gl-new-dropdown-item-danger:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { - color: var(--gl-action-danger-foreground-color-active); - background-color: var(--gl-action-danger-background-color-active); + &:not([data-disabled]):active > .gl-new-dropdown-item-content, + &:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { + color: var(--gl-action-danger-foreground-color-active); + background-color: var(--gl-action-danger-background-color-active); + } } -.btn-group .gl-new-dropdown:not(:last-child) .gl-new-dropdown-toggle { - @apply gl-rounded-br-none gl-rounded-tr-none; -} +.btn-group { + .gl-new-dropdown:not(:last-child) { + .gl-new-dropdown-toggle { + @apply gl-rounded-br-none gl-rounded-tr-none; + } + } -.btn-group .gl-new-dropdown:not(:first-child) .gl-new-dropdown-toggle { - @apply gl-rounded-bl-none gl-rounded-tl-none; -} + .gl-new-dropdown:not(:first-child) { + .gl-new-dropdown-toggle { + @apply gl-rounded-bl-none gl-rounded-tl-none; + } + } -.btn-group .gl-new-dropdown:hover .gl-new-dropdown-toggle, -.btn-group .gl-new-dropdown .gl-new-dropdown-toggle:focus-visible, -.btn-group .gl-new-dropdown .gl-new-dropdown-toggle:active { - @apply gl-z-1; + .gl-new-dropdown:hover .gl-new-dropdown-toggle, + .gl-new-dropdown .gl-new-dropdown-toggle:focus-visible, + .gl-new-dropdown .gl-new-dropdown-toggle:active { + @apply gl-z-1; + } } -@media (prefers-reduced-motion) { - .gl-new-dropdown-item-content { +.gl-new-dropdown-item-content { + @media (prefers-reduced-motion) { transition-duration: 0.01ms !important; transition-delay: 0ms !important; } @@ -439,7 +451,8 @@ @media (forced-colors: active) { .gl-new-dropdown-item:not([data-disabled]):active > .gl-new-dropdown-item-content, .gl-new-dropdown-item:not([data-disabled]):focus-visible > .gl-new-dropdown-item-content, - .gl-new-dropdown-item:not([data-disabled]):focus-visible:active > .gl-new-dropdown-item-content { + .gl-new-dropdown-item:not([data-disabled]):focus-visible:active + > .gl-new-dropdown-item-content { outline: 2px solid LinkText; box-shadow: none; } diff --git a/packages/styles/src/forms/bootstrap-custom-forms.css b/packages/styles/src/forms/bootstrap-custom-forms.css index c88f22e..d589295 100644 --- a/packages/styles/src/forms/bootstrap-custom-forms.css +++ b/packages/styles/src/forms/bootstrap-custom-forms.css @@ -63,13 +63,13 @@ width: 1rem; height: 1.25rem; opacity: 0; -} -/* The active (pressed) state. */ -.gl-form-checkbox .custom-control-input:not(:disabled):active ~ .custom-control-label::before, -.gl-form-radio .custom-control-input:not(:disabled):active ~ .custom-control-label::before { - background-color: #b3d7ff; - border-color: #b3d7ff; + /* The active (pressed) state. */ + &:not(:disabled):active ~ .custom-control-label::before { + background-color: #b3d7ff; + border-color: #b3d7ff; + } + } .gl-form-checkbox .custom-control-label, @@ -79,104 +79,96 @@ display: inline-block; margin-bottom: 0; vertical-align: top; -} -/* Background-color and border (the box) */ -.gl-form-checkbox .custom-control-label::before, -.gl-form-radio .custom-control-label::before { - position: absolute; - top: 0.25rem; - left: -1.5rem; - display: block; - width: 1rem; - height: 1rem; - pointer-events: none; - content: ""; - border-width: 1px; - border-style: solid; - /* `$custom-forms-transition` */ - transition: - background-color 0.15s ease-in-out, - border-color 0.15s ease-in-out, - box-shadow 0.15s ease-in-out; -} - -@media (prefers-reduced-motion: reduce) { - .gl-form-checkbox .custom-control-label::before, - .gl-form-radio .custom-control-label::before { - transition: none; + /* Background-color and border (the box) */ + &::before { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + pointer-events: none; + content: ""; + border-width: 1px; + border-style: solid; + /* `$custom-forms-transition` */ + transition: + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; + + @media (prefers-reduced-motion: reduce) { + transition: none; + } } -} -/* Foreground (the indicator icon) */ -.gl-form-checkbox .custom-control-label::after, -.gl-form-radio .custom-control-label::after { - position: absolute; - top: 0.25rem; - left: -1.5rem; - display: block; - width: 1rem; - height: 1rem; - content: ""; - background: 50% / 50% 50% no-repeat; + /* Foreground (the indicator icon) */ + &::after { + position: absolute; + top: 0.25rem; + left: -1.5rem; + display: block; + width: 1rem; + height: 1rem; + content: ""; + background: 50% / 50% 50% no-repeat; + } } /* `form-validation-state` for `.custom-control-input`; only the * component-controlled `.is-valid` / `.is-invalid` selectors. */ -.gl-form-checkbox .custom-control-input.is-valid ~ .custom-control-label, -.gl-form-radio .custom-control-input.is-valid ~ .custom-control-label { - color: #2f7549; -} - -.gl-form-checkbox .custom-control-input.is-valid ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-valid ~ .custom-control-label::before { - border-color: #2f7549; -} - -.gl-form-checkbox .custom-control-input.is-valid:checked ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-valid:checked ~ .custom-control-label::before { - background-color: #3e9960; - border-color: #3e9960; -} - -.gl-form-checkbox .custom-control-input.is-valid:focus-visible ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-valid:focus-visible ~ .custom-control-label::before { - box-shadow: 0 0 0 0.2rem rgba(47, 117, 73, 0.25); -} - -.gl-form-checkbox .custom-control-input.is-valid:focus-visible:not(:checked) - ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-valid:focus-visible:not(:checked) - ~ .custom-control-label::before { - border-color: #2f7549; -} - -.gl-form-checkbox .custom-control-input.is-invalid ~ .custom-control-label, -.gl-form-radio .custom-control-input.is-invalid ~ .custom-control-label { - color: #c02f12; -} - -.gl-form-checkbox .custom-control-input.is-invalid ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-invalid ~ .custom-control-label::before { - border-color: #c02f12; -} - -.gl-form-checkbox .custom-control-input.is-invalid:checked ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-invalid:checked ~ .custom-control-label::before { - background-color: #ea3e1b; - border-color: #ea3e1b; -} - -.gl-form-checkbox .custom-control-input.is-invalid:focus-visible ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-invalid:focus-visible ~ .custom-control-label::before { - box-shadow: 0 0 0 0.2rem rgba(192, 47, 18, 0.25); -} +.gl-form-checkbox .custom-control-input, +.gl-form-radio .custom-control-input { + &.is-valid { + ~ .custom-control-label { + color: #2f7549; + + &::before { + border-color: #2f7549; + } + } + + &:checked ~ .custom-control-label::before { + background-color: #3e9960; + border-color: #3e9960; + } + + &:focus-visible { + ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(47, 117, 73, 0.25); + } + + &:not(:checked) ~ .custom-control-label::before { + border-color: #2f7549; + } + } + } -.gl-form-checkbox .custom-control-input.is-invalid:focus-visible:not(:checked) - ~ .custom-control-label::before, -.gl-form-radio .custom-control-input.is-invalid:focus-visible:not(:checked) - ~ .custom-control-label::before { - border-color: #c02f12; + &.is-invalid { + ~ .custom-control-label { + color: #c02f12; + + &::before { + border-color: #c02f12; + } + } + + &:checked ~ .custom-control-label::before { + background-color: #ea3e1b; + border-color: #ea3e1b; + } + + &:focus-visible { + ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(192, 47, 18, 0.25); + } + + &:not(:checked) ~ .custom-control-label::before { + border-color: #c02f12; + } + } + } } /* `.custom-select` base. Component-specific overrides are kept in the @@ -189,19 +181,17 @@ background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -} -@media (prefers-reduced-motion: reduce) { - .gl-form-select.custom-select { + @media (prefers-reduced-motion: reduce) { transition: none; } -} -.gl-form-select.custom-select[multiple], -.gl-form-select.custom-select[size]:not([size="1"]) { - height: auto; - padding-right: 0.75rem; - background-image: none; + &[multiple], + &[size]:not([size="1"]) { + height: auto; + padding-right: 0.75rem; + background-image: none; + } } /* `.custom-range` base (thumb/track). */ @@ -211,101 +201,103 @@ padding: 0; /* Need to reset padding */ background-color: transparent; appearance: none; -} -.gl-form-input.custom-range:focus-visible { - outline: 0; -} + &:focus-visible { + outline: 0; -/* Pseudo-elements must be split across multiple rulesets to have an effect. */ -.gl-form-input.custom-range:focus-visible::-webkit-slider-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} + /* Pseudo-elements must be split across multiple rulesets to have an effect. */ + &::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + } -.gl-form-input.custom-range:focus-visible::-moz-range-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} - -.gl-form-input.custom-range::-moz-focus-outer { - border: 0; -} - -.gl-form-input.custom-range::-webkit-slider-thumb { - appearance: none; - width: 1rem; - height: 1rem; - margin-top: -0.25rem; /* WebKit specific */ - background-color: #007bff; - border: 0; - border-radius: 1rem; - /* `$custom-forms-transition` */ - transition: - background-color 0.15s ease-in-out, - border-color 0.15s ease-in-out, - box-shadow 0.15s ease-in-out; -} + &::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + } + } -.gl-form-input.custom-range::-webkit-slider-thumb:active { - background-color: #b3d7ff; -} + &::-moz-focus-outer { + border: 0; + } -.gl-form-input.custom-range::-webkit-slider-runnable-track { - width: 100%; - height: 0.5rem; - color: transparent; - cursor: pointer; - background-color: #dee2e6; - border-color: transparent; - border-radius: 1rem; -} + &::-webkit-slider-thumb { + appearance: none; + width: 1rem; + height: 1rem; + margin-top: -0.25rem; /* WebKit specific */ + background-color: #007bff; + border: 0; + border-radius: 1rem; + /* `$custom-forms-transition` */ + transition: + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; + + &:active { + background-color: #b3d7ff; + } + } -.gl-form-input.custom-range::-moz-range-thumb { - appearance: none; - width: 1rem; - height: 1rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - /* `$custom-forms-transition` */ - transition: - background-color 0.15s ease-in-out, - border-color 0.15s ease-in-out, - box-shadow 0.15s ease-in-out; -} + &::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; + } -.gl-form-input.custom-range::-moz-range-thumb:active { - background-color: #b3d7ff; -} + &::-moz-range-thumb { + appearance: none; + width: 1rem; + height: 1rem; + background-color: #007bff; + border: 0; + border-radius: 1rem; + /* `$custom-forms-transition` */ + transition: + background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, + box-shadow 0.15s ease-in-out; + + &:active { + background-color: #b3d7ff; + } + } -.gl-form-input.custom-range::-moz-range-track { - width: 100%; - height: 0.5rem; - color: transparent; - cursor: pointer; - background-color: #dee2e6; - border-color: transparent; - border-radius: 1rem; -} + &::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; + } -@media (prefers-reduced-motion: reduce) { - .gl-form-input.custom-range::-webkit-slider-thumb, - .gl-form-input.custom-range::-moz-range-thumb { - transition: none; + @media (prefers-reduced-motion: reduce) { + &::-webkit-slider-thumb, + &::-moz-range-thumb { + transition: none; + } } -} -.gl-form-input.custom-range:disabled::-webkit-slider-thumb { - background-color: #adb5bd; -} + &:disabled { + &::-webkit-slider-thumb { + background-color: #adb5bd; + } -.gl-form-input.custom-range:disabled::-webkit-slider-runnable-track { - cursor: default; -} + &::-webkit-slider-runnable-track { + cursor: default; + } -.gl-form-input.custom-range:disabled::-moz-range-thumb { - background-color: #adb5bd; -} + &::-moz-range-thumb { + background-color: #adb5bd; + } -.gl-form-input.custom-range:disabled::-moz-range-track { - cursor: default; + &::-moz-range-track { + cursor: default; + } + } } diff --git a/packages/styles/src/forms/bootstrap-forms.css b/packages/styles/src/forms/bootstrap-forms.css index f4a06c0..b41586f 100644 --- a/packages/styles/src/forms/bootstrap-forms.css +++ b/packages/styles/src/forms/bootstrap-forms.css @@ -54,8 +54,8 @@ textarea.gl-form-textarea { margin-top: 0.25rem; } -@media (prefers-reduced-motion: reduce) { - .gl-form-input.form-control { +.gl-form-input.form-control { + @media (prefers-reduced-motion: reduce) { transition: none; } } diff --git a/packages/styles/src/forms/gitlab-check-controls.css b/packages/styles/src/forms/gitlab-check-controls.css index 6cc3d61..2586c97 100644 --- a/packages/styles/src/forms/gitlab-check-controls.css +++ b/packages/styles/src/forms/gitlab-check-controls.css @@ -10,10 +10,10 @@ * radios. Only genuinely component-private rules stay in the component CSS: * the indicator shapes, mask images and the checkbox indeterminate states. * - * React adaptation: selectors that upstream nests under the combined - * `.gl-form-checkbox, .gl-form-radio` block are written out per marker class. - * Cross-type combinations that cannot occur in this React markup (e.g. a - * `[type="checkbox"]` input inside `.gl-form-radio`) are omitted. + * React adaptation: the shared rules preserve upstream's combined + * `.gl-form-checkbox, .gl-form-radio` parent. Cross-type combinations that + * cannot occur in this React markup (e.g. a `[type="checkbox"]` input inside + * `.gl-form-radio`) are omitted. */ .gl-form-checkbox, @@ -30,61 +30,45 @@ @apply gl-cursor-not-allowed gl-text-disabled; } -.gl-form-checkbox.custom-control, -.gl-form-radio.custom-control { - @apply gl-pl-5; -} - -.gl-form-checkbox.custom-control .custom-control-input ~ .custom-control-label, -.gl-form-radio.custom-control .custom-control-input ~ .custom-control-label { - @apply gl-cursor-pointer gl-pl-3 gl-mb-3; -} - -.gl-form-checkbox.custom-control .custom-control-input ~ .custom-control-label::before, -.gl-form-checkbox.custom-control .custom-control-input ~ .custom-control-label::after, -.gl-form-radio.custom-control .custom-control-input ~ .custom-control-label::before, -.gl-form-radio.custom-control .custom-control-input ~ .custom-control-label::after { - top: 0; - /* -$gl-spacing-scale-5 */ - left: -1rem; -} - -.gl-form-checkbox.custom-control .custom-control-input ~ .custom-control-label::before, -.gl-form-radio.custom-control .custom-control-input ~ .custom-control-label::before { - background-color: var(--gl-control-background-color-default); - border-color: var(--gl-control-border-color-default); -} - -.gl-form-checkbox.custom-control - .custom-control-input:not(:disabled):hover - ~ .custom-control-label::before, -.gl-form-radio.custom-control - .custom-control-input:not(:disabled):hover - ~ .custom-control-label::before { - border-color: var(--gl-control-border-color-hover); -} - -.gl-form-checkbox.custom-control - .custom-control-input:not(:disabled):focus-visible - ~ .custom-control-label::before, -.gl-form-radio.custom-control - .custom-control-input:not(:disabled):focus-visible - ~ .custom-control-label::before { - @apply gl-focus; - border-color: var(--gl-control-border-color-focus); -} - -.gl-form-checkbox.custom-control .custom-control-input:checked ~ .custom-control-label::before, -.gl-form-radio.custom-control .custom-control-input:checked ~ .custom-control-label::before { - background-color: var(--gl-control-background-color-selected-default); - border-color: var(--gl-control-border-color-selected-default); -} - -@media (forced-colors: active) { - .gl-form-checkbox.custom-control .custom-control-input:checked ~ .custom-control-label::before, - .gl-form-radio.custom-control .custom-control-input:checked ~ .custom-control-label::before { - background-color: LinkText; - border-color: LinkText; +.gl-form-checkbox, +.gl-form-radio { + &.custom-control { + @apply gl-pl-5; + + .custom-control-input ~ .custom-control-label { + @apply gl-cursor-pointer gl-pl-3 gl-mb-3; + } + + .custom-control-input ~ .custom-control-label::before, + .custom-control-input ~ .custom-control-label::after { + top: 0; + /* -$gl-spacing-scale-5 */ + left: -1rem; + } + + .custom-control-input ~ .custom-control-label::before { + background-color: var(--gl-control-background-color-default); + border-color: var(--gl-control-border-color-default); + } + + .custom-control-input:not(:disabled):hover ~ .custom-control-label::before { + border-color: var(--gl-control-border-color-hover); + } + + .custom-control-input:not(:disabled):focus-visible ~ .custom-control-label::before { + @apply gl-focus; + border-color: var(--gl-control-border-color-focus); + } + + .custom-control-input:checked ~ .custom-control-label::before { + background-color: var(--gl-control-background-color-selected-default); + border-color: var(--gl-control-border-color-selected-default); + + @media (forced-colors: active) { + background-color: LinkText; + border-color: LinkText; + } + } } } @@ -121,14 +105,14 @@ border-color: var(--gl-control-border-color-selected-hover); } -.gl-form-checkbox.custom-control - .custom-control-input:not(:disabled):focus-visible:checked - ~ .custom-control-label::before, -.gl-form-radio.custom-control - .custom-control-input:not(:disabled):focus-visible:checked - ~ .custom-control-label::before { - background-color: var(--gl-control-background-color-selected-focus); - border-color: var(--gl-control-border-color-selected-focus); +.gl-form-checkbox, +.gl-form-radio { + &.custom-control { + .custom-control-input:not(:disabled):focus-visible:checked ~ .custom-control-label::before { + background-color: var(--gl-control-background-color-selected-focus); + border-color: var(--gl-control-border-color-selected-focus); + } + } } @media (forced-colors: active) { @@ -155,31 +139,26 @@ } } -.gl-form-checkbox.custom-control .custom-control-input:not(:disabled) ~ .custom-control-label, -.gl-form-radio.custom-control .custom-control-input:not(:disabled) ~ .custom-control-label { - @apply gl-text-default; -} - -.gl-form-checkbox.custom-control .custom-control-input:disabled ~ .custom-control-label, -.gl-form-radio.custom-control .custom-control-input:disabled ~ .custom-control-label { - @apply gl-cursor-not-allowed; -} - -.gl-form-checkbox.custom-control .custom-control-input:disabled ~ .custom-control-label::before, -.gl-form-radio.custom-control .custom-control-input:disabled ~ .custom-control-label::before { - @apply gl-pointer-events-auto; - background-color: var(--gl-control-background-color-disabled); - border-color: var(--gl-control-border-color-disabled); -} - -@media (forced-colors: active) { - .gl-form-checkbox.custom-control - .custom-control-input:disabled - ~ .custom-control-label::before, - .gl-form-radio.custom-control - .custom-control-input:disabled - ~ .custom-control-label::before { - opacity: 0.5; +.gl-form-checkbox, +.gl-form-radio { + &.custom-control { + .custom-control-input:not(:disabled) ~ .custom-control-label { + @apply gl-text-default; + } + + .custom-control-input:disabled ~ .custom-control-label { + @apply gl-cursor-not-allowed; + } + + .custom-control-input:disabled ~ .custom-control-label::before { + @apply gl-pointer-events-auto; + background-color: var(--gl-control-background-color-disabled); + border-color: var(--gl-control-border-color-disabled); + + @media (forced-colors: active) { + opacity: 0.5; + } + } } } @@ -228,7 +207,9 @@ } } -.gl-form-checkbox .help-text, -.gl-form-radio .help-text { - @apply gl-mt-2 gl-mb-0 gl-text-base gl-leading-normal gl-text-subtle; +.gl-form-checkbox, +.gl-form-radio { + .help-text { + @apply gl-mt-2 gl-mb-0 gl-text-base gl-leading-normal gl-text-subtle; + } } diff --git a/packages/styles/src/forms/gitlab-text-controls.css b/packages/styles/src/forms/gitlab-text-controls.css index 58f6f7c..5edf32e 100644 --- a/packages/styles/src/forms/gitlab-text-controls.css +++ b/packages/styles/src/forms/gitlab-text-controls.css @@ -22,29 +22,24 @@ background: var(--gl-control-background-color-default); /* Bootstrap's `.form-control` base provides these upstream. */ @apply gl-block gl-w-full gl-rounded-control gl-font-regular gl-text-base gl-leading-normal gl-py-3 gl-px-4 gl-h-auto gl-border-none gl-text-default; -} -/* Bootstrap's deprecated `form-control-focus` mixin output; the - * `:not(.form-control-plaintext):focus-visible` rule below overrides it. */ -.gl-form-input:focus-visible, -.gl-form-input.form-control:focus-visible { - color: #4c4b51; - background-color: #fff; - border-color: #80bdff; - outline: 0; - box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); -} + /* Bootstrap's deprecated `form-control-focus` mixin output; the + * `:not(.form-control-plaintext):focus-visible` rule below overrides it. */ + &:focus-visible { + color: #4c4b51; + background-color: #fff; + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + } -@media (forced-colors: active) { - .gl-form-input, - .gl-form-input.form-control { + @media (forced-colors: active) { border: 1px solid; } -} -.gl-form-input:hover, -.gl-form-input.form-control:hover { - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-hover); + &:hover { + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-hover); + } } .gl-form-input:not(.gl-form-input-not-readonly):not(:disabled):not(.form-control-plaintext):not( @@ -57,61 +52,53 @@ box-shadow: none; } -.gl-form-input:disabled, -.gl-form-input.form-control:disabled { - @apply gl-cursor-not-allowed; - background: var(--gl-control-background-color-disabled); - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-disabled); - @apply gl-text-disabled; -} +.gl-form-input, +.gl-form-input.form-control { -/* `gl-focus($color: var(--gl-control-border-color-focus))` */ -.gl-form-input:not(.form-control-plaintext):focus-visible, -.gl-form-input.form-control:not(.form-control-plaintext):focus-visible { - background: var(--gl-control-background-color-default); - @apply gl-text-default; - box-shadow: - inset 0 0 0 1px var(--gl-control-border-color-focus), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color); - outline: none; -} + &:disabled { + @apply gl-cursor-not-allowed; + background: var(--gl-control-background-color-disabled); + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-disabled); + @apply gl-text-disabled; + } + + /* `gl-focus($color: var(--gl-control-border-color-focus))` */ + &:not(.form-control-plaintext):focus-visible { + background: var(--gl-control-background-color-default); + @apply gl-text-default; + box-shadow: + inset 0 0 0 1px var(--gl-control-border-color-focus), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color); + outline: none; -@media (forced-colors: active) { - .gl-form-input:not(.form-control-plaintext):focus-visible, - .gl-form-input.form-control:not(.form-control-plaintext):focus-visible { - outline: 2px solid LinkText; + @media (forced-colors: active) { + outline: 2px solid LinkText; + } } -} -.gl-form-input.is-invalid, -.gl-form-input.form-control.is-invalid { - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-error); -} + &.is-invalid { + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-error); -/* `gl-focus($color: var(--gl-control-border-color-error))` */ -.gl-form-input.is-invalid:focus-visible, -.gl-form-input.form-control.is-invalid:focus-visible { - box-shadow: - inset 0 0 0 1px var(--gl-control-border-color-error), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color); - outline: none; -} + /* `gl-focus($color: var(--gl-control-border-color-error))` */ + &:focus-visible { + box-shadow: + inset 0 0 0 1px var(--gl-control-border-color-error), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color); + outline: none; -@media (forced-colors: active) { - .gl-form-input.is-invalid:focus-visible, - .gl-form-input.form-control.is-invalid:focus-visible { - outline: 2px solid LinkText; + @media (forced-colors: active) { + outline: 2px solid LinkText; + } + } } -} -.gl-form-input::placeholder, -.gl-form-input.form-control::placeholder { - color: var(--gl-control-placeholder-color); -} + &::placeholder { + color: var(--gl-control-placeholder-color); + } -.gl-form-input.form-control-plaintext, -.gl-form-input.form-control.form-control-plaintext { - @apply gl-shadow-none; + &.form-control-plaintext { + @apply gl-shadow-none; + } } diff --git a/packages/styles/src/tables/bootstrap-tables.css b/packages/styles/src/tables/bootstrap-tables.css index 9f35526..a3a4702 100644 --- a/packages/styles/src/tables/bootstrap-tables.css +++ b/packages/styles/src/tables/bootstrap-tables.css @@ -14,10 +14,10 @@ overflow-x: auto; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; -} -.gl-table-responsive > .gl-table { - margin-bottom: 0; + > .gl-table { + margin-bottom: 0; + } } .gl-table-responsive.b-table-sticky-header { @@ -25,29 +25,35 @@ overflow-y: auto; } -table.gl-table.b-table-fixed { - table-layout: fixed; -} +table.gl-table { + &.b-table-fixed { + table-layout: fixed; + } -table.gl-table.b-table-no-border-collapse { - border-collapse: separate; - border-spacing: 0; -} + &.b-table-no-border-collapse { + border-collapse: separate; + border-spacing: 0; + } -table.gl-table > caption { - caption-side: bottom; -} + > caption { + caption-side: bottom; + } -table.gl-table.b-table-caption-top > caption { - caption-side: top !important; + &.b-table-caption-top > caption { + caption-side: top !important; + } } -table.gl-table.table-sm tr > :is(th, td) { - padding: 0.3rem; +table.gl-table.table-sm { + tr > :is(th, td) { + padding: 0.3rem; + } } -table.gl-table.table-striped tbody tr:nth-of-type(odd) { - background-color: var(--gl-background-color-subtle); +table.gl-table.table-striped { + tbody tr:nth-of-type(odd) { + background-color: var(--gl-background-color-subtle); + } } @media print { @@ -59,19 +65,21 @@ table.gl-table.table-striped tbody tr:nth-of-type(odd) { table.gl-table.table-bordered { @apply gl-border gl-border-solid gl-border-default; -} -table.gl-table.table-bordered th, -table.gl-table.table-bordered td { - @apply gl-border gl-border-solid gl-border-default; + th, + td { + @apply gl-border gl-border-solid gl-border-default; + } } -table.gl-table.table-borderless, -table.gl-table.table-borderless th, -table.gl-table.table-borderless td, -table.gl-table.table-borderless thead th, -table.gl-table.table-borderless tbody + tbody { - border: 0; +table.gl-table.table-borderless { + &, + th, + td, + thead th, + tbody + tbody { + border: 0; + } } table.gl-table.b-table-stacked { @@ -95,187 +103,195 @@ table.gl-table.b-table-stacked { --gl-table-stacked-content-align: right; } -@container (width < 576px) { - :where(html.with-gl-container-queries) table.gl-table.b-table-stacked-sm { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; +table.gl-table.b-table-stacked-sm { + @container (width < 576px) { + :where(html.with-gl-container-queries) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } -} -@media (width < 576px) { - :where(html:not(.with-gl-container-queries)) table.gl-table.b-table-stacked-sm { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; + @media (width < 576px) { + :where(html:not(.with-gl-container-queries)) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } } -@container (width < 768px) { - :where(html.with-gl-container-queries) table.gl-table.b-table-stacked-md { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; +table.gl-table.b-table-stacked-md { + @container (width < 768px) { + :where(html.with-gl-container-queries) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } -} -@media (width < 768px) { - :where(html:not(.with-gl-container-queries)) table.gl-table.b-table-stacked-md { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; + @media (width < 768px) { + :where(html:not(.with-gl-container-queries)) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } } -@container (width < 992px) { - :where(html.with-gl-container-queries) table.gl-table.b-table-stacked-lg { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; +table.gl-table.b-table-stacked-lg { + @container (width < 992px) { + :where(html.with-gl-container-queries) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } -} -@media (width < 992px) { - :where(html:not(.with-gl-container-queries)) table.gl-table.b-table-stacked-lg { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; + @media (width < 992px) { + :where(html:not(.with-gl-container-queries)) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } } -@container (width < 1200px) { - :where(html.with-gl-container-queries) table.gl-table.b-table-stacked-xl { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; +table.gl-table.b-table-stacked-xl { + @container (width < 1200px) { + :where(html.with-gl-container-queries) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } -} -@media (width < 1200px) { - :where(html:not(.with-gl-container-queries)) table.gl-table.b-table-stacked-xl { - --gl-table-stacked-table-display: block; - --gl-table-stacked-section-display: block; - --gl-table-stacked-row-display: block; - --gl-table-stacked-cell-display: block; - --gl-table-stacked-head-foot-display: none; - --gl-table-stacked-caption-side: top; - --gl-table-stacked-label-display: block; - --gl-table-stacked-content-display: inline-block; - --gl-table-stacked-content-width: 60%; - --gl-table-stacked-content-padding-left: 0.5rem; - --gl-table-stacked-heavy-border-width: 3px; - --gl-table-stacked-row-gap-display: block; - --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); - --gl-table-stacked-label-align: left; - --gl-table-stacked-labelled-first-border-width: 1px; - --gl-table-stacked-labelled-border-width: 0; - --gl-table-stacked-content-wrap: break-word; - --gl-table-stacked-content-align: right; + @media (width < 1200px) { + :where(html:not(.with-gl-container-queries)) & { + --gl-table-stacked-table-display: block; + --gl-table-stacked-section-display: block; + --gl-table-stacked-row-display: block; + --gl-table-stacked-cell-display: block; + --gl-table-stacked-head-foot-display: none; + --gl-table-stacked-caption-side: top; + --gl-table-stacked-label-display: block; + --gl-table-stacked-content-display: inline-block; + --gl-table-stacked-content-width: 60%; + --gl-table-stacked-content-padding-left: 0.5rem; + --gl-table-stacked-heavy-border-width: 3px; + --gl-table-stacked-row-gap-display: block; + --gl-table-stacked-cell-side-border: 1px solid var(--gl-border-color-default); + --gl-table-stacked-label-align: left; + --gl-table-stacked-labelled-first-border-width: 1px; + --gl-table-stacked-labelled-border-width: 0; + --gl-table-stacked-content-wrap: break-word; + --gl-table-stacked-content-align: right; + } } } @@ -288,143 +304,59 @@ table.gl-table:is( ) { display: var(--gl-table-stacked-table-display, table); width: 100%; -} -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > caption, -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody { - display: var(--gl-table-stacked-section-display, revert); -} + > caption, + > tbody { + display: var(--gl-table-stacked-section-display, revert); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr { - display: var(--gl-table-stacked-row-display, revert); -} + > tbody > tr { + display: var(--gl-table-stacked-row-display, revert); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > td, -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > th { - display: var(--gl-table-stacked-cell-display, revert); -} + > tbody > tr > td, + > tbody > tr > th { + display: var(--gl-table-stacked-cell-display, revert); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > thead, -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tfoot { - display: var(--gl-table-stacked-head-foot-display, revert); -} + > thead, + > tfoot { + display: var(--gl-table-stacked-head-foot-display, revert); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > caption { - caption-side: var(--gl-table-stacked-caption-side, bottom); -} + > caption { + caption-side: var(--gl-table-stacked-caption-side, bottom); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > [data-label]::before { - display: var(--gl-table-stacked-label-display, none); - float: left; - width: 40%; - padding: 0 0.5rem 0 0; - margin: 0; - overflow-wrap: break-word; - font-style: normal; - font-weight: bold; - text-align: right; - content: attr(data-label); -} + > tbody > tr > [data-label]::before { + display: var(--gl-table-stacked-label-display, none); + float: left; + width: 40%; + padding: 0 0.5rem 0 0; + margin: 0; + overflow-wrap: break-word; + font-style: normal; + font-weight: bold; + text-align: right; + content: attr(data-label); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > [data-label]::after { - display: var(--gl-table-stacked-label-display, none); - clear: both; - content: ""; -} + > tbody > tr > [data-label]::after { + display: var(--gl-table-stacked-label-display, none); + clear: both; + content: ""; + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > [data-label] > .gl-table-cell-content { - display: var(--gl-table-stacked-content-display, block); - width: var(--gl-table-stacked-content-width, auto); - padding-left: var(--gl-table-stacked-content-padding-left, 0); - margin: 0; -} + > tbody > tr > [data-label] > .gl-table-cell-content { + display: var(--gl-table-stacked-content-display, block); + width: var(--gl-table-stacked-content-width, auto); + padding-left: var(--gl-table-stacked-content-padding-left, 0); + margin: 0; + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > :first-child, -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > [rowspan] + td, -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) > tbody > tr > [rowspan] + th { - border-top-width: var(--gl-table-stacked-heavy-border-width, 1px); + > tbody > tr > :first-child, + > tbody > tr > [rowspan] + td, + > tbody > tr > [rowspan] + th { + border-top-width: var(--gl-table-stacked-heavy-border-width, 1px); + } } diff --git a/packages/styles/src/typography.css b/packages/styles/src/typography.css index 1dcd448..a0e12ca 100644 --- a/packages/styles/src/typography.css +++ b/packages/styles/src/typography.css @@ -46,17 +46,17 @@ kbd { .table { @apply gl-mb-3 gl-w-full gl-bg-transparent gl-text-default; -} -.table th, -.table td { - @apply gl-border-t gl-p-4 gl-align-top; -} + th, + td { + @apply gl-border-t gl-p-4 gl-align-top; + } -.table thead th { - @apply gl-border-b gl-border-b-2 gl-align-bottom; -} + thead th { + @apply gl-border-b gl-border-b-2 gl-align-bottom; + } -.table tbody + tbody { - @apply gl-border-t gl-border-t-2; + tbody + tbody { + @apply gl-border-t gl-border-t-2; + } } diff --git a/packages/ui/src/base/accordion/accordion.css b/packages/ui/src/base/accordion/accordion.css index d659dcf..900bd59 100644 --- a/packages/ui/src/base/accordion/accordion.css +++ b/packages/ui/src/base/accordion/accordion.css @@ -9,10 +9,10 @@ .gl-accordion-item { @apply gl-mb-5; -} -.gl-accordion-item:last-child { - @apply gl-mb-0; + &:last-child { + @apply gl-mb-0; + } } .gl-accordion-item-header { diff --git a/packages/ui/src/base/alert/alert.css b/packages/ui/src/base/alert/alert.css index 0827530..564f2e8 100644 --- a/packages/ui/src/base/alert/alert.css +++ b/packages/ui/src/base/alert/alert.css @@ -40,10 +40,10 @@ .gl-link:not(.gl-label-link) { @apply gl-underline; } -} -.gl-alert-not-dismissible { - padding-right: calc(1rem + var(--gl-alert-padding-x, 0px)); + &-not-dismissible { + padding-right: calc(1rem + var(--gl-alert-padding-x, 0px)); + } } .gl-alert-sticky { diff --git a/packages/ui/src/base/attribute-list/attribute-list.css b/packages/ui/src/base/attribute-list/attribute-list.css index 682d044..aa51739 100644 --- a/packages/ui/src/base/attribute-list/attribute-list.css +++ b/packages/ui/src/base/attribute-list/attribute-list.css @@ -14,26 +14,24 @@ @apply gl-gap-x-7; } -@container (min-width: 25rem) { - .gl-attribute-list-horizontal-items { +.gl-attribute-list-horizontal-items { + @container (min-width: 25rem) { grid-template-columns: fit-content(15rem) 1fr; - } - .gl-attribute-list-horizontal-items .gl-attribute-list-item { - @apply gl-col-span-2; + .gl-attribute-list-item { + @apply gl-col-span-2; + } } -} -@container (min-width: 54rem) { - .gl-attribute-list-horizontal-items { + @container (min-width: 54rem) { grid-template-columns: repeat(2, fit-content(15rem) 1fr); @apply gl-grid-flow-col; grid-template-rows: repeat(var(--attribute-list-row-count), auto); } } -@container (min-width: 40rem) { - .gl-attribute-list-vertical-items { +.gl-attribute-list-vertical-items { + @container (min-width: 40rem) { @apply gl-grid-cols-2; @apply gl-grid-flow-col; grid-template-rows: repeat(var(--attribute-list-row-count), auto); diff --git a/packages/ui/src/base/avatar-labeled/avatar-labeled.css b/packages/ui/src/base/avatar-labeled/avatar-labeled.css index c946d2b..a12b730 100644 --- a/packages/ui/src/base/avatar-labeled/avatar-labeled.css +++ b/packages/ui/src/base/avatar-labeled/avatar-labeled.css @@ -5,25 +5,27 @@ .gl-avatar-labeled { @apply gl-inline-flex; -} -.gl-avatar-labeled-labels { - @apply gl-ml-3 gl-flex gl-flex-col gl-justify-center gl-text-base gl-leading-normal gl-text-strong !gl-text-left; -} + &-labels { + @apply gl-ml-3 gl-flex gl-flex-col gl-justify-center gl-text-base gl-leading-normal gl-text-strong !gl-text-left; + } -.gl-avatar-labeled-labels.inline-labels { - @apply gl-flex-row gl-items-center gl-gap-2; + &-labels.inline-labels { + @apply gl-flex-row gl-items-center gl-gap-2; + } } .gl-avatar-labeled-label-row { @apply -gl-mx-1 -gl-my-1 gl-flex gl-flex-wrap gl-items-center !gl-text-left; } -.gl-avatar-labeled-label { - @apply gl-p-1 gl-font-bold gl-text-strong; -} +.gl-avatar-labeled { + &-label { + @apply gl-p-1 gl-font-bold gl-text-strong; + } -.gl-avatar-labeled-sublabel { - @apply gl-text-subtle; - overflow-wrap: anywhere; + &-sublabel { + @apply gl-text-subtle; + overflow-wrap: anywhere; + } } diff --git a/packages/ui/src/base/avatar-link/avatar-link.css b/packages/ui/src/base/avatar-link/avatar-link.css index 924067a..444ab7e 100644 --- a/packages/ui/src/base/avatar-link/avatar-link.css +++ b/packages/ui/src/base/avatar-link/avatar-link.css @@ -5,34 +5,34 @@ .gl-avatar-link { @apply gl-inline-flex; -} -.gl-avatar-link .gl-avatar { - @apply gl-transition-border-color gl-duration-slow gl-ease-ease; -} + .gl-avatar { + @apply gl-transition-border-color gl-duration-slow gl-ease-ease; + } -.gl-avatar-link:hover { - @apply gl-no-underline; -} + &:hover { + @apply gl-no-underline; -.gl-avatar-link:hover .gl-avatar { - outline: 1px solid var(--gl-avatar-border-color-hover); -} + .gl-avatar { + outline: 1px solid var(--gl-avatar-border-color-hover); + } -.gl-avatar-link:hover .gl-avatar-labeled-label, -.gl-avatar-link:hover .gl-avatar-labeled-sublabel { - @apply gl-underline; -} + .gl-avatar-labeled { + &-label, + &-sublabel { + @apply gl-underline; + } + } + } -.gl-avatar-link:active, -.gl-avatar-link:focus-visible, -.gl-avatar-link:focus-visible:active { - box-shadow: none !important; - outline: none !important; -} + &:active, + &:focus-visible, + &:focus-visible:active { + box-shadow: none !important; + outline: none !important; -.gl-avatar-link:active .gl-avatar, -.gl-avatar-link:focus-visible .gl-avatar, -.gl-avatar-link:focus-visible:active .gl-avatar { - @apply gl-focus; + .gl-avatar { + @apply gl-focus; + } + } } diff --git a/packages/ui/src/base/badge/badge.css b/packages/ui/src/base/badge/badge.css index 2687bdb..25b6e55 100644 --- a/packages/ui/src/base/badge/badge.css +++ b/packages/ui/src/base/badge/badge.css @@ -16,32 +16,28 @@ background-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), border-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), box-shadow 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); -} -@media (prefers-reduced-motion) { - .gl-badge { + @media (prefers-reduced-motion) { transition-duration: 0.01ms !important; transition-delay: 0ms !important; } -} -.gl-badge:has(.gl-truncate, .gl-text-truncate) { - @apply gl-max-w-full; -} + &:has(.gl-truncate, .gl-text-truncate) { + @apply gl-max-w-full; + } -@media (forced-colors: active) { - .gl-badge { + @media (forced-colors: active) { border: 1px solid; } -} -.gl-badge .gl-badge-icon { - @apply gl-h-5 gl-w-5 gl-shrink-0; - top: auto; -} + .gl-badge-icon { + @apply gl-h-5 gl-w-5 gl-shrink-0; + top: auto; + } -.gl-badge .gl-badge-content { - @apply gl-flex gl-justify-center gl-min-w-3; + .gl-badge-content { + @apply gl-flex gl-justify-center gl-min-w-3; + } } a.gl-badge.disabled { @@ -53,48 +49,49 @@ a.gl-badge.disabled { .gl-badge.badge-neutral { color: var(--gl-badge-neutral-text-color-default); background-color: var(--gl-badge-neutral-background-color-default); -} -.gl-badge.badge-neutral .gl-badge-icon { - color: var(--gl-badge-neutral-icon-color-default); - transition: inherit; + .gl-badge-icon { + color: var(--gl-badge-neutral-icon-color-default); + transition: inherit; + } } -a.gl-badge.badge-neutral:not(.disabled):hover { - @apply gl-no-underline; - color: var(--gl-badge-neutral-text-color-hover); - background-color: var(--gl-badge-neutral-background-color-hover); - box-shadow: inset 0 0 0 1px var(--gl-badge-neutral-border-color-hover); -} +a.gl-badge.badge-neutral:not(.disabled) { + &:hover { + @apply gl-no-underline; + color: var(--gl-badge-neutral-text-color-hover); + background-color: var(--gl-badge-neutral-background-color-hover); + box-shadow: inset 0 0 0 1px var(--gl-badge-neutral-border-color-hover); -a.gl-badge.badge-neutral:not(.disabled):hover .gl-badge-icon { - color: var(--gl-badge-neutral-icon-color-hover); -} + .gl-badge-icon { + color: var(--gl-badge-neutral-icon-color-hover); + } + } -a.gl-badge.badge-neutral:not(.disabled):focus-visible { - color: var(--gl-badge-neutral-text-color-focus); - background-color: var(--gl-badge-neutral-background-color-focus); -} + &:focus-visible { + color: var(--gl-badge-neutral-text-color-focus); + background-color: var(--gl-badge-neutral-background-color-focus); -a.gl-badge.badge-neutral:not(.disabled):focus-visible .gl-badge-icon { - color: var(--gl-badge-neutral-icon-color-focus); -} + .gl-badge-icon { + color: var(--gl-badge-neutral-icon-color-focus); + } + } -a.gl-badge.badge-neutral:not(.disabled).active, -a.gl-badge.badge-neutral:not(.disabled):active { - color: var(--gl-badge-neutral-text-color-active); - background-color: var(--gl-badge-neutral-background-color-active); -} + &.active, + &:active { + color: var(--gl-badge-neutral-text-color-active); + background-color: var(--gl-badge-neutral-background-color-active); -a.gl-badge.badge-neutral:not(.disabled).active .gl-badge-icon, -a.gl-badge.badge-neutral:not(.disabled):active .gl-badge-icon { - color: var(--gl-badge-neutral-icon-color-active); -} + .gl-badge-icon { + color: var(--gl-badge-neutral-icon-color-active); + } + } -a.gl-badge.badge-neutral:not(.disabled):active, -a.gl-badge.badge-neutral:not(.disabled):focus-visible, -a.gl-badge.badge-neutral:not(.disabled):focus-visible:active { - @apply gl-focus; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + } } /* Info */ @@ -102,48 +99,49 @@ a.gl-badge.badge-neutral:not(.disabled):focus-visible:active { .gl-badge.badge-info { color: var(--gl-badge-info-text-color-default); background-color: var(--gl-badge-info-background-color-default); -} -.gl-badge.badge-info .gl-badge-icon { - color: var(--gl-badge-info-icon-color-default); - transition: inherit; + .gl-badge-icon { + color: var(--gl-badge-info-icon-color-default); + transition: inherit; + } } -a.gl-badge.badge-info:not(.disabled):hover { - @apply gl-no-underline; - color: var(--gl-badge-info-text-color-hover); - background-color: var(--gl-badge-info-background-color-hover); - box-shadow: inset 0 0 0 1px var(--gl-badge-info-border-color-hover); -} +a.gl-badge.badge-info:not(.disabled) { + &:hover { + @apply gl-no-underline; + color: var(--gl-badge-info-text-color-hover); + background-color: var(--gl-badge-info-background-color-hover); + box-shadow: inset 0 0 0 1px var(--gl-badge-info-border-color-hover); -a.gl-badge.badge-info:not(.disabled):hover .gl-badge-icon { - color: var(--gl-badge-info-icon-color-hover); -} + .gl-badge-icon { + color: var(--gl-badge-info-icon-color-hover); + } + } -a.gl-badge.badge-info:not(.disabled):focus-visible { - color: var(--gl-badge-info-text-color-focus); - background-color: var(--gl-badge-info-background-color-focus); -} + &:focus-visible { + color: var(--gl-badge-info-text-color-focus); + background-color: var(--gl-badge-info-background-color-focus); -a.gl-badge.badge-info:not(.disabled):focus-visible .gl-badge-icon { - color: var(--gl-badge-info-icon-color-focus); -} + .gl-badge-icon { + color: var(--gl-badge-info-icon-color-focus); + } + } -a.gl-badge.badge-info:not(.disabled).active, -a.gl-badge.badge-info:not(.disabled):active { - color: var(--gl-badge-info-text-color-active); - background-color: var(--gl-badge-info-background-color-active); -} + &.active, + &:active { + color: var(--gl-badge-info-text-color-active); + background-color: var(--gl-badge-info-background-color-active); -a.gl-badge.badge-info:not(.disabled).active .gl-badge-icon, -a.gl-badge.badge-info:not(.disabled):active .gl-badge-icon { - color: var(--gl-badge-info-icon-color-active); -} + .gl-badge-icon { + color: var(--gl-badge-info-icon-color-active); + } + } -a.gl-badge.badge-info:not(.disabled):active, -a.gl-badge.badge-info:not(.disabled):focus-visible, -a.gl-badge.badge-info:not(.disabled):focus-visible:active { - @apply gl-focus; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + } } /* Success */ @@ -151,48 +149,49 @@ a.gl-badge.badge-info:not(.disabled):focus-visible:active { .gl-badge.badge-success { color: var(--gl-badge-success-text-color-default); background-color: var(--gl-badge-success-background-color-default); -} -.gl-badge.badge-success .gl-badge-icon { - color: var(--gl-badge-success-icon-color-default); - transition: inherit; + .gl-badge-icon { + color: var(--gl-badge-success-icon-color-default); + transition: inherit; + } } -a.gl-badge.badge-success:not(.disabled):hover { - @apply gl-no-underline; - color: var(--gl-badge-success-text-color-hover); - background-color: var(--gl-badge-success-background-color-hover); - box-shadow: inset 0 0 0 1px var(--gl-badge-success-border-color-hover); -} +a.gl-badge.badge-success:not(.disabled) { + &:hover { + @apply gl-no-underline; + color: var(--gl-badge-success-text-color-hover); + background-color: var(--gl-badge-success-background-color-hover); + box-shadow: inset 0 0 0 1px var(--gl-badge-success-border-color-hover); -a.gl-badge.badge-success:not(.disabled):hover .gl-badge-icon { - color: var(--gl-badge-success-icon-color-hover); -} + .gl-badge-icon { + color: var(--gl-badge-success-icon-color-hover); + } + } -a.gl-badge.badge-success:not(.disabled):focus-visible { - color: var(--gl-badge-success-text-color-focus); - background-color: var(--gl-badge-success-background-color-focus); -} + &:focus-visible { + color: var(--gl-badge-success-text-color-focus); + background-color: var(--gl-badge-success-background-color-focus); -a.gl-badge.badge-success:not(.disabled):focus-visible .gl-badge-icon { - color: var(--gl-badge-success-icon-color-focus); -} + .gl-badge-icon { + color: var(--gl-badge-success-icon-color-focus); + } + } -a.gl-badge.badge-success:not(.disabled).active, -a.gl-badge.badge-success:not(.disabled):active { - color: var(--gl-badge-success-text-color-active); - background-color: var(--gl-badge-success-background-color-active); -} + &.active, + &:active { + color: var(--gl-badge-success-text-color-active); + background-color: var(--gl-badge-success-background-color-active); -a.gl-badge.badge-success:not(.disabled).active .gl-badge-icon, -a.gl-badge.badge-success:not(.disabled):active .gl-badge-icon { - color: var(--gl-badge-success-icon-color-active); -} + .gl-badge-icon { + color: var(--gl-badge-success-icon-color-active); + } + } -a.gl-badge.badge-success:not(.disabled):active, -a.gl-badge.badge-success:not(.disabled):focus-visible, -a.gl-badge.badge-success:not(.disabled):focus-visible:active { - @apply gl-focus; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + } } /* Warning */ @@ -200,48 +199,49 @@ a.gl-badge.badge-success:not(.disabled):focus-visible:active { .gl-badge.badge-warning { color: var(--gl-badge-warning-text-color-default); background-color: var(--gl-badge-warning-background-color-default); -} -.gl-badge.badge-warning .gl-badge-icon { - color: var(--gl-badge-warning-icon-color-default); - transition: inherit; + .gl-badge-icon { + color: var(--gl-badge-warning-icon-color-default); + transition: inherit; + } } -a.gl-badge.badge-warning:not(.disabled):hover { - @apply gl-no-underline; - color: var(--gl-badge-warning-text-color-hover); - background-color: var(--gl-badge-warning-background-color-hover); - box-shadow: inset 0 0 0 1px var(--gl-badge-warning-border-color-hover); -} +a.gl-badge.badge-warning:not(.disabled) { + &:hover { + @apply gl-no-underline; + color: var(--gl-badge-warning-text-color-hover); + background-color: var(--gl-badge-warning-background-color-hover); + box-shadow: inset 0 0 0 1px var(--gl-badge-warning-border-color-hover); -a.gl-badge.badge-warning:not(.disabled):hover .gl-badge-icon { - color: var(--gl-badge-warning-icon-color-hover); -} + .gl-badge-icon { + color: var(--gl-badge-warning-icon-color-hover); + } + } -a.gl-badge.badge-warning:not(.disabled):focus-visible { - color: var(--gl-badge-warning-text-color-focus); - background-color: var(--gl-badge-warning-background-color-focus); -} + &:focus-visible { + color: var(--gl-badge-warning-text-color-focus); + background-color: var(--gl-badge-warning-background-color-focus); -a.gl-badge.badge-warning:not(.disabled):focus-visible .gl-badge-icon { - color: var(--gl-badge-warning-icon-color-focus); -} + .gl-badge-icon { + color: var(--gl-badge-warning-icon-color-focus); + } + } -a.gl-badge.badge-warning:not(.disabled).active, -a.gl-badge.badge-warning:not(.disabled):active { - color: var(--gl-badge-warning-text-color-active); - background-color: var(--gl-badge-warning-background-color-active); -} + &.active, + &:active { + color: var(--gl-badge-warning-text-color-active); + background-color: var(--gl-badge-warning-background-color-active); -a.gl-badge.badge-warning:not(.disabled).active .gl-badge-icon, -a.gl-badge.badge-warning:not(.disabled):active .gl-badge-icon { - color: var(--gl-badge-warning-icon-color-active); -} + .gl-badge-icon { + color: var(--gl-badge-warning-icon-color-active); + } + } -a.gl-badge.badge-warning:not(.disabled):active, -a.gl-badge.badge-warning:not(.disabled):focus-visible, -a.gl-badge.badge-warning:not(.disabled):focus-visible:active { - @apply gl-focus; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + } } /* Danger */ @@ -249,48 +249,49 @@ a.gl-badge.badge-warning:not(.disabled):focus-visible:active { .gl-badge.badge-danger { color: var(--gl-badge-danger-text-color-default); background-color: var(--gl-badge-danger-background-color-default); -} -.gl-badge.badge-danger .gl-badge-icon { - color: var(--gl-badge-danger-icon-color-default); - transition: inherit; + .gl-badge-icon { + color: var(--gl-badge-danger-icon-color-default); + transition: inherit; + } } -a.gl-badge.badge-danger:not(.disabled):hover { - @apply gl-no-underline; - color: var(--gl-badge-danger-text-color-hover); - background-color: var(--gl-badge-danger-background-color-hover); - box-shadow: inset 0 0 0 1px var(--gl-badge-danger-border-color-hover); -} +a.gl-badge.badge-danger:not(.disabled) { + &:hover { + @apply gl-no-underline; + color: var(--gl-badge-danger-text-color-hover); + background-color: var(--gl-badge-danger-background-color-hover); + box-shadow: inset 0 0 0 1px var(--gl-badge-danger-border-color-hover); -a.gl-badge.badge-danger:not(.disabled):hover .gl-badge-icon { - color: var(--gl-badge-danger-icon-color-hover); -} + .gl-badge-icon { + color: var(--gl-badge-danger-icon-color-hover); + } + } -a.gl-badge.badge-danger:not(.disabled):focus-visible { - color: var(--gl-badge-danger-text-color-focus); - background-color: var(--gl-badge-danger-background-color-focus); -} + &:focus-visible { + color: var(--gl-badge-danger-text-color-focus); + background-color: var(--gl-badge-danger-background-color-focus); -a.gl-badge.badge-danger:not(.disabled):focus-visible .gl-badge-icon { - color: var(--gl-badge-danger-icon-color-focus); -} + .gl-badge-icon { + color: var(--gl-badge-danger-icon-color-focus); + } + } -a.gl-badge.badge-danger:not(.disabled).active, -a.gl-badge.badge-danger:not(.disabled):active { - color: var(--gl-badge-danger-text-color-active); - background-color: var(--gl-badge-danger-background-color-active); -} + &.active, + &:active { + color: var(--gl-badge-danger-text-color-active); + background-color: var(--gl-badge-danger-background-color-active); -a.gl-badge.badge-danger:not(.disabled).active .gl-badge-icon, -a.gl-badge.badge-danger:not(.disabled):active .gl-badge-icon { - color: var(--gl-badge-danger-icon-color-active); -} + .gl-badge-icon { + color: var(--gl-badge-danger-icon-color-active); + } + } -a.gl-badge.badge-danger:not(.disabled):active, -a.gl-badge.badge-danger:not(.disabled):focus-visible, -a.gl-badge.badge-danger:not(.disabled):focus-visible:active { - @apply gl-focus; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + } } /* Tier */ @@ -298,48 +299,49 @@ a.gl-badge.badge-danger:not(.disabled):focus-visible:active { .gl-badge.badge-tier { color: var(--gl-badge-tier-text-color-default); background-color: var(--gl-badge-tier-background-color-default); -} -.gl-badge.badge-tier .gl-badge-icon { - color: var(--gl-badge-tier-icon-color-default); - transition: inherit; + .gl-badge-icon { + color: var(--gl-badge-tier-icon-color-default); + transition: inherit; + } } -a.gl-badge.badge-tier:not(.disabled):hover { - @apply gl-no-underline; - color: var(--gl-badge-tier-text-color-hover); - background-color: var(--gl-badge-tier-background-color-hover); - box-shadow: inset 0 0 0 1px var(--gl-badge-tier-border-color-hover); -} +a.gl-badge.badge-tier:not(.disabled) { + &:hover { + @apply gl-no-underline; + color: var(--gl-badge-tier-text-color-hover); + background-color: var(--gl-badge-tier-background-color-hover); + box-shadow: inset 0 0 0 1px var(--gl-badge-tier-border-color-hover); -a.gl-badge.badge-tier:not(.disabled):hover .gl-badge-icon { - color: var(--gl-badge-tier-icon-color-hover); -} + .gl-badge-icon { + color: var(--gl-badge-tier-icon-color-hover); + } + } -a.gl-badge.badge-tier:not(.disabled):focus-visible { - color: var(--gl-badge-tier-text-color-focus); - background-color: var(--gl-badge-tier-background-color-focus); -} + &:focus-visible { + color: var(--gl-badge-tier-text-color-focus); + background-color: var(--gl-badge-tier-background-color-focus); -a.gl-badge.badge-tier:not(.disabled):focus-visible .gl-badge-icon { - color: var(--gl-badge-tier-icon-color-focus); -} + .gl-badge-icon { + color: var(--gl-badge-tier-icon-color-focus); + } + } -a.gl-badge.badge-tier:not(.disabled).active, -a.gl-badge.badge-tier:not(.disabled):active { - color: var(--gl-badge-tier-text-color-active); - background-color: var(--gl-badge-tier-background-color-active); -} + &.active, + &:active { + color: var(--gl-badge-tier-text-color-active); + background-color: var(--gl-badge-tier-background-color-active); -a.gl-badge.badge-tier:not(.disabled).active .gl-badge-icon, -a.gl-badge.badge-tier:not(.disabled):active .gl-badge-icon { - color: var(--gl-badge-tier-icon-color-active); -} + .gl-badge-icon { + color: var(--gl-badge-tier-icon-color-active); + } + } -a.gl-badge.badge-tier:not(.disabled):active, -a.gl-badge.badge-tier:not(.disabled):focus-visible, -a.gl-badge.badge-tier:not(.disabled):focus-visible:active { - @apply gl-focus; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + } } /* diff --git a/packages/ui/src/base/broadcast-message/broadcast-message.css b/packages/ui/src/base/broadcast-message/broadcast-message.css index 7fa5f7a..58f5109 100644 --- a/packages/ui/src/base/broadcast-message/broadcast-message.css +++ b/packages/ui/src/base/broadcast-message/broadcast-message.css @@ -114,39 +114,39 @@ border-radius: var(--gl-broadcast-banner-border-radius); max-width: 18.75rem; } -} -.gl-broadcast-message-content { - @apply gl-flex; - @apply gl-justify-center; + &-content { + @apply gl-flex; + @apply gl-justify-center; - a { - @apply gl-text-inherit; - @apply gl-underline; - } + a { + @apply gl-text-inherit; + @apply gl-underline; + } - p:last-of-type { - @apply gl-mb-0; + p:last-of-type { + @apply gl-mb-0; + } } -} -.gl-broadcast-message-icon { - @apply gl-mr-5; - line-height: 1rem; + &-icon { + @apply gl-mr-5; + line-height: 1rem; - > svg { - @apply gl-align-bottom; + > svg { + @apply gl-align-bottom; + } } -} -.gl-broadcast-message-text { - margin-top: -0.125rem; - margin-bottom: -0.125rem; - @apply gl-hyphens-auto gl-break-anywhere; -} + &-text { + margin-top: -0.125rem; + margin-bottom: -0.125rem; + @apply gl-hyphens-auto gl-break-anywhere; + } -.gl-broadcast-message-dismiss { - @apply -gl-my-2; - @apply gl-ml-5; - color: inherit !important; + &-dismiss { + @apply -gl-my-2; + @apply gl-ml-5; + color: inherit !important; + } } diff --git a/packages/ui/src/base/button-group/button-group.css b/packages/ui/src/base/button-group/button-group.css index aa75904..ed6de4a 100644 --- a/packages/ui/src/base/button-group/button-group.css +++ b/packages/ui/src/base/button-group/button-group.css @@ -31,170 +31,88 @@ .gl-button-group:not(.gl-keyset-pagination), .btn-group:not(.gl-keyset-pagination), .gl-dropdown.btn-group -) > .gl-button:not(:first-child), -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .btn-group:not(:first-child) > .gl-button, -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-new-dropdown:not(:first-child) > .gl-button { - @apply gl-rounded-l-none gl-border-l-0; -} - -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-button:not(:last-child):not(.dropdown-toggle), -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .btn-group:not(:last-child) > .gl-button, -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-new-dropdown:not(:last-child) > .gl-button { - @apply gl-rounded-r-none gl-border-r-0; -} - -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-button:not(:first-child), -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .btn-group:not(:first-child) > .gl-button, -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-new-dropdown:not(:first-child) > .gl-button { - @apply gl-relative gl-isolate gl-ml-[1px]; -} - -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-button:not(:first-child)::before, -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .btn-group:not(:first-child) > .gl-button::before, -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-new-dropdown:not(:first-child) > .gl-button::before { - content: ""; - @apply gl-absolute gl-bottom-[-1px] gl-left-[-1px] gl-top-[-1px] gl-block gl-w-[1px]; - z-index: 4; -} +) { + > .gl-button:not(:first-child), + > .btn-group:not(:first-child) > .gl-button, + > .gl-new-dropdown:not(:first-child) > .gl-button { + @apply gl-rounded-l-none gl-border-l-0; + } -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) > .gl-button:is(:focus-visible, :active, .active) { - z-index: 3; -} + > .gl-button:not(:last-child):not(.dropdown-toggle), + > .btn-group:not(:last-child) > .gl-button, + > .gl-new-dropdown:not(:last-child) > .gl-button { + @apply gl-rounded-r-none gl-border-r-0; + } + + > .gl-button:not(:first-child), + > .btn-group:not(:first-child) > .gl-button, + > .gl-new-dropdown:not(:first-child) > .gl-button { + @apply gl-relative gl-isolate gl-ml-[1px]; + + &::before { + content: ""; + @apply gl-absolute gl-bottom-[-1px] gl-left-[-1px] gl-top-[-1px] gl-block gl-w-[1px]; + z-index: 4; + } + } + + > .gl-button:is(:focus-visible, :active, .active) { + z-index: 3; + } -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) :is(.btn-confirm, .btn-danger):not(.disabled):not([disabled])::before { - @apply gl-bg-transparent; -} + :is(.btn-confirm, .btn-danger):not(.disabled):not([disabled])::before { + @apply gl-bg-transparent; + } -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) .gl-button.btn-icon .gl-button-text .gl-button-icon { - @apply gl-mr-[-1px]; -} + .gl-button.btn-icon .gl-button-text .gl-button-icon { + @apply gl-mr-[-1px]; + } -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -):is(.disabled, [disabled])::before { - background-color: var(--gl-button-disabled-border-color); -} + &:is(.disabled, [disabled])::before { + background-color: var(--gl-button-disabled-border-color); + } -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) .btn-confirm-secondary:not(.disabled):not([disabled])::before { - background-color: var(--gl-button-confirm-secondary-border-color-default); -} + .btn-confirm-secondary:not(.disabled):not([disabled])::before { + background-color: var(--gl-button-confirm-secondary-border-color-default); + } -:is( - .gl-button-group:not(.gl-keyset-pagination), - .btn-group:not(.gl-keyset-pagination), - .gl-dropdown.btn-group -) .btn-danger-secondary:not(.disabled):not([disabled])::before { - background-color: var(--gl-button-danger-secondary-border-color-default); + .btn-danger-secondary:not(.disabled):not([disabled])::before { + background-color: var(--gl-button-danger-secondary-border-color-default); + } } :is(.gl-button-group-vertical, .btn-group-vertical) { @apply gl-flex-col gl-items-start gl-justify-center; -} -:is(.gl-button-group-vertical, .btn-group-vertical) > :is(.gl-button, .btn-group) { - @apply gl-relative gl-w-full; -} + > :is(.gl-button, .btn-group) { + @apply gl-relative gl-w-full; + } -:is(.gl-button-group-vertical, .btn-group-vertical) > .gl-button:not(:first-child), -:is(.gl-button-group-vertical, .btn-group-vertical) > .btn-group:not(:first-child) > .gl-button, -:is(.gl-button-group-vertical, .btn-group-vertical) - > .gl-new-dropdown:not(:first-child) - > .gl-button { - @apply gl-rounded-t-none gl-border-t-0; -} + > .gl-button:not(:first-child), + > .btn-group:not(:first-child) > .gl-button, + > .gl-new-dropdown:not(:first-child) > .gl-button { + @apply gl-rounded-t-none gl-border-t-0; + } -:is(.gl-button-group-vertical, .btn-group-vertical) > .gl-button:not(:last-child):not(.dropdown-toggle), -:is(.gl-button-group-vertical, .btn-group-vertical) > .btn-group:not(:last-child) > .gl-button, -:is(.gl-button-group-vertical, .btn-group-vertical) - > .gl-new-dropdown:not(:last-child) - > .gl-button { - @apply gl-rounded-b-none gl-border-b-0; -} - -:is(.gl-button-group-vertical, .btn-group-vertical) > .gl-button:not(:first-child), -:is(.gl-button-group-vertical, .btn-group-vertical) > .btn-group:not(:first-child) > .gl-button, -:is(.gl-button-group-vertical, .btn-group-vertical) - > .gl-new-dropdown:not(:first-child) - > .gl-button { - @apply gl-relative gl-mt-[1px]; -} - -:is(.gl-button-group-vertical, .btn-group-vertical) > .gl-button:not(:first-child)::before, -:is(.gl-button-group-vertical, .btn-group-vertical) - > .btn-group:not(:first-child) - > .gl-button::before, -:is(.gl-button-group-vertical, .btn-group-vertical) - > .gl-new-dropdown:not(:first-child) - > .gl-button::before { - content: ""; - @apply gl-absolute gl-left-[-1px] gl-right-[-1px] gl-top-[-1px] gl-block gl-h-[1px]; - z-index: 4; -} + > .btn-group:not(:last-child) > .gl-button, + > .gl-new-dropdown:not(:last-child) > .gl-button { + @apply gl-rounded-b-none gl-border-b-0; + } + + > .gl-button:not(:first-child), + > .btn-group:not(:first-child) > .gl-button, + > .gl-new-dropdown:not(:first-child) > .gl-button { + @apply gl-relative gl-mt-[1px]; + + &::before { + content: ""; + @apply gl-absolute gl-left-[-1px] gl-right-[-1px] gl-top-[-1px] gl-block gl-h-[1px]; + z-index: 4; + } + } -:is(.gl-button-group-vertical, .btn-group-vertical) :is(.btn-confirm, .btn-danger):not(.disabled):not([disabled])::before { - @apply gl-bg-transparent; + @apply gl-bg-transparent; + } } diff --git a/packages/ui/src/base/button/button.css b/packages/ui/src/base/button/button.css index 9a8a1a0..aa7f6e9 100644 --- a/packages/ui/src/base/button/button.css +++ b/packages/ui/src/base/button/button.css @@ -8,10 +8,12 @@ font-family: inherit; } -.gl-button:not(.btn-link):focus-visible, -.gl-button:not(.btn-link):active, -.gl-button:not(.btn-link):focus-visible:active { - @apply gl-no-underline; +.gl-button:not(.btn-link) { + &:focus-visible, + &:active, + &:focus-visible:active { + @apply gl-no-underline; + } } .gl-button.gl-button { @@ -41,34 +43,34 @@ border-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), box-shadow 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), text-decoration-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); -} -.gl-button.gl-button::before { - background-color: var(--gl-button-variant-border); - transition: - background-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), - border-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); -} + &::before { + background-color: var(--gl-button-variant-border); + transition: + background-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), + border-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); + } -.gl-button.gl-button:hover { - color: var(--gl-button-variant-hover-foreground); - background-color: var(--gl-button-variant-hover-background); - border-color: var(--gl-button-variant-hover-border); -} + &:hover { + color: var(--gl-button-variant-hover-foreground); + background-color: var(--gl-button-variant-hover-background); + border-color: var(--gl-button-variant-hover-border); + } -.gl-button.gl-button:focus-visible, -.gl-button.gl-button:focus-visible:active { - @apply gl-focus; - color: var(--gl-button-variant-focus-foreground); - background-color: var(--gl-button-variant-focus-background); - border-color: var(--gl-button-variant-focus-border); -} + &:focus-visible, + &:focus-visible:active { + @apply gl-focus; + color: var(--gl-button-variant-focus-foreground); + background-color: var(--gl-button-variant-focus-background); + border-color: var(--gl-button-variant-focus-border); + } -.gl-button.gl-button:active, -.gl-button.gl-button.active { - color: var(--gl-button-variant-active-foreground); - background-color: var(--gl-button-variant-active-background); - border-color: var(--gl-button-variant-active-border); + &:active, + &.active { + color: var(--gl-button-variant-active-foreground); + background-color: var(--gl-button-variant-active-background); + border-color: var(--gl-button-variant-active-border); + } } .gl-button.btn-default, @@ -291,23 +293,23 @@ text-decoration-color: transparent; text-decoration-style: solid; text-decoration-thickness: auto; -} -.gl-button.gl-button.btn-link:hover { - @apply gl-bg-transparent; - color: var(--gl-button-link-text-color-hover); - text-decoration-color: var(--gl-button-link-text-color-hover); -} + &:hover { + @apply gl-bg-transparent; + color: var(--gl-button-link-text-color-hover); + text-decoration-color: var(--gl-button-link-text-color-hover); + } -.gl-button.gl-button.btn-link:active { - @apply gl-bg-transparent; - color: var(--gl-button-link-text-color-active); - text-decoration-color: var(--gl-button-link-text-color-active); -} + &:active { + @apply gl-bg-transparent; + color: var(--gl-button-link-text-color-active); + text-decoration-color: var(--gl-button-link-text-color-active); + } -.gl-button.gl-button.btn-link:focus-visible, -.gl-button.gl-button.btn-link:focus-visible:active { - @apply gl-bg-transparent; + &:focus-visible, + &:focus-visible:active { + @apply gl-bg-transparent; + } } .gl-button.gl-button.btn-block { diff --git a/packages/ui/src/base/disclosure-dropdown/disclosure-dropdown.css b/packages/ui/src/base/disclosure-dropdown/disclosure-dropdown.css index 76f8e2f..17fc1a8 100644 --- a/packages/ui/src/base/disclosure-dropdown/disclosure-dropdown.css +++ b/packages/ui/src/base/disclosure-dropdown/disclosure-dropdown.css @@ -3,15 +3,15 @@ * packages/gitlab-ui/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.scss */ -.gl-disclosure-dropdown-panel .gl-new-dropdown-inner { - max-height: none; -} +.gl-disclosure-dropdown-panel { + .gl-new-dropdown-inner { + max-height: none; + } -.gl-disclosure-dropdown-panel - .gl-new-dropdown-item[data-disabled] - > .gl-new-dropdown-item-content { - color: var(--gl-dropdown-option-text-color-disabled); - cursor: not-allowed; - text-decoration: none; - background: none; + .gl-new-dropdown-item[data-disabled] > .gl-new-dropdown-item-content { + color: var(--gl-dropdown-option-text-color-disabled); + cursor: not-allowed; + text-decoration: none; + background: none; + } } diff --git a/packages/ui/src/base/form-checkbox/form-checkbox.css b/packages/ui/src/base/form-checkbox/form-checkbox.css index 4a5f3dd..d939d1a 100644 --- a/packages/ui/src/base/form-checkbox/form-checkbox.css +++ b/packages/ui/src/base/form-checkbox/form-checkbox.css @@ -29,56 +29,49 @@ @apply gl-rounded-base; } -.gl-form-checkbox.custom-control - .custom-control-input[type="checkbox"]:checked - ~ .custom-control-label::after { - mask-image: var(--gl-icon-check); -} +.gl-form-checkbox { + &.custom-control { + .custom-control-input[type="checkbox"]:checked ~ .custom-control-label::after { + mask-image: var(--gl-icon-check); + } -.gl-form-checkbox.custom-control - .custom-control-input[type="checkbox"]:indeterminate - ~ .custom-control-label::after { - mask-image: var(--gl-icon-indeterminate); -} + .custom-control-input[type="checkbox"]:indeterminate ~ .custom-control-label::after { + mask-image: var(--gl-icon-indeterminate); + } -.gl-form-checkbox.custom-control.custom-checkbox - .custom-control-input:indeterminate - ~ .custom-control-label::before { - background-color: var(--gl-control-background-color-selected-default); - border-color: var(--gl-control-border-color-selected-default); -} + &.custom-checkbox { + .custom-control-input:indeterminate ~ .custom-control-label::before { + background-color: var(--gl-control-background-color-selected-default); + border-color: var(--gl-control-border-color-selected-default); + } -@media (forced-colors: active) { - .gl-form-checkbox.custom-control.custom-checkbox - .custom-control-input:indeterminate - ~ .custom-control-label::before { - background-color: LinkText; - border-color: LinkText; - } -} + @media (forced-colors: active) { + .custom-control-input:indeterminate ~ .custom-control-label::before { + background-color: LinkText; + border-color: LinkText; + } + } -.gl-form-checkbox.custom-control.custom-checkbox - .custom-control-input:not(:disabled):indeterminate - ~ .custom-control-label:hover::before { - background-color: var(--gl-control-background-color-selected-hover); - border-color: var(--gl-control-border-color-selected-hover); -} + .custom-control-input:not(:disabled):indeterminate ~ .custom-control-label:hover::before { + background-color: var(--gl-control-background-color-selected-hover); + border-color: var(--gl-control-border-color-selected-hover); + } -.gl-form-checkbox.custom-control.custom-checkbox - .custom-control-input:not(:disabled):focus-visible:indeterminate - ~ .custom-control-label::before { - background-color: var(--gl-control-background-color-selected-focus); - border-color: var(--gl-control-border-color-selected-focus); -} + .custom-control-input:not(:disabled):focus-visible:indeterminate + ~ .custom-control-label::before { + background-color: var(--gl-control-background-color-selected-focus); + border-color: var(--gl-control-border-color-selected-focus); + } -@media (forced-colors: active) { - .gl-form-checkbox.custom-control.custom-checkbox - .custom-control-input:not(:disabled):indeterminate - ~ .custom-control-label:hover::before, - .gl-form-checkbox.custom-control.custom-checkbox - .custom-control-input:not(:disabled):focus-visible:indeterminate - ~ .custom-control-label::before { - background-color: LinkText; - border-color: LinkText; + @media (forced-colors: active) { + .custom-control-input:not(:disabled):indeterminate + ~ .custom-control-label:hover::before, + .custom-control-input:not(:disabled):focus-visible:indeterminate + ~ .custom-control-label::before { + background-color: LinkText; + border-color: LinkText; + } + } + } } } diff --git a/packages/ui/src/base/form-date/form-date.css b/packages/ui/src/base/form-date/form-date.css index c7dc5f9..c3b845a 100644 --- a/packages/ui/src/base/form-date/form-date.css +++ b/packages/ui/src/base/form-date/form-date.css @@ -8,8 +8,10 @@ * packages/styles/src/forms/). */ -.gl-form-date input::-webkit-datetime-edit { - line-height: 1; - padding: 0; - margin-bottom: -2px; +.gl-form-date { + input::-webkit-datetime-edit { + line-height: 1; + padding: 0; + margin-bottom: -2px; + } } diff --git a/packages/ui/src/base/form-input/form-input.css b/packages/ui/src/base/form-input/form-input.css index 8663975..2ac853b 100644 --- a/packages/ui/src/base/form-input/form-input.css +++ b/packages/ui/src/base/form-input/form-input.css @@ -41,60 +41,57 @@ input[type="color"].gl-form-input.form-control:disabled { } /* `` custom-range validation styling (standalone control only) */ -.gl-form-input.custom-range.is-valid:focus::-webkit-slider-thumb, -.gl-form-input.custom-range.is-invalid:focus::-webkit-slider-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem var(--_range-focus-color); -} - -.gl-form-input.custom-range.is-valid:focus::-moz-range-thumb, -.gl-form-input.custom-range.is-invalid:focus::-moz-range-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem var(--_range-focus-color); -} - -.gl-form-input.custom-range.is-valid::-webkit-slider-thumb, -.gl-form-input.custom-range.is-invalid::-webkit-slider-thumb { - background-color: var(--_range-color); - background-image: none; -} - -.gl-form-input.custom-range.is-valid::-webkit-slider-thumb:active, -.gl-form-input.custom-range.is-invalid::-webkit-slider-thumb:active { - background-color: var(--_range-focus-color); - background-image: none; -} - -.gl-form-input.custom-range.is-valid::-webkit-slider-runnable-track, -.gl-form-input.custom-range.is-invalid::-webkit-slider-runnable-track { - background-color: var(--_range-track-color); -} - -.gl-form-input.custom-range.is-valid::-moz-range-thumb, -.gl-form-input.custom-range.is-invalid::-moz-range-thumb { - background-color: var(--_range-color); - background-image: none; -} - -.gl-form-input.custom-range.is-valid::-moz-range-thumb:active, -.gl-form-input.custom-range.is-invalid::-moz-range-thumb:active { - background-color: var(--_range-focus-color); - background-image: none; -} - -.gl-form-input.custom-range.is-valid::-moz-range-track, -.gl-form-input.custom-range.is-invalid::-moz-range-track { - background: var(--_range-track-color); -} - -.gl-form-input.custom-range.is-valid { - --_range-color: #2f7549; - --_range-focus-color: #88cfa2; - --_range-track-color: rgba(47, 117, 73, 0.35); -} - -.gl-form-input.custom-range.is-invalid { - --_range-color: #c02f12; - --_range-focus-color: #f5a190; - --_range-track-color: rgba(192, 47, 18, 0.35); +.gl-form-input.custom-range { + &.is-valid, + &.is-invalid { + &:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem var(--_range-focus-color); + } + + &:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem var(--_range-focus-color); + } + + &::-webkit-slider-thumb { + background-color: var(--_range-color); + background-image: none; + + &:active { + background-color: var(--_range-focus-color); + background-image: none; + } + } + + &::-webkit-slider-runnable-track { + background-color: var(--_range-track-color); + } + + &::-moz-range-thumb { + background-color: var(--_range-color); + background-image: none; + + &:active { + background-color: var(--_range-focus-color); + background-image: none; + } + } + + &::-moz-range-track { + background: var(--_range-track-color); + } + } + + &.is-valid { + --_range-color: #2f7549; + --_range-focus-color: #88cfa2; + --_range-track-color: rgba(47, 117, 73, 0.35); + } + + &.is-invalid { + --_range-color: #c02f12; + --_range-focus-color: #f5a190; + --_range-track-color: rgba(192, 47, 18, 0.35); + } } /* `$gl-form-input-sizes` at `$grid-size: 8px` */ diff --git a/packages/ui/src/base/form-select/form-select.css b/packages/ui/src/base/form-select/form-select.css index 028da43..5bd7088 100644 --- a/packages/ui/src/base/form-select/form-select.css +++ b/packages/ui/src/base/form-select/form-select.css @@ -30,61 +30,59 @@ @apply gl-text-default; padding-right: calc(var(--gl-spacing-scale-2) + var(--gl-spacing-scale-6)); position: relative; -} -@media (forced-colors: active) { - .gl-form-select { + @media (forced-colors: active) { box-shadow: none; border: 1px solid; } -} - -.gl-form-select:hover { - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-hover); -} - -.gl-form-select:focus-visible, -.gl-form-select:focus-visible:active { - box-shadow: - inset 0 0 0 1px var(--gl-control-border-color-focus), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} -@media (forced-colors: active) { - .gl-form-select:focus-visible, - .gl-form-select:focus-visible:active { - outline: 2px solid LinkText !important; + &:hover { + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-hover); } -} - -.gl-form-select:disabled { - @apply gl-cursor-not-allowed; - @apply gl-text-disabled; - background-color: var(--gl-control-background-color-disabled); - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-disabled); -} -.gl-form-select.is-invalid:not(:disabled) { - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-error); -} + &:focus-visible, + &:focus-visible:active { + box-shadow: + inset 0 0 0 1px var(--gl-control-border-color-focus), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } -.gl-form-select.is-invalid:not(:disabled):hover { - box-shadow: inset 0 0 0 1px var(--gl-control-border-color-error); -} + @media (forced-colors: active) { + &:focus-visible, + &:focus-visible:active { + outline: 2px solid LinkText !important; + } + } -.gl-form-select.is-invalid:not(:disabled):focus-visible { - box-shadow: - inset 0 0 0 1px var(--gl-control-border-color-error), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} + &:disabled { + @apply gl-cursor-not-allowed; + @apply gl-text-disabled; + background-color: var(--gl-control-background-color-disabled); + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-disabled); + } -@media (forced-colors: active) { - .gl-form-select.is-invalid:not(:disabled):focus-visible { - outline: 2px solid LinkText !important; + &.is-invalid:not(:disabled) { + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-error); + + &:hover { + box-shadow: inset 0 0 0 1px var(--gl-control-border-color-error); + } + + &:focus-visible { + box-shadow: + inset 0 0 0 1px var(--gl-control-border-color-error), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } + + @media (forced-colors: active) { + &:focus-visible { + outline: 2px solid LinkText !important; + } + } } } @@ -94,39 +92,39 @@ position: relative; display: inline-block; width: 100%; -} -.gl-form-select-wrapper::after { - content: ""; - background-color: var(--gl-icon-color-default); - -webkit-mask-image: var(--gl-icon-select-chevron-down); - mask-image: var(--gl-icon-select-chevron-down); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-position: center center; - mask-position: center center; - pointer-events: none; - position: absolute; - top: 50%; - right: var(--gl-spacing-scale-4); - transform: translateY(-50%); - height: 5px; - width: 8px; -} + &::after { + content: ""; + background-color: var(--gl-icon-color-default); + -webkit-mask-image: var(--gl-icon-select-chevron-down); + mask-image: var(--gl-icon-select-chevron-down); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center center; + mask-position: center center; + pointer-events: none; + position: absolute; + top: 50%; + right: var(--gl-spacing-scale-4); + transform: translateY(-50%); + height: 5px; + width: 8px; + } -@media (forced-colors: active) { - .gl-form-select-wrapper::after { - background-color: CanvasText; + @media (forced-colors: active) { + &::after { + background-color: CanvasText; + } } -} -.gl-form-select-wrapper:has(> .gl-form-select:disabled)::after { - background-color: var(--gl-icon-color-disabled); -} + &:has(> .gl-form-select:disabled)::after { + background-color: var(--gl-icon-color-disabled); + } -@media (forced-colors: active) { - .gl-form-select-wrapper:has(> .gl-form-select:disabled)::after { - background-color: GrayText; + @media (forced-colors: active) { + &:has(> .gl-form-select:disabled)::after { + background-color: GrayText; + } } } diff --git a/packages/ui/src/base/icon/icon.css b/packages/ui/src/base/icon/icon.css index d8551a7..d7bbae8 100644 --- a/packages/ui/src/base/icon/icon.css +++ b/packages/ui/src/base/icon/icon.css @@ -3,34 +3,36 @@ * packages/gitlab-ui/src/components/base/icon/icon.scss */ -.gl-icon.s8 { - @apply gl-w-[8px] gl-h-[8px]; -} - -.gl-icon.s12 { - @apply gl-w-[12px] gl-h-[12px]; -} - -.gl-icon.s14 { - @apply gl-w-[14px] gl-h-[14px]; -} - -.gl-icon.s16 { - @apply gl-w-[16px] gl-h-[16px]; -} - -.gl-icon.s24 { - @apply gl-w-[24px] gl-h-[24px]; -} - -.gl-icon.s32 { - @apply gl-w-[32px] gl-h-[32px]; -} - -.gl-icon.s48 { - @apply gl-w-[48px] gl-h-[48px]; -} - -.gl-icon.s72 { - @apply gl-w-[72px] gl-h-[72px]; +.gl-icon { + &.s8 { + @apply gl-w-[8px] gl-h-[8px]; + } + + &.s12 { + @apply gl-w-[12px] gl-h-[12px]; + } + + &.s14 { + @apply gl-w-[14px] gl-h-[14px]; + } + + &.s16 { + @apply gl-w-[16px] gl-h-[16px]; + } + + &.s24 { + @apply gl-w-[24px] gl-h-[24px]; + } + + &.s32 { + @apply gl-w-[32px] gl-h-[32px]; + } + + &.s48 { + @apply gl-w-[48px] gl-h-[48px]; + } + + &.s72 { + @apply gl-w-[72px] gl-h-[72px]; + } } diff --git a/packages/ui/src/base/label/label.css b/packages/ui/src/base/label/label.css index 119bd35..4ae1492 100644 --- a/packages/ui/src/base/label/label.css +++ b/packages/ui/src/base/label/label.css @@ -6,134 +6,132 @@ .gl-label { @apply gl-relative gl-inline-flex gl-items-center gl-max-w-full gl-overflow-hidden gl-rounded-pill gl-text-inherit gl-bg-default gl-text-sm gl-leading-normal; box-shadow: var(--label-inset-border) !important; -} -@media (forced-colors: active) { - .gl-label { + @media (forced-colors: active) { border: 1px solid; } -} -.gl-label:not(.gl-label-scoped) { - background-color: var(--label-background-color); -} - -.gl-label:has(> :first-child:focus-visible) { - box-shadow: - inset 0 0 0 1px var(--label-background-color, var(--gl-background-color-default)), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -@media (forced-colors: active) { - .gl-label:has(> :first-child:focus-visible) { - outline: 2px solid LinkText !important; + &:not(.gl-label-scoped) { + background-color: var(--label-background-color); } -} - -.gl-label .gl-label-link { - @apply gl-flex gl-max-w-full gl-overflow-hidden gl-text-inherit gl-font-normal; -} -.gl-label .gl-label-link:hover, -.gl-label .gl-label-link:focus-visible, -.gl-label .gl-label-link:focus-visible:active { - @apply gl-text-inherit gl-shadow-none gl-outline-none; -} + &:has(> :first-child:focus-visible) { + box-shadow: + inset 0 0 0 1px var(--label-background-color, var(--gl-background-color-default)), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } -.gl-label .gl-label-link-underline { - @apply gl-no-underline; -} + @media (forced-colors: active) { + &:has(> :first-child:focus-visible) { + outline: 2px solid LinkText !important; + } + } -.gl-label .gl-label-link-underline:hover .gl-label-text, -.gl-label .gl-label-link-underline:hover .gl-label-text-scoped, -.gl-label .gl-label-link-underline:focus-visible .gl-label-text, -.gl-label .gl-label-link-underline:focus-visible .gl-label-text-scoped, -.gl-label .gl-label-link-underline:focus-visible:active .gl-label-text, -.gl-label .gl-label-link-underline:focus-visible:active .gl-label-text-scoped { - @apply gl-underline; -} + .gl-label-link { + @apply gl-flex gl-max-w-full gl-overflow-hidden gl-text-inherit gl-font-normal; -.gl-label .gl-label-text, -.gl-label .gl-label-text-scoped { - @apply gl-inline-block gl-min-w-0 gl-max-w-full gl-overflow-x-clip gl-overflow-y-visible gl-text-ellipsis gl-align-top gl-whitespace-nowrap; - padding: var(--gl-spacing-scale-1) 0.375rem; -} + &:hover, + &:focus-visible, + &:focus-visible:active { + @apply gl-text-inherit gl-shadow-none gl-outline-none; + } + } -.gl-label > .gl-label-close.gl-button { - @apply gl-flex gl-border-0 gl-p-0 gl-rounded-full gl-shadow-none; - width: 0.875rem; - min-width: auto !important; - height: 0.875rem; - min-height: auto !important; - margin-right: 0.1875rem; - margin-left: -0.1875rem; -} + .gl-label-link-underline { + @apply gl-no-underline; + + &:hover .gl-label-text, + &:hover .gl-label-text-scoped, + &:focus-visible .gl-label-text, + &:focus-visible .gl-label-text-scoped, + &:focus-visible:active .gl-label-text, + &:focus-visible:active .gl-label-text-scoped { + @apply gl-underline; + } + } -.gl-label > .gl-label-close.gl-button:focus-visible, -.gl-label > .gl-label-close.gl-button:active { - @apply gl-focus; -} + .gl-label-text, + .gl-label-text-scoped { + @apply gl-inline-block gl-min-w-0 gl-max-w-full gl-overflow-x-clip gl-overflow-y-visible gl-text-ellipsis gl-align-top gl-whitespace-nowrap; + padding: var(--gl-spacing-scale-1) 0.375rem; + } -.gl-label > .gl-label-close.gl-button .gl-icon { - vertical-align: -1px; + > .gl-label-close.gl-button { + @apply gl-flex gl-border-0 gl-p-0 gl-rounded-full gl-shadow-none; + width: 0.875rem; + min-width: auto !important; + height: 0.875rem; + min-height: auto !important; + margin-right: 0.1875rem; + margin-left: -0.1875rem; + + &:focus-visible, + &:active { + @apply gl-focus; + } + + .gl-icon { + vertical-align: -1px; + } + } } .gl-label-text-dark { color: var(--gl-label-light-text-color); -} -.gl-label-text-dark .gl-label-close.gl-button { - color: var(--gl-label-light-button-icon-color-default); - background-color: var(--gl-label-light-button-background-color-default); -} + .gl-label-close.gl-button { + color: var(--gl-label-light-button-icon-color-default); + background-color: var(--gl-label-light-button-background-color-default); -.gl-label-text-dark .gl-label-close.gl-button:hover, -.gl-label-text-dark .gl-label-close.gl-button:focus-visible { - color: var(--label-background-color); - background-color: var(--gl-label-light-button-background-color-hover); + &:hover, + &:focus-visible { + color: var(--label-background-color); + background-color: var(--gl-label-light-button-background-color-hover); + } + } } .gl-label-text-light { color: var(--gl-label-dark-text-color); -} -.gl-label-text-light .gl-label-close.gl-button { - color: var(--gl-label-dark-button-icon-color-default); - background-color: var(--gl-label-dark-button-background-color-default); -} + .gl-label-close.gl-button { + color: var(--gl-label-dark-button-icon-color-default); + background-color: var(--gl-label-dark-button-background-color-default); -.gl-label-text-light .gl-label-close.gl-button:hover, -.gl-label-text-light .gl-label-close.gl-button:focus-visible { - color: var(--label-background-color); - background-color: var(--gl-label-dark-button-background-color-hover); + &:hover, + &:focus-visible { + color: var(--label-background-color); + background-color: var(--gl-label-dark-button-background-color-hover); + } + } } -.gl-label-scoped .gl-label-close.gl-button { - margin-left: -0.375rem; - color: var(--gl-label-scoped-button-icon-color-default); -} +.gl-label-scoped { + .gl-label-close.gl-button { + margin-left: -0.375rem; + color: var(--gl-label-scoped-button-icon-color-default); -.gl-label-scoped .gl-label-close.gl-button:hover, -.gl-label-scoped .gl-label-close.gl-button:focus-visible { - color: var(--gl-label-scoped-button-icon-color-hover); - background-color: var(--gl-label-scoped-button-background-color-hover); -} + &:hover, + &:focus-visible { + color: var(--gl-label-scoped-button-icon-color-hover); + background-color: var(--gl-label-scoped-button-background-color-hover); + } + } -.gl-label-scoped .gl-label-text { - background-color: var(--label-background-color); -} + .gl-label-text { + background-color: var(--label-background-color); -@media (forced-colors: active) { - .gl-label-scoped .gl-label-text { - border-right: 1px solid; + @media (forced-colors: active) { + border-right: 1px solid; + } } -} -.gl-label-scoped .gl-label-text-scoped { - @apply gl-pr-3 gl-pl-2; - color: var(--gl-label-scoped-text-color); + .gl-label-text-scoped { + @apply gl-pr-3 gl-pl-2; + color: var(--gl-label-scoped-text-color); + } } .gl-label-tooltip-title { diff --git a/packages/ui/src/base/link/link.css b/packages/ui/src/base/link/link.css index ea1b183..14d66db 100644 --- a/packages/ui/src/base/link/link.css +++ b/packages/ui/src/base/link/link.css @@ -5,34 +5,36 @@ .gl-link { text-underline-offset: var(--gl-spacing-scale-1); -} -.gl-link:hover { - @apply gl-cursor-pointer; -} + &:hover { + @apply gl-cursor-pointer; + } -.gl-link, -.gl-link:hover, -.gl-link:active, -.gl-link:focus-visible { - @apply gl-text-link; -} + &, + &:hover, + &:active, + &:focus-visible { + @apply gl-text-link; + } -.gl-link:active, -.gl-link:focus-visible, -.gl-link:focus-visible:active { - @apply gl-underline; -} + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-underline; + } -.gl-link:focus-visible, -.gl-link:focus-visible:active { - outline: 2px solid var(--gl-focus-ring-outer-color); - outline-offset: 2px; + &:focus-visible, + &:focus-visible:active { + outline: 2px solid var(--gl-focus-ring-outer-color); + outline-offset: 2px; + } } -.gl-link-inline, -.gl-link-inline:hover { - @apply gl-underline; +.gl-link-inline { + &, + &:hover { + @apply gl-underline; + } } .gl-link-external::after { @@ -42,60 +44,56 @@ .gl-link-meta { @apply gl-no-underline; -} -.gl-link-meta:hover { - @apply gl-underline; -} + &:hover { + @apply gl-underline; + } -.gl-link-meta, -.gl-link-meta:hover, -.gl-link-meta:focus-visible, -.gl-link-meta:focus-visible:hover { - @apply gl-text-inherit; + &, + &:hover, + &:focus-visible, + &:focus-visible:hover { + @apply gl-text-inherit; + } } .gl-link-mention, .gl-link-mention-current { @apply gl-px-1 gl-rounded-default gl-no-underline; -} -.gl-link-mention:hover, -.gl-link-mention-current:hover { - @apply gl-underline; -} + &:hover { + @apply gl-underline; + } -.gl-link-mention:active, -.gl-link-mention:focus-visible, -.gl-link-mention:focus-visible:active, -.gl-link-mention-current:active, -.gl-link-mention-current:focus-visible, -.gl-link-mention-current:focus-visible:active { - @apply gl-no-underline; + &:active, + &:focus-visible, + &:focus-visible:active { + @apply gl-no-underline; + } } .gl-link-mention { background-color: var(--gl-link-mention-background-color-default); -} -.gl-link-mention, -.gl-link-mention:hover, -.gl-link-mention:active, -.gl-link-mention:focus-visible, -.gl-link-mention:focus-visible:active { - color: var(--gl-link-mention-text-color-default); + &, + &:hover, + &:active, + &:focus-visible, + &:focus-visible:active { + color: var(--gl-link-mention-text-color-default); + } } .gl-link-mention-current { background-color: var(--gl-link-mention-background-color-current); -} -.gl-link-mention-current, -.gl-link-mention-current:hover, -.gl-link-mention-current:active, -.gl-link-mention-current:focus-visible, -.gl-link-mention-current:focus-visible:active { - color: var(--gl-link-mention-text-color-current); + &, + &:hover, + &:active, + &:focus-visible, + &:focus-visible:active { + color: var(--gl-link-mention-text-color-current); + } } @media (forced-colors: active) { diff --git a/packages/ui/src/base/loading-icon/loading-icon.css b/packages/ui/src/base/loading-icon/loading-icon.css index 3570414..eaa157a 100644 --- a/packages/ui/src/base/loading-icon/loading-icon.css +++ b/packages/ui/src/base/loading-icon/loading-icon.css @@ -47,32 +47,32 @@ .gl-dots-loader { --gl-dots-loader-size: 0.375rem; -} -.gl-dots-loader::before, -.gl-dots-loader > span, -.gl-dots-loader::after { - @apply gl-inline-block; - width: var(--gl-dots-loader-size); - height: var(--gl-dots-loader-size); - margin-right: calc(var(--gl-dots-loader-size) / 2); - border-radius: 100%; - background-color: var(--gl-icon-color-subtle); - content: ""; - animation: gl-dots-loader-animation 1400ms ease-in-out infinite; - animation-fill-mode: both; -} + &::before, + > span, + &::after { + @apply gl-inline-block; + width: var(--gl-dots-loader-size); + height: var(--gl-dots-loader-size); + margin-right: calc(var(--gl-dots-loader-size) / 2); + border-radius: 100%; + background-color: var(--gl-icon-color-subtle); + content: ""; + animation: gl-dots-loader-animation 1400ms ease-in-out infinite; + animation-fill-mode: both; + } -.gl-dots-loader::before { - animation-delay: -0.3s; -} + &::before { + animation-delay: -0.3s; + } -.gl-dots-loader > span { - animation-delay: -0.15s; -} + > span { + animation-delay: -0.15s; + } -.gl-dots-loader::after { - margin-right: 0 !important; + &::after { + margin-right: 0 !important; + } } .gl-dots-loader-md { diff --git a/packages/ui/src/base/table/table.css b/packages/ui/src/base/table/table.css index 28750fd..0a03b70 100644 --- a/packages/ui/src/base/table/table.css +++ b/packages/ui/src/base/table/table.css @@ -9,109 +9,83 @@ table.gl-table { @apply gl-text-default; background-color: var(--gl-color-alpha-0); -} -table.gl-table tr th, -table.gl-table tr td { - @apply gl-border-b-1 gl-border-b-solid gl-border-default; - @apply gl-bg-transparent gl-p-5; - @apply gl-leading-normal gl-text-base; - @apply gl-align-top; - @apply gl-text-default gl-font-normal; -} + tr { + th, + td { + @apply gl-border-b-1 gl-border-b-solid gl-border-default; + @apply gl-bg-transparent gl-p-5; + @apply gl-leading-normal gl-text-base; + @apply gl-align-top; + @apply gl-text-default gl-font-normal; + } -table.gl-table tr:focus-visible { - @apply gl-focus; - position: relative; - z-index: 1; -} + &:focus-visible { + @apply gl-focus; + position: relative; + z-index: 1; + } + } -table.gl-table thead tr th { - @apply gl-font-bold gl-text-heading; -} + thead tr th { + @apply gl-font-bold gl-text-heading; + } -table.gl-table.gl-table--sticky-header thead tr { - @apply gl-bg-default; - position: sticky; - top: -1px; - z-index: 2; - box-shadow: inset 0 -1px 0 var(--gl-border-color-default); -} + &.gl-table--sticky-header thead tr { + @apply gl-bg-default; + position: sticky; + top: -1px; + z-index: 2; + box-shadow: inset 0 -1px 0 var(--gl-border-color-default); + } -table.gl-table caption { - @apply gl-pt-2; -} + caption { + @apply gl-pt-2; + } -table.gl-table.table-hover tbody tr:hover, -table.gl-table.table-hover td.table-secondary:hover { - background-color: var(--gl-table-row-background-color-hover); -} + &.table-hover tbody tr:hover, + &.table-hover td.table-secondary:hover { + background-color: var(--gl-table-row-background-color-hover); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) tbody > tr::after { - display: var(--gl-table-stacked-row-gap-display, none); - width: 100%; - height: 1.5rem; - content: ""; -} + &:is( + .b-table-stacked, + .b-table-stacked-sm, + .b-table-stacked-md, + .b-table-stacked-lg, + .b-table-stacked-xl + ) tbody > tr { + &::after { + display: var(--gl-table-stacked-row-gap-display, none); + width: 100%; + height: 1.5rem; + content: ""; + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) tbody > tr > :is(td, th)[data-label] { - border-right: var(--gl-table-stacked-cell-side-border, 0 solid transparent); - border-left: var(--gl-table-stacked-cell-side-border, 0 solid transparent); -} + > :is(td, th)[data-label] { + border-right: var(--gl-table-stacked-cell-side-border, 0 solid transparent); + border-left: var(--gl-table-stacked-cell-side-border, 0 solid transparent); -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) tbody > tr > :is(td, th)[data-label]::before { - text-align: var(--gl-table-stacked-label-align, right); -} + &::before { + text-align: var(--gl-table-stacked-label-align, right); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) tbody > tr > :is(td, th)[data-label]:first-child { - border-top-width: var(--gl-table-stacked-labelled-first-border-width, 1px); -} + &:first-child { + border-top-width: var(--gl-table-stacked-labelled-first-border-width, 1px); + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) tbody > tr > :is(td, th)[data-label]:not(:first-child) { - border-top-width: var(--gl-table-stacked-labelled-border-width, 1px); -} + &:not(:first-child) { + border-top-width: var(--gl-table-stacked-labelled-border-width, 1px); + } + } -table.gl-table:is( - .b-table-stacked, - .b-table-stacked-sm, - .b-table-stacked-md, - .b-table-stacked-lg, - .b-table-stacked-xl -) tbody > tr .gl-table-cell-content { - overflow-wrap: var(--gl-table-stacked-content-wrap, normal); - text-align: var(--gl-table-stacked-content-align, inherit); -} + .gl-table-cell-content { + overflow-wrap: var(--gl-table-stacked-content-wrap, normal); + text-align: var(--gl-table-stacked-content-align, inherit); + } + } -table.gl-table.table-borderless tr > :is(th, td) { - border: 0; + &.table-borderless tr > :is(th, td) { + border: 0; + } } diff --git a/packages/ui/src/base/toggle/toggle.css b/packages/ui/src/base/toggle/toggle.css index 97dd8ca..651fa44 100644 --- a/packages/ui/src/base/toggle/toggle.css +++ b/packages/ui/src/base/toggle/toggle.css @@ -21,14 +21,14 @@ .gl-toggle-label-inline { @apply gl-flex-row gl-items-center; -} -.gl-toggle-label-inline .gl-toggle-label { - @apply gl-mr-3 gl-mb-0 gl-whitespace-nowrap; -} + .gl-toggle-label { + @apply gl-mr-3 gl-mb-0 gl-whitespace-nowrap; + } -.gl-toggle-label-inline .gl-help-label { - @apply gl-mt-0 gl-ml-3; + .gl-help-label { + @apply gl-mt-0 gl-ml-3; + } } .gl-toggle-label { @@ -46,276 +46,253 @@ color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), background-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), box-shadow 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); -} -@media (prefers-reduced-motion) { - .gl-toggle { + @media (prefers-reduced-motion) { transition-duration: 0.01ms !important; transition-delay: 0ms !important; } -} -@media (forced-colors: active) { - .gl-toggle { + @media (forced-colors: active) { outline: 1px solid CanvasText !important; outline-offset: -1px; transition: none; } -} -/* Upstream also lists `::before::selection` / `::after::selection`, which are - * invalid selectors that browsers ignore and lightningcss rejects. */ -.gl-toggle::selection { - @apply gl-bg-transparent; -} - -.gl-toggle:hover { - color: var(--gl-toggle-switch-icon-color-unchecked-hover); - background-color: var(--gl-toggle-switch-track-color-unchecked-hover); - box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-hover); -} - -.gl-toggle:focus-visible { - color: var(--gl-toggle-switch-icon-color-unchecked-focus); - background-color: var(--gl-toggle-switch-track-color-unchecked-focus); - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-focus), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -.gl-toggle:active { - color: var(--gl-toggle-switch-icon-color-unchecked-active); - background-color: var(--gl-toggle-switch-track-color-unchecked-active); - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-active), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -@media (forced-colors: active) { - .gl-toggle:focus-visible, - .gl-toggle:active { - outline: 2px solid LinkText !important; + /* Upstream also lists `::before::selection` / `::after::selection`, which are + * invalid selectors that browsers ignore and lightningcss rejects. */ + &::selection { + @apply gl-bg-transparent; } -} - -/* The thumb grows on hover and focus so the interaction reads on the thumb as - * well as on the track. */ -.gl-toggle:hover .toggle-icon::before, -.gl-toggle:focus-visible .toggle-icon::before { - transform: scale(0.875); -} - -.gl-toggle .toggle-loading { - @apply gl-h-5; -} - -.gl-toggle .toggle-icon { - @apply gl-absolute gl-top-1 gl-left-1 gl-w-5 gl-h-5; - transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); -} -@media (prefers-reduced-motion) { - .gl-toggle .toggle-icon { - transition-duration: 0.01ms !important; - transition-delay: 0ms !important; + &:hover { + color: var(--gl-toggle-switch-icon-color-unchecked-hover); + background-color: var(--gl-toggle-switch-track-color-unchecked-hover); + box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-hover); } -} -@media (forced-colors: active) { - .gl-toggle .toggle-icon { - transition: none; + &:focus-visible { + color: var(--gl-toggle-switch-icon-color-unchecked-focus); + background-color: var(--gl-toggle-switch-track-color-unchecked-focus); + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-focus), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; } -} -.gl-toggle .toggle-icon::before { - @apply gl-absolute gl-inset-0 gl-rounded-full; - background-color: var(--gl-toggle-switch-background-color-unchecked-default); - content: ""; - transform: scale(0.75); - transition: - transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), - background-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); -} - -@media (prefers-reduced-motion) { - .gl-toggle .toggle-icon::before { - transition-duration: 0.01ms !important; - transition-delay: 0ms !important; + &:active { + color: var(--gl-toggle-switch-icon-color-unchecked-active); + background-color: var(--gl-toggle-switch-track-color-unchecked-active); + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-active), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; } -} -@media (forced-colors: active) { - .gl-toggle .toggle-icon::before { - background-color: CanvasText; - transition: none; + @media (forced-colors: active) { + &:focus-visible, + &:active { + outline: 2px solid LinkText !important; + } } -} - -.gl-toggle .toggle-icon > svg { - @apply gl-absolute gl-w-4 gl-h-4; - top: 50%; - left: 50%; - /* Check/close icons are only rendered in Windows high contrast - * (forced-colors) mode so the toggle state remains distinguishable - * when background colors are overridden by the user agent. */ - display: none; - transform: translate(-50%, -50%); -} -@media (forced-colors: active) { - .gl-toggle .toggle-icon > svg { - display: block; - color: Canvas; + /* The thumb grows on hover and focus so the interaction reads on the thumb as + * well as on the track. */ + &:hover .toggle-icon::before, + &:focus-visible .toggle-icon::before { + transform: scale(0.875); } -} -.gl-toggle.is-checked { - color: var(--gl-toggle-switch-icon-color-checked-default); - background-color: var(--gl-toggle-switch-track-color-checked-default); - box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-default); -} - -.gl-toggle.is-checked:hover { - color: var(--gl-toggle-switch-icon-color-checked-hover); - background-color: var(--gl-toggle-switch-track-color-checked-hover); - box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-hover); -} - -.gl-toggle.is-checked:focus-visible { - color: var(--gl-toggle-switch-icon-color-checked-focus); - background-color: var(--gl-toggle-switch-track-color-checked-focus); - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-focus), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -.gl-toggle.is-checked:active { - color: var(--gl-toggle-switch-icon-color-checked-active); - background-color: var(--gl-toggle-switch-track-color-checked-active); - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-active), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -@media (forced-colors: active) { - .gl-toggle.is-checked { - background-color: CanvasText !important; + .toggle-loading { + @apply gl-h-5; } - .gl-toggle.is-checked svg { - color: CanvasText; + .toggle-icon { + @apply gl-absolute gl-top-1 gl-left-1 gl-w-5 gl-h-5; + transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); + + @media (prefers-reduced-motion) { + transition-duration: 0.01ms !important; + transition-delay: 0ms !important; + } + + @media (forced-colors: active) { + transition: none; + } + + &::before { + @apply gl-absolute gl-inset-0 gl-rounded-full; + background-color: var(--gl-toggle-switch-background-color-unchecked-default); + content: ""; + transform: scale(0.75); + transition: + transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1), + background-color 0.2s cubic-bezier(0.22, 0.61, 0.36, 1); + + @media (prefers-reduced-motion) { + transition-duration: 0.01ms !important; + transition-delay: 0ms !important; + } + + @media (forced-colors: active) { + background-color: CanvasText; + transition: none; + } + } + + > svg { + @apply gl-absolute gl-w-4 gl-h-4; + top: 50%; + left: 50%; + /* Check/close icons are only rendered in Windows high contrast + * (forced-colors) mode so the toggle state remains distinguishable + * when background colors are overridden by the user agent. */ + display: none; + transform: translate(-50%, -50%); + + @media (forced-colors: active) { + display: block; + color: Canvas; + } + } } -} - -.gl-toggle.is-checked .toggle-icon { - transform: translateX(1rem); -} - -.gl-toggle.is-checked .toggle-icon::before { - background-color: var(--gl-toggle-switch-background-color-checked-default); - transform: scale(1); -} - -/* Both disabled blocks must stay last. `.gl-toggle.is-checked` and - * `.gl-toggle.is-disabled` carry equal specificity, so source order is what - * lets the disabled styles win over the checked ones. */ -.gl-toggle.is-disabled { - @apply gl-cursor-not-allowed; - background-color: var(--gl-toggle-switch-track-color-unchecked-disabled); - box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-disabled); -} - -.gl-toggle.is-disabled .toggle-icon { - color: var(--gl-toggle-switch-icon-color-disabled); -} - -.gl-toggle.is-disabled .toggle-icon::before { - background-color: var(--gl-toggle-switch-background-color-unchecked-disabled); -} -@media (forced-colors: active) { - .gl-toggle.is-disabled .toggle-icon::before { - background-color: GrayText; + &.is-checked { + color: var(--gl-toggle-switch-icon-color-checked-default); + background-color: var(--gl-toggle-switch-track-color-checked-default); + box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-default); + + &:hover { + color: var(--gl-toggle-switch-icon-color-checked-hover); + background-color: var(--gl-toggle-switch-track-color-checked-hover); + box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-hover); + } + + &:focus-visible { + color: var(--gl-toggle-switch-icon-color-checked-focus); + background-color: var(--gl-toggle-switch-track-color-checked-focus); + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-focus), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } + + &:active { + color: var(--gl-toggle-switch-icon-color-checked-active); + background-color: var(--gl-toggle-switch-track-color-checked-active); + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-active), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } + + @media (forced-colors: active) { + background-color: CanvasText !important; + + svg { + color: CanvasText; + } + } + + .toggle-icon { + transform: translateX(1rem); + + &::before { + background-color: var(--gl-toggle-switch-background-color-checked-default); + transform: scale(1); + } + } } -} - -.gl-toggle.is-disabled:hover .toggle-icon::before, -.gl-toggle.is-disabled:focus-visible .toggle-icon::before { - transform: scale(0.75); -} - -.gl-toggle.is-disabled:active, -.gl-toggle.is-disabled:focus-visible, -.gl-toggle.is-disabled:focus-visible:active { - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-disabled), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -.gl-toggle.is-checked.is-disabled { - background-color: var(--gl-toggle-switch-track-color-checked-disabled); - box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-disabled); -} - -.gl-toggle.is-checked.is-disabled .toggle-icon::before { - background-color: var(--gl-toggle-switch-background-color-checked-disabled); - transform: scale(1); -} -.gl-toggle.is-checked.is-disabled:hover .toggle-icon::before, -.gl-toggle.is-checked.is-disabled:focus-visible .toggle-icon::before { - transform: scale(1); -} - -.gl-toggle.is-checked.is-disabled:active, -.gl-toggle.is-checked.is-disabled:focus-visible, -.gl-toggle.is-checked.is-disabled:focus-visible:active { - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-disabled), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; -} - -@media (forced-colors: active) { - .gl-toggle.is-checked.is-disabled { - background-color: GrayText !important; + /* Both disabled blocks must stay last. `.gl-toggle.is-checked` and + * `.gl-toggle.is-disabled` carry equal specificity, so source order is what + * lets the disabled styles win over the checked ones. */ + &.is-disabled { + @apply gl-cursor-not-allowed; + background-color: var(--gl-toggle-switch-track-color-unchecked-disabled); + box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-disabled); + + .toggle-icon { + color: var(--gl-toggle-switch-icon-color-disabled); + + &::before { + background-color: var(--gl-toggle-switch-background-color-unchecked-disabled); + + @media (forced-colors: active) { + background-color: GrayText; + } + } + } + + &:hover .toggle-icon::before, + &:focus-visible .toggle-icon::before { + transform: scale(0.75); + } + + &:active, + &:focus-visible, + &:focus-visible:active { + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-unchecked-disabled), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } } -} -/* A loading toggle renders a spinner in place of the thumb, so the track is - * the only thing left to look at and its value is still in flight. It gets a - * flat fill that ignores the checked state, which also keeps the spinner - * legible in both color modes. - * - * `.is-loading` is always accompanied by `.is-disabled`, so this block has to - * stay after both disabled blocks: the checked pairs tie on specificity and - * source order is what settles them. */ -.gl-toggle.is-loading, -.gl-toggle.is-checked.is-loading { - background-color: var(--gl-toggle-switch-track-color-loading); - box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-loading); -} + &.is-checked.is-disabled { + background-color: var(--gl-toggle-switch-track-color-checked-disabled); + box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-disabled); + + .toggle-icon::before { + background-color: var(--gl-toggle-switch-background-color-checked-disabled); + transform: scale(1); + } + + &:hover .toggle-icon::before, + &:focus-visible .toggle-icon::before { + transform: scale(1); + } + + &:active, + &:focus-visible, + &:focus-visible:active { + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-checked-disabled), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } + + @media (forced-colors: active) { + background-color: GrayText !important; + } + } -.gl-toggle.is-loading:active, -.gl-toggle.is-loading:focus-visible, -.gl-toggle.is-loading:focus-visible:active, -.gl-toggle.is-checked.is-loading:active, -.gl-toggle.is-checked.is-loading:focus-visible, -.gl-toggle.is-checked.is-loading:focus-visible:active { - box-shadow: - inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-loading), - 0 0 0 1px var(--gl-focus-ring-inner-color), - 0 0 0 3px var(--gl-focus-ring-outer-color) !important; - outline: none !important; + /* A loading toggle renders a spinner in place of the thumb, so the track is + * the only thing left to look at and its value is still in flight. It gets a + * flat fill that ignores the checked state, which also keeps the spinner + * legible in both color modes. + * + * `.is-loading` is always accompanied by `.is-disabled`, so this block has to + * stay after both disabled blocks: the checked pairs tie on specificity and + * source order is what settles them. */ + &.is-loading, + &.is-checked.is-loading { + background-color: var(--gl-toggle-switch-track-color-loading); + box-shadow: inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-loading); + + &:active, + &:focus-visible, + &:focus-visible:active { + box-shadow: + inset 0 0 0 1px var(--gl-toggle-switch-track-border-color-loading), + 0 0 0 1px var(--gl-focus-ring-inner-color), + 0 0 0 3px var(--gl-focus-ring-outer-color) !important; + outline: none !important; + } + } } diff --git a/packages/ui/src/base/tooltip/tooltip.css b/packages/ui/src/base/tooltip/tooltip.css index 1975f26..46efe06 100644 --- a/packages/ui/src/base/tooltip/tooltip.css +++ b/packages/ui/src/base/tooltip/tooltip.css @@ -31,26 +31,30 @@ @apply gl-opacity-0; } -.gl-tooltip .tooltip-inner { - @apply gl-drop-shadow-md gl-leading-normal gl-font-normal gl-py-3 gl-px-4 gl-rounded-feedback gl-text-center; - max-width: 200px; - background: var(--gl-feedback-strong-background-color); - color: var(--gl-feedback-strong-text-color); - --gl-text-color-subtle: var(--gl-tooltip-text-color-subtle); -} - -.gl-tooltip .arrow { - @apply gl-block gl-w-2 gl-h-3; -} - -.gl-tooltip .arrow::before { - @apply gl-absolute gl-border-4 gl-border-solid gl-border-transparent; - content: ""; -} - -.gl-tooltip.bs-tooltip-top .arrow, -.gl-tooltip.bs-tooltip-bottom .arrow { - @apply gl-w-3 gl-h-2; +.gl-tooltip { + .tooltip-inner { + @apply gl-drop-shadow-md gl-leading-normal gl-font-normal gl-py-3 gl-px-4 gl-rounded-feedback gl-text-center; + max-width: 200px; + background: var(--gl-feedback-strong-background-color); + color: var(--gl-feedback-strong-text-color); + --gl-text-color-subtle: var(--gl-tooltip-text-color-subtle); + } + + .arrow { + @apply gl-block gl-w-2 gl-h-3; + + &::before { + @apply gl-absolute gl-border-4 gl-border-solid gl-border-transparent; + content: ""; + } + } +} + +.gl-tooltip.bs-tooltip-top, +.gl-tooltip.bs-tooltip-bottom { + .arrow { + @apply gl-w-3 gl-h-2; + } } /* The arrow lives inside the popup's 4px padding (like upstream, where the diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9871fa9..4d49ab4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,6 +90,9 @@ importers: postcss: specifier: ^8.5.26 version: 8.5.26 + postcss-nested: + specifier: ^8.0.1 + version: 8.0.1(postcss@8.5.26) postcss-selector-parser: specifier: 7.1.0 version: 7.1.0 @@ -2827,10 +2830,20 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-nested@8.0.1: + resolution: {integrity: sha512-PvSIwDVh1NTw939iu4FBK+oeZfSm0cbErFAjXCTPiStammzobBNE2SiQNezy8Xp+Oud2uLXaLpTauv3UdxWjbQ==} + engines: {node: ^22.0.0 || ^24.0.0 || >= 26.0.0} + peerDependencies: + postcss: ^8.2.14 + postcss-selector-parser@7.1.0: resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} engines: {node: '>=4'} + postcss-selector-parser@7.1.6: + resolution: {integrity: sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==} + engines: {node: '>=4'} + postcss@8.5.26: resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} engines: {node: ^10 || ^12 || >=14} @@ -5931,11 +5944,21 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-nested@8.0.1(postcss@8.5.26): + dependencies: + postcss: 8.5.26 + postcss-selector-parser: 7.1.6 + postcss-selector-parser@7.1.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-selector-parser@7.1.6: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss@8.5.26: dependencies: nanoid: 3.3.18 From 61a93563f8bdba9936a6feb7688a2d34952e3334 Mon Sep 17 00:00:00 2001 From: NriotHrreion Date: Fri, 4 Sep 2026 16:54:47 +0800 Subject: [PATCH 2/4] fix(styles): preprocess nested css before tailwind --- packages/styles/scripts/fixtures/nesting-forms.css | 1 + packages/styles/scripts/legacy-prefix.test.mjs | 1 + packages/styles/scripts/postcss-gitlab-tailwind.mjs | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/styles/scripts/fixtures/nesting-forms.css b/packages/styles/scripts/fixtures/nesting-forms.css index 19e065f..f61cbba 100644 --- a/packages/styles/scripts/fixtures/nesting-forms.css +++ b/packages/styles/scripts/fixtures/nesting-forms.css @@ -8,6 +8,7 @@ } &-suffix { + @apply gl-relative; color: green; } diff --git a/packages/styles/scripts/legacy-prefix.test.mjs b/packages/styles/scripts/legacy-prefix.test.mjs index e5a4698..b07db5c 100644 --- a/packages/styles/scripts/legacy-prefix.test.mjs +++ b/packages/styles/scripts/legacy-prefix.test.mjs @@ -82,6 +82,7 @@ test("expands the Sass-like nesting forms used by upstream styles", async () => const input = await readFile(inputPath, "utf8"); const result = await postcss(createPostcssPlugins()).process(input, { from: inputPath }); const root = postcss.parse(result.css); + expect(result.css).not.toMatch(/@apply/u); const selectorsForDeclaration = (property, value, container = root) => { const selectors = []; container.walkRules((rule) => { diff --git a/packages/styles/scripts/postcss-gitlab-tailwind.mjs b/packages/styles/scripts/postcss-gitlab-tailwind.mjs index 3925e50..b96ac77 100644 --- a/packages/styles/scripts/postcss-gitlab-tailwind.mjs +++ b/packages/styles/scripts/postcss-gitlab-tailwind.mjs @@ -35,9 +35,10 @@ function compilerSources(compiler, base) { } async function prepareStylesheet(postcss, content, from) { - // Tailwind parses imported stylesheets before downstream PostCSS plugins run. - // Expand source nesting here so Sass-style selectors such as `&-suffix` - // survive that import step; the configured postcss-nested pass still handles + // Tailwind parses stylesheets before downstream PostCSS plugins run, and + // bundlers such as Vite may inline imports into the entry AST first. Expand + // source nesting here so Sass-style selectors such as `&-suffix` survive + // Tailwind's `@apply` pass; the configured postcss-nested pass still handles // any nesting left in Tailwind's completed AST. const rewritten = rewriteLegacyApplyDirectives(content, from); const result = await postcss([postcssNested()]).process(rewritten, { @@ -82,7 +83,7 @@ export default function gitlabTailwind({ candidates = [], sources: additionalSou const from = result.opts.from ? path.resolve(result.opts.from) : undefined; const base = from ? path.dirname(from) : process.cwd(); const dependencies = new Set(); - const input = rewriteLegacyApplyDirectives(root.toString(), from); + const input = await prepareStylesheet(postcss, root.toString(), from); const compiler = await compile(input, { base, From b32e64d00c3e12093417f2263291c3d597723306 Mon Sep 17 00:00:00 2001 From: NriotHrreion Date: Fri, 4 Sep 2026 17:11:48 +0800 Subject: [PATCH 3/4] refactor(styles): delegate keyframe unwrapping to postcss-nested --- packages/styles/dist/gitlab-ui.css | 16 +++++----- .../styles/scripts/legacy-prefix.test.mjs | 15 ++-------- .../scripts/postcss-gitlab-tailwind.mjs | 30 ------------------- 3 files changed, 10 insertions(+), 51 deletions(-) diff --git a/packages/styles/dist/gitlab-ui.css b/packages/styles/dist/gitlab-ui.css index effaa30..418043b 100644 --- a/packages/styles/dist/gitlab-ui.css +++ b/packages/styles/dist/gitlab-ui.css @@ -6928,6 +6928,14 @@ table.gl-table.table-borderless tr > :is(th, td) { animation-iteration-count: 3 } } +@keyframes gl-keyframes-skeleton-loader { + 0% { + background-position-x: -32rem; + } + 100% { + background-position-x: 32rem; + } + } .\!gl-max-w-20 { max-width: var(--gl-spacing-scale-20) !important; } @@ -7324,11 +7332,3 @@ table.gl-table.table-borderless tr > :is(th, td) { } } } -@keyframes gl-keyframes-skeleton-loader { - 0% { - background-position-x: -32rem; - } - 100% { - background-position-x: 32rem; - } -} diff --git a/packages/styles/scripts/legacy-prefix.test.mjs b/packages/styles/scripts/legacy-prefix.test.mjs index b07db5c..5e20aa5 100644 --- a/packages/styles/scripts/legacy-prefix.test.mjs +++ b/packages/styles/scripts/legacy-prefix.test.mjs @@ -41,7 +41,7 @@ test("compiles @apply and restores upstream gl-* selectors", async () => { expect(result.css).not.toMatch(/:where\(\.gl-dark \*\)/u); }, 30000); -test("hoists plugin keyframes and expands nested media rules", async () => { +test("expands nested media rules", async () => { const input = await readFile(inputPath, "utf8"); const result = await postcss( createPostcssPlugins({ candidates: ["animate-skeleton-loader"] }), @@ -50,18 +50,10 @@ test("hoists plugin keyframes and expands nested media rules", async () => { const skeletonRule = root.nodes.find( (node) => node.type === "rule" && node.selector === ".gl-animate-skeleton-loader", ); - const keyframes = root.nodes.find( - (node) => node.type === "atrule" - && node.name === "keyframes" - && node.params === "gl-keyframes-skeleton-loader", - ); - expect(skeletonRule).toBeDefined(); - expect(skeletonRule.nodes.some((node) => node.type === "atrule")).toBe(false); expect(skeletonRule.nodes.some( - (node) => node.type === "atrule" && node.name === "keyframes", + (node) => node.type === "atrule" && node.name === "media", )).toBe(false); - expect(keyframes).toBeDefined(); const reducedMotionRules = root.nodes .filter( (node) => node.type === "atrule" @@ -72,9 +64,6 @@ test("hoists plugin keyframes and expands nested media rules", async () => { expect(reducedMotionRules.some( (node) => node.type === "rule" && node.selector === ".gl-animate-skeleton-loader", )).toBe(true); - expect(result.css).toContain( - "\n@keyframes gl-keyframes-skeleton-loader {\n 0% {", - ); }, 30000); test("expands the Sass-like nesting forms used by upstream styles", async () => { diff --git a/packages/styles/scripts/postcss-gitlab-tailwind.mjs b/packages/styles/scripts/postcss-gitlab-tailwind.mjs index b96ac77..6f31b15 100644 --- a/packages/styles/scripts/postcss-gitlab-tailwind.mjs +++ b/packages/styles/scripts/postcss-gitlab-tailwind.mjs @@ -49,33 +49,6 @@ async function prepareStylesheet(postcss, content, from) { return result.css; } -function removeOneIndentLevel(node) { - for(const property of ["before", "after"]) { - const rawValue = node.raws[property]; - if(typeof rawValue === "string") { - node.raws[property] = rawValue.replace(/(\r?\n) {2}/gu, "$1"); - } - } - - for(const child of node.nodes ?? []) removeOneIndentLevel(child); -} - -function hoistKeyframesFromStyleRules(root) { - const keyframesToHoist = []; - - root.walkAtRules((atRule) => { - if(!atRule.name.endsWith("keyframes") || atRule.parent?.type !== "rule") return; - - atRule.remove(); - atRule.raws.before = "\n"; - atRule.raws.after = "\n"; - for(const child of atRule.nodes ?? []) removeOneIndentLevel(child); - keyframesToHoist.push(atRule); - }); - - root.append(keyframesToHoist); -} - export default function gitlabTailwind({ candidates = [], sources: additionalSources = [] } = {}) { return { postcssPlugin: "gitlab-tailwind-v3-prefix-compatibility", @@ -117,9 +90,6 @@ export default function gitlabTailwind({ candidates = [], sources: additionalSou const compiledRoot = postcss.parse(css, { from }); restoreLegacySelectors(compiledRoot, candidateMap); - // Tailwind 4 preserves plugin-authored nested keyframes, but production - // CSS minifiers expect keyframes at the stylesheet root. - hoistKeyframesFromStyleRules(compiledRoot); root.removeAll(); root.append(compiledRoot.nodes); From 7cb61dd392b4ae2242346e8202dc78ff185101c4 Mon Sep 17 00:00:00 2001 From: NriotHrreion Date: Fri, 4 Sep 2026 17:17:42 +0800 Subject: [PATCH 4/4] docs: update porting skill docs --- .agents/skills/port-gitlab-ui-component/SKILL.md | 2 ++ .../port-gitlab-ui-component/references/react-porting.md | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.agents/skills/port-gitlab-ui-component/SKILL.md b/.agents/skills/port-gitlab-ui-component/SKILL.md index d24824b..35d784b 100644 --- a/.agents/skills/port-gitlab-ui-component/SKILL.md +++ b/.agents/skills/port-gitlab-ui-component/SKILL.md @@ -69,6 +69,8 @@ Keep stylesheet provenance boundaries strict. A component's colocated CSS may co When authoring component CSS, prefer `@apply` with supported upstream `gl-*` utilities wherever it preserves the intended declaration and cascade. When upstream already uses `@apply`, keep its utility choices, variant prefixes, grouping, and source order as closely as the local Tailwind build and React structure allow. Keep native CSS for component-specific tokens, Sass-only constructs, compatibility adaptations, missing utilities, or cases where `@apply` would change specificity or source-order behavior. See [references/react-porting.md](references/react-porting.md) for the detailed boundary. +Match the upstream stylesheet's selector organization as closely as the local React and Base UI structure allows. When upstream uses Sass-style nesting, preserve the equivalent nesting for states, modifiers, descendants, combinators, and conditional at-rules; when upstream leaves a rule flat, keep its local counterpart flat instead of introducing nesting merely because the build supports it. Nest only when the existing `postcss-nested` pipeline expands to the same selector set, specificity, at-rule context, and source order. Do not introduce Sass variables, mixins, loops, or interpolation. + If upstream behavior cannot be supported without a missing local primitive, either add the smallest reusable prerequisite within scope or preserve a clear typed API boundary and document the deliberate deferral. Never silently drop a supported state. ### 4. Verify in increasing cost order diff --git a/.agents/skills/port-gitlab-ui-component/references/react-porting.md b/.agents/skills/port-gitlab-ui-component/references/react-porting.md index eaed836..0193347 100644 --- a/.agents/skills/port-gitlab-ui-component/references/react-porting.md +++ b/.agents/skills/port-gitlab-ui-component/references/react-porting.md @@ -29,10 +29,13 @@ Use this reference after the upstream compatibility checklist is known. It captu - Model closed variants with `cva` and exported literal unions. Keep structural classes separate from consumer `className` merging. - Treat upstream stylesheet boundaries as part of the port. Colocated component CSS may contain only rules whose semantic source is the corresponding upstream component stylesheet, including declarations generated by mixins, utilities, or required build-compatibility transforms invoked there. Rules supplied transitively by Bootstrap, vendor/global styles, or imported stylesheets belong in the matching shared styles layer, scoped to a component marker where needed and imported before component-private CSS. - Translate Sass into colocated CSS and prefer `@apply` with supported `gl-*` utilities whenever they express the same semantics. +- Treat the upstream nesting structure as part of the stylesheet organization. Mirror equivalent Sass-style nesting for pseudo-classes, pseudo-elements, modifiers, suffixes, descendants, combinators, and nested `@media`, `@supports`, or `@container` rules when the local selectors correspond directly. If upstream keeps a rule flat, keep the local counterpart flat; nesting support alone is not a reason to reorganize it. +- Before nesting selector lists or sharing a parent rule, confirm that expansion produces exactly the intended selector set. The compiled result must preserve selector specificity, declarations, at-rule context, relative source order, and cascade. If React or Base UI adaptation breaks the one-to-one structure, prefer the clearest semantically equivalent local organization and record meaningful deviations. +- Use only Sass-style nesting syntax supported by the existing `postcss-nested` pipeline. Keep Sass variables, mixins, loops, and interpolation expanded into supported CSS rather than introducing a new preprocessing capability. - When upstream already uses `@apply`, preserve the same utility candidates, variant prefixes, grouping, and source order wherever practical instead of rewriting them into merely equivalent utilities. Deviate only when required by unsupported local utilities or configuration, React or Base UI structure, or cascade and specificity constraints; record meaningful deviations. - Use the same `@apply` approach for exact utility equivalents introduced by React or Base UI adaptations. - Keep native CSS declarations for component-specific tokens, Sass variables/calculations/mixins after expansion, literal values without a meaningful utility, and cases where `@apply` would change cascade, specificity, or source-order behavior. Keep transitive global-style compensation in the appropriate shared layer rather than a component's colocated stylesheet. Do not invent arbitrary utilities merely to eliminate native declarations. -- Component source may contain `@apply`, but the published styles output must contain only compiled CSS. Verify that the styles package build expands every directive and regenerate `packages/styles/dist` rather than editing it directly. +- Component source may contain `@apply` and supported nesting, but the published styles output must contain only fully expanded CSS. Verify that the styles package build expands every directive and nested rule, and regenerate `packages/styles/dist` rather than editing it directly. - Inspect mixin definitions and transitive global styles before replacing them; do not approximate a hidden behavior by appearance alone. - Cover hover, active, focus-visible, disabled, dark theme, forced colors, reduced motion, and responsive behavior only where upstream or shared foundations support them. - Import component CSS from `packages/styles/src/components.css`. Regenerate `packages/styles/dist` with the styles package build; never hand-edit generated output.