Skip to content

Commit

Permalink
Merge pull request #11942 from craftcms/feature/exclusive-button-group
Browse files Browse the repository at this point in the history
Refactor Listbox to use exclusive button group pattern
  • Loading branch information
brandonkelly authored Oct 2, 2022
2 parents e36c533 + cb29f6e commit 3f09433
Show file tree
Hide file tree
Showing 15 changed files with 97 additions and 233 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
- Added `Craft.BaseElementIndex::getSourceLevel()`.

### Changed
- Improved the control panel accessibility. ([#10546](https://github.com/craftcms/cms/pull/10546), [#11534](https://github.com/craftcms/cms/pull/11534), [#11565](https://github.com/craftcms/cms/pull/11565), [#11578](https://github.com/craftcms/cms/pull/11578), [#11589](https://github.com/craftcms/cms/pull/11589), [#11604](https://github.com/craftcms/cms/pull/11604), [#11610](https://github.com/craftcms/cms/pull/11610), [#11611](https://github.com/craftcms/cms/pull/11611), [#11613](https://github.com/craftcms/cms/pull/11613), [#11636](https://github.com/craftcms/cms/pull/11636), [#11662](https://github.com/craftcms/cms/pull/11662)[#11703](https://github.com/craftcms/cms/pull/11703), [#11727](https://github.com/craftcms/cms/pull/11727), [#11763](https://github.com/craftcms/cms/pull/11763), [#11768](https://github.com/craftcms/cms/pull/11768), [#11775](https://github.com/craftcms/cms/pull/11775), [#11844](https://github.com/craftcms/cms/pull/11844), [#11905](https://github.com/craftcms/cms/pull/11905), [#11906](https://github.com/craftcms/cms/pull/11906), [#11911](https://github.com/craftcms/cms/pull/11911), [#11915](https://github.com/craftcms/cms/pull/11915), [#11926](https://github.com/craftcms/cms/discussions/11926))
- Improved the control panel accessibility. ([#10546](https://github.com/craftcms/cms/pull/10546), [#11534](https://github.com/craftcms/cms/pull/11534), [#11565](https://github.com/craftcms/cms/pull/11565), [#11578](https://github.com/craftcms/cms/pull/11578), [#11589](https://github.com/craftcms/cms/pull/11589), [#11604](https://github.com/craftcms/cms/pull/11604), [#11610](https://github.com/craftcms/cms/pull/11610), [#11611](https://github.com/craftcms/cms/pull/11611), [#11613](https://github.com/craftcms/cms/pull/11613), [#11636](https://github.com/craftcms/cms/pull/11636), [#11662](https://github.com/craftcms/cms/pull/11662)[#11703](https://github.com/craftcms/cms/pull/11703), [#11727](https://github.com/craftcms/cms/pull/11727), [#11763](https://github.com/craftcms/cms/pull/11763), [#11768](https://github.com/craftcms/cms/pull/11768), [#11775](https://github.com/craftcms/cms/pull/11775), [#11844](https://github.com/craftcms/cms/pull/11844), [#11905](https://github.com/craftcms/cms/pull/11905), [#11906](https://github.com/craftcms/cms/pull/11906), [#11911](https://github.com/craftcms/cms/pull/11911), [#11915](https://github.com/craftcms/cms/pull/11915), [#11926](https://github.com/craftcms/cms/discussions/11926), [#11942](https://github.com/craftcms/cms/pull/11942))
- Element indexes now respect field layouts’ user conditions when determining which custom field columns to show. ([#11913](https://github.com/craftcms/cms/pull/11913))
- Element index footers now stick to the bottom of the window, and element action triggers are now inserted into the footer rather than replacing the contents of the page’s toolbar. ([#11844](https://github.com/craftcms/cms/pull/11844))
- Notifications are now shown after executing folder actions on the Assets index page. ([#11906/](https://github.com/craftcms/cms/pull/11906))
Expand Down
16 changes: 5 additions & 11 deletions src/helpers/Cp.php
Original file line number Diff line number Diff line change
Expand Up @@ -1556,29 +1556,23 @@ public static function fieldLayoutDesignerHtml(FieldLayout $fieldLayout, array $
Html::endTag('div') . // .fld-workspace
Html::beginTag('div', ['class' => 'fld-sidebar']) .
($config['customizableUi']
? Html::beginTag('div', [
'role' => 'listbox',
'class' => ['btngroup', 'small', 'fullwidth'],
? Html::beginTag('section', [
'class' => ['btngroup', 'btngroup--exclusive', 'small', 'fullwidth'],
'aria' => ['label' => Craft::t('app', 'Layout element types')],
'tabindex' => '0',
]) .
Html::button(Craft::t('app', 'Fields'), [
'role' => 'option',
'type' => 'button',
'class' => ['btn', 'small', 'active'],
'aria' => ['selected' => 'true'],
'aria' => ['pressed' => 'true'],
'data' => ['library' => 'field'],
'tabindex' => '-1',
]) .
Html::button(Craft::t('app', 'UI Elements'), [
'role' => 'option',
'type' => 'button',
'class' => ['btn', 'small'],
'aria' => ['selected' => 'false'],
'aria' => ['pressed' => 'false'],
'data' => ['library' => 'ui'],
'tabindex' => '-1',
]) .
Html::endTag('div') // .btngroup
Html::endTag('section') // .btngroup
: '') .
Html::beginTag('div', ['class' => 'fld-field-library']) .
Html::beginTag('div', ['class' => ['texticon', 'search', 'icon', 'clearable']]) .
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/css/cp.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/css/cp.css.map

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions src/web/assets/cp/src/css/_cp.scss
Original file line number Diff line number Diff line change
Expand Up @@ -879,11 +879,6 @@ li.breadcrumb-toggle-wrapper {
opacity: 0.8;
}

.btn[aria-pressed='true'] {
background-color: var(--gray-500);
color: var(--white);
}

.text {
border-radius: var(--large-border-radius);

Expand Down
7 changes: 7 additions & 0 deletions src/web/assets/cp/src/css/_main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1510,6 +1510,13 @@ ul.icons {
}
}

.btngroup--exclusive {
.btn[aria-pressed='true']:not(.disabled):not(.loading):not(.dashed):not([aria-disabled]) {
background-color: var(--gray-500);
color: var(--white);
}
}

.copytext {
position: relative;
z-index: 1;
Expand Down
62 changes: 23 additions & 39 deletions src/web/assets/cp/src/css/_preview.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,29 @@
}

.lp-device-type {
margin: 0;
.btn {
&::before {
width: 27px;
height: 22px;
display: block;
content: '';
background-size: contain;
background-repeat: no-repeat;
background-position: center;
transition-duration: 0.3s;
}

// SVGs
&.lp-device-type-btn--phone::before {
background-image: url(../images/preview/icon-phone.svg);
}
&.lp-device-type-btn--tablet::before {
background-image: url(../images/preview/icon-tablet.svg);
}
&.lp-device-type-btn--desktop::before {
background-image: url(../images/preview/icon-desktop.svg);
}
}
}
}

Expand Down Expand Up @@ -140,49 +162,11 @@
}
}

.lp-device-type__radio-group {
display: flex;
white-space: nowrap;
align-items: center;
}

.lp-device-type__item:not(:last-child) .btn {
body.ltr & {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
margin-right: 1px;
}

body.rtl & {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
margin-left: 1px;
}
}

.lp-preview-container__bumper-link {
top: unset;
bottom: 0;
}

.lp-device-type__item:not(:first-child) .btn {
body.ltr & {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

body.rtl & {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}

.lp-device-type__input {
&.focus-visible + label {
box-shadow: var(--focus-ring);
}
}

.lp-device-mask {
display: none;
}
Expand Down
21 changes: 7 additions & 14 deletions src/web/assets/cp/src/js/BaseElementIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -1339,10 +1339,9 @@ Craft.BaseElementIndex = Garnish.Base.extend(

// Create the buttons if there's more than one mode available to this source
if (this.sourceViewModes.length > 1) {
this.$viewModeBtnContainer = $('<section class="btngroup"/>').attr(
'aria-label',
Craft.t('app', 'View')
);
this.$viewModeBtnContainer = $(
'<section class="btngroup btngroup--exclusive"/>'
).attr('aria-label', Craft.t('app', 'View'));

if (this.activeViewMenu) {
this.$viewModeBtnContainer.insertBefore(this.activeViewMenu.$trigger);
Expand Down Expand Up @@ -2904,36 +2903,30 @@ const ViewMenu = Garnish.Base.extend({
'aria-label': Craft.t('app', 'Sort attribute'),
});

this.$sortDirectionPicker = $('<div/>', {
role: 'listbox',
class: 'btngroup',
this.$sortDirectionPicker = $('<section/>', {
class: 'btngroup btngroup--exclusive',
'aria-label': Craft.t('app', 'Sort direction'),
tabindex: '0',
})
.append(
$('<button/>', {
role: 'option',
type: 'button',
class: 'btn',
title: Craft.t('app', 'Sort ascending'),
'aria-label': Craft.t('app', 'Sort ascending'),
'aria-selected': 'false',
'aria-pressed': 'false',
'data-icon': 'asc',
'data-dir': 'asc',
tabindex: '-1',
})
)
.append(
$('<button/>', {
role: 'option',
type: 'button',
class: 'btn',
title: Craft.t('app', 'Sort descending'),
'aria-label': Craft.t('app', 'Sort descending'),
'aria-selected': 'false',
'aria-pressed': 'false',
'data-icon': 'desc',
'data-dir': 'desc',
tabindex: '-1',
})
)
.appendTo($container);
Expand Down
62 changes: 9 additions & 53 deletions src/web/assets/cp/src/js/Listbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,49 +21,21 @@ Craft.Listbox = Garnish.Base.extend(
}

this.$container.data('listbox', this);
this.$options = this.$container.find('[role=option]');
// todo: drop [role=option] in Craft 5
this.$options = this.$container.find('button,[role=option]');

// is there already a selected option?
this.$selectedOption = this.$options.filter('[aria-selected=true]');
// todo: drop [aria-selected=true] & attr normalization in Craft 5
this.$selectedOption = this.$options
.filter('[aria-pressed=true],[aria-selected=true]')
.removeAttr('aria-selected')
.attr('aria-pressed', 'true');
if (this.$selectedOption.length) {
this.selectedOptionIndex = this.$options.index(this.$selectedOption);
} else {
this.$selectedOption = null;
}

this.addListener(this.$container, 'keydown', (ev) => {
switch (ev.keyCode) {
case Garnish.UP_KEY:
this.selectPrev();
ev.preventDefault();
ev.stopPropagation();
break;
case Garnish.DOWN_KEY:
this.selectNext();
ev.preventDefault();
ev.stopPropagation();
break;
case Garnish.LEFT_KEY:
if (Craft.orientation === 'ltr') {
this.selectPrev();
} else {
this.selectNext();
}
ev.preventDefault();
ev.stopPropagation();
break;
case Garnish.RIGHT_KEY:
if (Craft.orientation === 'ltr') {
this.selectNext();
} else {
this.selectPrev();
}
ev.preventDefault();
ev.stopPropagation();
break;
}
});

this.addListener(this.$options, 'click', (ev) => {
this.select(this.$options.index($(ev.currentTarget)));
ev.preventDefault();
Expand All @@ -82,13 +54,13 @@ Craft.Listbox = Garnish.Base.extend(
if (this.$selectedOption) {
this.$selectedOption
.removeClass(this.settings.selectedClass)
.attr('aria-selected', 'false');
.attr('aria-pressed', 'false');
}

this.$selectedOption = this.$options
.eq(index)
.addClass(this.settings.selectedClass)
.attr('aria-selected', 'true');
.attr('aria-pressed', 'true');

this.selectedOptionIndex = index;

Expand All @@ -99,22 +71,6 @@ Craft.Listbox = Garnish.Base.extend(
});
},

selectPrev: function () {
if (this.selectedOptionIndex === null) {
this.select(0);
} else {
this.select(this.selectedOptionIndex - 1);
}
},

selectNext: function () {
if (this.selectedOptionIndex === null) {
this.select(0);
} else {
this.select(this.selectedOptionIndex + 1);
}
},

disable: function () {
this.base();
this.$container.attr('aria-disabled', 'true');
Expand Down
Loading

0 comments on commit 3f09433

Please sign in to comment.