diff --git a/scss/_buttons.scss b/scss/_buttons.scss index 47b21aff2f..40d45c371f 100644 --- a/scss/_buttons.scss +++ b/scss/_buttons.scss @@ -4,7 +4,8 @@ .btn { // scss-docs-start btn-css-vars - --#{$prefix}btn-padding-x: #{$btn-padding-x}; + --#{$prefix}btn-padding-start: #{$btn-padding-x}; + --#{$prefix}btn-padding-end: #{$btn-padding-x}; --#{$prefix}btn-padding-y: #{$btn-padding-y}; --#{$prefix}btn-min-width: #{$ouds-button-size-min-width}; // OUDS mod --#{$prefix}btn-min-height: #{$ouds-button-size-min-height}; // OUDS mod @@ -35,7 +36,11 @@ justify-content: center; // OUDS mod min-width: var(--#{$prefix}btn-min-width); // OUDS mod min-height: var(--#{$prefix}btn-min-height); // OUDS mod - padding: subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-border-width)) subtract(var(--#{$prefix}btn-padding-x), var(--#{$prefix}btn-border-width)); // OUDS mod + padding: + subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-border-width)) + subtract(var(--#{$prefix}btn-padding-end), var(--#{$prefix}btn-border-width)) + subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-border-width)) + subtract(var(--#{$prefix}btn-padding-start), var(--#{$prefix}btn-border-width)); // OUDS mod font-family: var(--#{$prefix}btn-font-family); @include get-font-size("label-large"); // OUDS mod font-weight: var(--#{$prefix}btn-font-weight); @@ -56,7 +61,11 @@ &:hover, &:focus-visible, // OUDS mod: apply hover styles to focus visible as well &:focus[data-focus-visible-added] { // OUDS mod: apply hover styles to focus visible as well - padding: subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-interaction-border-width)) subtract(var(--#{$prefix}btn-padding-x), var(--#{$prefix}btn-interaction-border-width)); // OUDS mod + padding: + subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-interaction-border-width)) + subtract(var(--#{$prefix}btn-padding-end), var(--#{$prefix}btn-interaction-border-width)) + subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-interaction-border-width)) + subtract(var(--#{$prefix}btn-padding-start), var(--#{$prefix}btn-interaction-border-width)); // OUDS mod color: var(--#{$prefix}btn-hover-color); text-decoration: if($link-hover-decoration == underline, none, null); background-color: var(--#{$prefix}btn-hover-bg); @@ -76,7 +85,11 @@ &:active, &.active, &.show { - padding: subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-interaction-border-width)) subtract(var(--#{$prefix}btn-padding-x), var(--#{$prefix}btn-interaction-border-width)); // OUDS mod + padding: + subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-interaction-border-width)) + subtract(var(--#{$prefix}btn-padding-end), var(--#{$prefix}btn-interaction-border-width)) + subtract(var(--#{$prefix}btn-padding-y), var(--#{$prefix}btn-interaction-border-width)) + subtract(var(--#{$prefix}btn-padding-start), var(--#{$prefix}btn-interaction-border-width)); // OUDS mod color: var(--#{$prefix}btn-active-color); background-color: var(--#{$prefix}btn-active-bg); // Remove CSS gradients if they're enabled @@ -86,7 +99,6 @@ // OUDS mod: no box shadow modification for the active state // OUDS mod: no &:focus-visible } - // End mod // OUDS mod: no `.btn-check:checked:focus-visible + &` to handle box shadow @@ -94,7 +106,7 @@ // OUDS mod: selectors are slightly different to handle `.btn-check` // TODO how to handle to disable links with aria-disabled only .btn-check:disabled + &, - &:disabled:not(.loading-indeterminate):not(.loading-determinate):not(.skeleton), + &:disabled:not(.loading-indeterminate):not(.loading-determinate):not(.skeleton):not(:has(.loader-indeterminate-span)), &.disabled, fieldset:disabled & { color: var(--#{$prefix}btn-disabled-color); @@ -111,25 +123,51 @@ fieldset:disabled & { pointer-events: none; } - // End mod // OUDS mod: buttons with icon and text + &:not(.btn-icon):has(> svg), + &:not(.btn-icon):has(> img), + &:not(.btn-icon):has(> .icon) { + --#{$prefix}btn-padding-start: #{$ouds-button-space-padding-inline-icon-start}; + --#{$prefix}btn-padding-end: #{$ouds-button-space-padding-inline-start-icon-end}; + } + &:not(.btn-icon) > svg, &:not(.btn-icon) > img, &:not(.btn-icon) > .icon { width: $ouds-button-size-icon; height: $ouds-button-size-icon; margin-right: $ouds-button-space-column-gap-icon; - margin-left: subtract(var(--#{$prefix}icon-spacing), var(--#{$prefix}btn-padding-x)); overflow: hidden; font-size: $ouds-button-size-icon; line-height: $ouds-button-size-icon; } - // End mod // OUDS mod: loading buttons + &:has(.loader-indeterminate-span) { + color: transparent; + } + + .loader-indeterminate-span { + position: absolute; + display: inline-block; + width: px-to-rem($ouds-button-size-loader); + height: px-to-rem($ouds-button-size-loader); + color: var(--#{$prefix}btn-color); + vertical-align: middle; + background-color: transparent; + border: 3px solid currentcolor; + border-right-color: transparent; + // stylelint-disable-next-line property-disallowed-list + border-radius: 50%; + animation: .75s linear infinite spinner-border; + } + + @keyframes spinner-border { + to { transform: rotate(360deg) #{"/* rtl:ignore */"}; } + } &.loading-indeterminate, &.loading-determinate { @@ -173,7 +211,8 @@ } } - &[class*="loading"] { + &[class*="loading"], + &:has(.loader-indeterminate-span) { &.btn-default { --#{$prefix}btn-color: #{$ouds-button-color-content-default-loading}; --#{$prefix}btn-bg: #{$ouds-button-color-bg-default-loading}; @@ -217,27 +256,27 @@ } } - &.skeleton { - color: transparent; - background-color: $ouds-indicator-skeleton-color-bg; - border: #{$ouds-border-width-none}; - animation: skeleton-loading 1s linear infinite alternate; - } - - @if $enable-bootstrap-compatibility { - &.placeholder { - @extend .skeleton; - } - } - - @keyframes skeleton-loading { - 0% { - background-color: $ouds-indicator-skeleton-color-bg; - } - 100% { - background-color: $ouds-indicator-skeleton-color-gradient-middle; - } - } + //&.skeleton { + // color: transparent; + // background-color: $ouds-indicator-skeleton-color-bg; + // border: #{$ouds-border-width-none}; + // animation: skeleton-loading 1s linear infinite alternate; Animation disabled for now to be consistent with mobile devs + //} + // + //@if $enable-bootstrap-compatibility { + // &.placeholder { + // @extend .skeleton; + // } + //} + // + //@keyframes skeleton-loading { Animation disabled for now to be consistent with mobile devs + // 0% { + // background-color: $ouds-indicator-skeleton-color-bg; + // } + // 100% { + // background-color: $ouds-indicator-skeleton-color-gradient-middle; + // } + //} // End mod } @@ -543,7 +582,8 @@ // OUDS mod: icon button (icon only, without text) .btn-icon { - --#{$prefix}btn-padding-x: #{$ouds-button-space-inset-icon-alone}; + --#{$prefix}btn-padding-start: #{$ouds-button-space-inset-icon-alone}; + --#{$prefix}btn-padding-end: #{$ouds-button-space-inset-icon-alone}; > svg, > img, diff --git a/scss/tokens/_component.scss b/scss/tokens/_component.scss index 675d5d9ab2..21e6d686c3 100644 --- a/scss/tokens/_component.scss +++ b/scss/tokens/_component.scss @@ -114,7 +114,7 @@ $ouds-button-space-padding-block: $ouds-space-padding-block-medium !default; // $ouds-button-space-padding-inline-end-icon-start: $ouds-space-padding-inline-spacious !default; $ouds-button-space-padding-inline-icon-none: $ouds-space-padding-inline-huge !default; $ouds-button-space-padding-inline-icon-start: $ouds-space-padding-inline-taller !default; -// $ouds-button-space-padding-inline-start-icon-end: $ouds-space-padding-inline-spacious !default; +$ouds-button-space-padding-inline-start-icon-end: $ouds-space-padding-inline-spacious !default; // scss-docs-end ouds-component-button // Indicator diff --git a/site/assets/scss/_component-examples.scss b/site/assets/scss/_component-examples.scss index 9e13ba4b9e..895c6915e8 100644 --- a/site/assets/scss/_component-examples.scss +++ b/site/assets/scss/_component-examples.scss @@ -42,7 +42,8 @@ &.colored-bg, .colored-bg { - background: repeating-linear-gradient(-45deg, var(--bs-color-surface-brand-primary), var(--bs-color-surface-brand-primary) 40px, var(--bs-color-surface-status-warning-emphasized) 40px, var(--bs-color-surface-status-warning-emphasized) 80px, var(--bs-color-surface-status-negative-emphasized) 80px, var(--bs-color-surface-status-negative-emphasized) 120px, var(--bs-color-surface-status-positive-emphasized) 120px, var(--bs-color-surface-status-positive-emphasized) 160px, var(--bs-color-surface-status-info-emphasized) 160px, var(--bs-color-surface-status-info-emphasized) 200px); + //background: repeating-linear-gradient(-45deg, var(--bs-color-surface-brand-primary), var(--bs-color-surface-brand-primary) 40px, var(--bs-color-surface-status-warning-emphasized) 40px, var(--bs-color-surface-status-warning-emphasized) 80px, var(--bs-color-surface-status-negative-emphasized) 80px, var(--bs-color-surface-status-negative-emphasized) 120px, var(--bs-color-surface-status-positive-emphasized) 120px, var(--bs-color-surface-status-positive-emphasized) 160px, var(--bs-color-surface-status-info-emphasized) 160px, var(--bs-color-surface-status-info-emphasized) 200px); + background-color: $ouds-color-surface-brand-primary-light; } > .form-control { diff --git a/site/content/docs/0.0/components/buttons.md b/site/content/docs/0.0/components/buttons.md index 6abd9070c1..9b4dcee33d 100644 --- a/site/content/docs/0.0/components/buttons.md +++ b/site/content/docs/0.0/components/buttons.md @@ -283,31 +283,11 @@ To cover cases where you have to keep the `href` attribute on a disabled link, t Strong link {{< /example >}} - -## Skeleton state - -The skeleton state is to be used while some important elements of the page are still loading, before they can be fully displayed. This state improves the perceived loading time by providing a visual cue of where elements will appear once fully loaded. -The `.skeleton` class must be used with the `disabled` attribute to prevent any interaction. This state shouldn't be used on colored backgrounds. - -If the whole page is still loading, you should use a status message to indicate it to users with assistive technologies. - -This state is not usable on colored backgrounds. - -{{< example >}} - -{{< /example >}} - -{{< bootstrap-compatibility >}} -{{< example >}} - -{{< /example >}} -{{< /bootstrap-compatibility >}} - ## Loading state The loading state of a button indicates that an action is currently processing or taking place. This state provides feedback to users, enhancing user experience. - + When the loading starts, you will have to: - Add the `disabled` attribute to the button to avoid any unwanted interactions. - Add the class `.loading-indeterminate` (for an indeterminate loading time) or `.loading-determinate` (for a defined loading time); this will provide an animation corresponding to the current state. @@ -318,35 +298,32 @@ At the end of the loading, you should: - Remove the class `.loading-indeterminate` or `.loading-determinate` to restore its look. - Set a final status message, indicating the loading has ended. -See the buttons un cation in our [loading buttons live example]({{< docsref "/examples/loading-buttons" >}}). +See the buttons un action in our [loading buttons live example]({{< docsref "/examples/loading-buttons" >}}). {{< example class="p-none" >}}
+
{{< /example >}} @@ -429,3 +406,7 @@ There are four mixins for buttons: button and button outline variant mixins (bot Button variants (for regular and outline buttons) use their respective mixins with our `$theme-colors` map to generate the modifier classes in `scss/_buttons.scss`. {{< scss-docs name="btn-variant-loops" file="scss/_buttons.scss" >}} + +### Component tokens + +{{< scss-docs name="ouds-component-button" file="scss/tokens/_component.scss" >}} diff --git a/site/content/docs/0.0/examples/loading-buttons/index.html b/site/content/docs/0.0/examples/loading-buttons/index.html index f65f12d9a9..52171d5dfc 100644 --- a/site/content/docs/0.0/examples/loading-buttons/index.html +++ b/site/content/docs/0.0/examples/loading-buttons/index.html @@ -12,14 +12,19 @@

Loading buttons

Loading buttons in an indeterminate time

-
+
+
+
+
+ @@ -60,11 +65,23 @@

Loading buttons in a determinate time

+ + +

+
+
+ + + + + + +
+
+
diff --git a/site/content/docs/0.0/examples/loading-buttons/loading-buttons.js b/site/content/docs/0.0/examples/loading-buttons/loading-buttons.js index 9d27c512b7..30b0c3cff8 100644 --- a/site/content/docs/0.0/examples/loading-buttons/loading-buttons.js +++ b/site/content/docs/0.0/examples/loading-buttons/loading-buttons.js @@ -12,7 +12,6 @@ statusMessage.innerHTML = 'Downloading file 1' updateStatusMessageCall = setInterval(() => { statusMessage.innerHTML = `${statusMessage.innerHTML}.` - // statusMessage.innerHTML = 'Fichier en téléchargement' }, 3000) // stop loading after 10 secondes for this demo setTimeout(() => { @@ -23,14 +22,37 @@ }, 10000) }) + // Bootstrap compatibility for indeterminate loading time + const statusMessage3 = document.querySelector('#update3') + const loadingButton3 = document.querySelector('#load3') + let updateStatusMessageCall3 + loadingButton3.addEventListener('click', () => { + // Change button's look by adding a loading icon and disable it + loadingButton3.setAttribute('disabled', '') + loadingButton3.innerHTML += '' + // Update indeterminate loading status every 3 seconds + statusMessage3.innerHTML = 'Downloading file 3' + updateStatusMessageCall3 = setInterval(() => { + statusMessage3.innerHTML = `${statusMessage3.innerHTML}.` + }, 3000) + // stop loading after 10 secondes for this demo + setTimeout(() => { + clearTimeout(updateStatusMessageCall3) + statusMessage3.innerHTML = 'End of downloading file 3' + const span3 = document.querySelector('#loader3') + span3.remove() + loadingButton3.removeAttribute('disabled') + }, 10000) + }) + // Determinate loading time const statusMessage2 = document.querySelector('#update2') const loadingButton2 = document.querySelector('#load2') const loadingTime = getComputedStyle(loadingButton2).getPropertyValue('--bs-button-loading-time') let updateStatusMessageCall2 const interval = 3000 - let counter = 0 loadingButton2.addEventListener('click', () => { + let counter = 0 // Change button's look by adding a loading icon and disable it loadingButton2.classList.add('loading-determinate') loadingButton2.setAttribute('disabled', '') diff --git a/site/content/docs/0.0/migration-from-boosted.md b/site/content/docs/0.0/migration-from-boosted.md index 7e05ac49b3..18e57d07b5 100644 --- a/site/content/docs/0.0/migration-from-boosted.md +++ b/site/content/docs/0.0/migration-from-boosted.md @@ -81,7 +81,7 @@ All responsive classes, helpers, and utilities have been updated accordingly to ### Buttons - New `.btn-default`, `.btn-strong`, `.btn-minimal`, and `.btn-negative` have been added. -- New `.btn-default-on-colored-bg`, `.btn-strong-on-colored-bg`, and `.btn-minimal-on-colored-bg` have been added. +- New `.btn-default-on-colored-bg`, `.btn-strong-on-colored-bg`, and `.btn-minimal-on-colored-bg` have been added. - Breaking `.btn-primary`, `.btn-secondary`, `.btn-success`, `.btn-danger`, `.btn-warning`, `.btn-info`, `.btn-light`, and `.btn-dark` have been removed. You can still have them using `$enable-bootstrap-compatibility`. Here is the visual correspondence: - `.btn-primary` will look as `.btn-strong` - `.btn-secondary` will look as `.btn-default` @@ -94,18 +94,15 @@ All responsive classes, helpers, and utilities have been updated accordingly to - Breaking `.btn-no-outline` has been removed. You can use `.btn-minimal` instead. - Breaking `.btn-outline-*` have been removed. You can still have them using `$enable-bootstrap-compatibility`. - Warning `.btn-sm` and `.btn-lg` have been removed. -- Breaking `.btn.placeholder` has been replaced by `.btn.skeleton` to indicate a preloading state. An animation has been added by default. You can still have `.btn.placeholder` using `$enable-bootstrap-compatibility`. - Breaking Loading buttons implementation has changed. You should now use the classes `.loading-indeterminate` and `.loading-determinate` and no more spinner borders. - +
For example, you should now write: ```html ``` Instead of: