Skip to content

Commit

Permalink
Adapt to some of the new decisions made on buttons (to be finalized),…
Browse files Browse the repository at this point in the history
… variant loader-indeterminate with span
  • Loading branch information
hannahiss committed Dec 20, 2024
1 parent 3cf2c8f commit a79a57d
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 84 deletions.
104 changes: 72 additions & 32 deletions scss/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -86,15 +99,14 @@
// 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

// 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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion scss/tokens/_component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion site/assets/scss/_component-examples.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
49 changes: 15 additions & 34 deletions site/content/docs/0.0/components/buttons.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,31 +283,11 @@ To cover cases where you have to keep the `href` attribute on a disabled link, t
<a href="#" class="btn btn-strong disabled" tabindex="-1" role="button" aria-disabled="true">Strong link</a>
{{< /example >}}

<!-- OUDS mod: Skeleton state added -->
## 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 >}}
<button class="btn btn-default skeleton" disabled>Default</button>
{{< /example >}}

{{< bootstrap-compatibility >}}
{{< example >}}
<button class="btn btn-default placeholder" disabled>Default</button>
{{< /example >}}
{{< /bootstrap-compatibility >}}

<!-- OUDS mod: Loading state added -->
## 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.

<!-- TODO to finalize depending on the chosen implementation -->
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.
Expand All @@ -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" >}}
<div class="p-tall">
<button type="button" class="btn btn-default" id="loading-btn0" disabled>
Download file 0
<span class="loader-indeterminate-span" aria-hidden="true"></span>
<span role="status" id="loading-btn-msg0" class="visually-hidden">Downloading file 0</span>
</button>
<button type="button" class="btn btn-default loading-indeterminate" id="loading-btn1" disabled>
Download file 1
<span role="status">
<span id="loading-btn-msg1" class="visually-hidden">Downloading file 1</span>
</span>
<span role="status" id="loading-btn-msg1" class="visually-hidden">Downloading file 1</span>
</button>
<button type="button" class="btn btn-default loading-determinate" id="loading-btn2" disabled>
Download file 2
<span role="status">
<span id="loading-btn-msg2" class="visually-hidden">Downloading file 2</span>
</span>
<span role="status" id="loading-btn-msg2" class="visually-hidden">Downloading file 2</span>
</button>
</div>
<div class="colored-bg p-tall">
<button type="button" class="btn btn-default-on-colored-bg loading-indeterminate" id="loading-btn3" disabled>
Download file 3
<span role="status">
<span id="loading-btn-msg3" class="visually-hidden">Downloading file 3</span>
</span>
<span role="status" id="loading-btn-msg3" class="visually-hidden">Downloading file 3</span>
</button>
<button type="button" class="btn btn-default-on-colored-bg loading-determinate" id="loading-btn4" disabled>
Download file 4
<span role="status">
<span id="loading-btn-msg4" class="visually-hidden">Downloading file 4</span>
</span>
<span role="status" id="loading-btn-msg4" class="visually-hidden">Downloading file 4</span>
</button>
</div>
{{< /example >}}
Expand Down Expand Up @@ -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" >}}
33 changes: 25 additions & 8 deletions site/content/docs/0.0/examples/loading-buttons/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ <h1 class="py-medium">Loading buttons</h1>
<h2 class="py-short">Loading buttons in an indeterminate time</h2>

<div class="row py-taller">
<div class="col-3">
<div class="col-4">
<button type="button" class="btn btn-default" id="load1">
Download file 1
<span role="status">
<span id="update1" class="visually-hidden"></span>
</span>
Download file 1 (indeterminate without span)
<span role="status" id="update1" class="visually-hidden"></span>
</button>
</div>
<div class="col-4">
<button type="button" class="btn btn-default" id="load3">
Download file 3 (indeterminate with span)
<span role="status" id="update3" class="visually-hidden"></span>
</button>
</div>

<!-- <div class="col-3">-->
<!-- <button type="button" class="btn btn-strong">-->
<!-- Strong-->
Expand Down Expand Up @@ -60,11 +65,23 @@ <h2 class="py-short">Loading buttons in a determinate time</h2>
<div class="col-3">
<button type="button" class="btn btn-default" id="load2" style="--bs-button-loading-time: 10;">
Download file 2
<span role="status" aria-live="assertive">
<span id="update2" class="visually-hidden"></span>
</span>
<span role="status" id="update2" class="visually-hidden"></span>
</button>
</div>
</div>



<br><br>
<div class="example-hole">
<div class="btn btn-default">
<span class="loader-determinate">
<span class="fill"></span>
</span>
<span class="">
<span class="fill"></span>
</span>
</div>
</div>

</div>
26 changes: 24 additions & 2 deletions site/content/docs/0.0/examples/loading-buttons/loading-buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand All @@ -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 += '<span class="loader-indeterminate-span" id="loader3" aria-hidden="true"></span>'
// 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', '')
Expand Down
Loading

0 comments on commit a79a57d

Please sign in to comment.