Skip to content

Commit

Permalink
Fix off canvas accessibility
Browse files Browse the repository at this point in the history
  • Loading branch information
kadencewp committed Aug 19, 2024
1 parent 0f2556f commit f169f23
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 137 deletions.
2 changes: 1 addition & 1 deletion includes/assets/js/kb-off-canvas-trigger.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 65 additions & 62 deletions includes/blocks/header/class-kadence-blocks-off-canvas-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function build_css( $attributes, $css, $unique_id, $unique_style_id ) {
$css->set_media_state( 'desktop' );

// container.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id );
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-inner-wrap' );
if( !empty( $attributes['widthType'] ) && $attributes['widthType'] === 'full') {
$css->add_property( 'width', '100%' );
}
Expand All @@ -113,14 +113,19 @@ public function build_css( $attributes, $css, $unique_id, $unique_style_id ) {
'mobile_key' => 'paddingMobile',
) );

// For the close icon container styles, they need to get applied to the hover state too, due to resets on hover styles in the css
//close icon container
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close' . ', .wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover' );
$css->render_measure_output( $merged_attributes, 'closeIconPadding', 'padding', array(
'desktop_key' => 'closeIconPadding',
'tablet_key' => 'closeIconPaddingTablet',
'mobile_key' => 'closeIconPaddingMobile',
) );
// For the close icon container styles.
// close icon container.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close' );
$css->render_measure_output(
$merged_attributes,
'closeIconPadding',
'padding',
[
'desktop_key' => 'closeIconPadding',
'tablet_key' => 'closeIconPaddingTablet',
'mobile_key' => 'closeIconPaddingMobile',
]
);
$css->render_measure_output( $merged_attributes, 'closeIconBorderRadius', 'border-radius', array(
'desktop_key' => 'closeIconBorderRadius',
'tablet_key' => 'closeIconBorderRadiusTablet',
Expand All @@ -132,16 +137,18 @@ public function build_css( $attributes, $css, $unique_id, $unique_style_id ) {
'mobile_key' => 'closeIconBorderMobile',
) );

//close icon container hover
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover' );
$css->render_border_styles( $merged_attributes, 'closeIconBorderHover', false, array(
'desktop_key' => 'closeIconBorderHover',
'tablet_key' => 'closeIconBorderHoverTablet',
'mobile_key' => 'closeIconBorderHoverMobile',
) );

//close icon
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close svg' );
// Close icon container hover.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover, .wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:focus' );
$css->render_border_styles(
$merged_attributes,
'closeIconBorderHover',
false,
[
'desktop_key' => 'closeIconBorderHover',
'tablet_key' => 'closeIconBorderHoverTablet',
'mobile_key' => 'closeIconBorderHoverMobile',
]
);

return $css->css_output();
}
Expand All @@ -158,11 +165,11 @@ public function sized_dynamic_styles( $css, $attributes, $unique_id, $size = 'De

$css->set_media_state( strtolower( $size ) );

//container
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id );
if( empty( $attributes['widthType'] ) || $attributes['widthType'] !== 'full') {
$max_width_unit = !empty( $attributes['maxWidthUnit'] ) ? $attributes['maxWidthUnit'] : 'px';
if( !empty( $sized_attributes['maxWidth']) ) {
// Container.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-inner-wrap' );
if ( empty( $attributes['widthType'] ) || $attributes['widthType'] !== 'full' ) {
$max_width_unit = ! empty( $attributes['maxWidthUnit'] ) ? $attributes['maxWidthUnit'] : 'px';
if ( ! empty( $sized_attributes['maxWidth']) ) {
$css->add_property( 'max-width', $sized_attributes['maxWidth'] . $max_width_unit );
}
}
Expand All @@ -171,61 +178,58 @@ public function sized_dynamic_styles( $css, $attributes, $unique_id, $size = 'De
}

// Inner container.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-inner');
$max_width_unit = !empty( $sized_attributes['containerMaxWidthUnit'] ) ? $sized_attributes['containerMaxWidthUnit'] : 'px';
if( !empty( $sized_attributes['containerMaxWidth']) ) {
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-inner' );
$max_width_unit = ! empty( $sized_attributes['containerMaxWidthUnit'] ) ? $sized_attributes['containerMaxWidthUnit'] : 'px';
if ( ! empty( $sized_attributes['containerMaxWidth'] ) ) {
$css->add_property( 'max-width', $sized_attributes['containerMaxWidth'] . $max_width_unit );
}

// Content area inner alignment
if ($sized_attributes['hAlign'] == 'center') {
$css->add_property('align-items', 'center');
$css->add_property('margin-left', 'auto');
$css->add_property('margin-right', 'auto');
} else if ($sized_attributes['hAlign'] == 'right') {
$css->add_property('align-items', 'flex-end');
$css->add_property('margin-left', 'auto');
// Content area inner alignment.
if ( $sized_attributes['hAlign'] == 'center') {
$css->add_property( 'align-items', 'center' );
$css->add_property( 'margin-left', 'auto' );
$css->add_property( 'margin-right', 'auto' );
} elseif ( $sized_attributes['hAlign'] == 'right' ) {
$css->add_property( 'align-items', 'flex-end' );
$css->add_property( 'margin-left', 'auto' );
}
if ($sized_attributes['vAlign'] == 'center') {
$css->add_property('justify-content', 'center');
} else if ($sized_attributes['vAlign'] == 'bottom') {
$css->add_property('justify-content', 'flex-end');
if ( $sized_attributes['vAlign'] == 'center' ) {
$css->add_property( 'justify-content', 'center' );
} elseif ( $sized_attributes['vAlign'] == 'bottom' ) {
$css->add_property( 'justify-content', 'flex-end' );
}

// Overlay
// Overlay.
$css->set_selector( '.kb-off-canvas-overlay' . $unique_id );
if ( ! empty( $sized_attributes['pageBackgroundColor'] ) ) {
$css->add_property( 'background-color', $css->render_color( $sized_attributes['pageBackgroundColor'] ) );
}

// For the close icon container styles, they need to get applied to the hover state too, due to resets on hover styles in the css
//Close Icon container
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close' . ', .wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover' );
// Close Icon container.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close' );
if ( ! empty( $sized_attributes['closeIconBackgroundColor'] ) ) {
$css->add_property( 'background-color', $css->render_color( $sized_attributes['closeIconBackgroundColor'] ) );
}
if ( ! empty( $sized_attributes['closeIconColor'] ) ) {
$css->add_property( 'color', $css->render_color( $sized_attributes['closeIconColor'] ) );
}

//Close Icon container hover
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover' );
// Close Icon container hover.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover, .wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:focus' );
if ( ! empty( $sized_attributes['closeIconBackgroundColorHover'] ) ) {
$css->add_property( 'background-color', $css->render_color( $sized_attributes['closeIconBackgroundColorHover'] ) );
}
if ( ! empty( $sized_attributes['closeIconColorHover'] ) ) {
$css->add_property( 'color', $css->render_color( $sized_attributes['closeIconColorHover'] ) );
}

//Close Icon
// Close Icon.
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close svg' );
if ( ! empty( $sized_attributes['closeIconColor'] ) ) {
$css->add_property( 'color', $css->render_color( $sized_attributes['closeIconColor'] ) );
}
if ( ! empty( $sized_attributes['closeIconSize'] ) ) {
$css->add_property( 'width', $sized_attributes['closeIconSize'] . 'px' );
$css->add_property( 'height', $sized_attributes['closeIconSize'] . 'px' );
}

//Close Icon hover
$css->set_selector( '.wp-block-kadence-off-canvas' . $unique_id . ' .kb-off-canvas-close:hover svg' );
if ( ! empty( $sized_attributes['closeIconColorHover'] ) ) {
$css->add_property( 'color', $css->render_color( $sized_attributes['closeIconColorHover'] ) );
}
}

/**
Expand All @@ -236,8 +240,9 @@ public function sized_dynamic_styles( $css, $attributes, $unique_id, $size = 'De
* @return string Returns the block output.
*/
public function build_html( $attributes, $unique_id, $content, $block_instance ) {
$html = '';
$icon = '';
$html = '';
$overlay = '';
$icon = '';

if ( ! empty( $attributes['closeIcon'] ) ) {
$close_icon = $attributes['closeIcon'];
Expand Down Expand Up @@ -265,18 +270,16 @@ public function build_html( $attributes, $unique_id, $content, $block_instance )
'kb-off-canvas-overlay',
'kb-off-canvas-overlay' . $unique_id,
);

if ( empty( $attributes['widthType'] ) || $attributes['widthType'] === 'partial' ) {
$overlay = '<div data-unique-id="' . esc_attr( $unique_id ) . '" class="' . esc_attr( implode( ' ', $overlay_classes ) ) . '"></div>';
}

$wrapper_args = array(
'class' => implode( ' ', $classes ),
);
$wrapper_attributes = get_block_wrapper_attributes( $wrapper_args );

$html .= sprintf( '<div %1$s>%2$s<div class="kb-off-canvas-inner">%3$s</div></div>', $wrapper_attributes, $icon, $content );

if ( empty( $attributes['widthType'] ) || $attributes['widthType'] === 'partial' ) {
$html .= '<div data-unique-id="' . esc_attr( $unique_id ) . '" class="' . esc_attr( implode( ' ', $overlay_classes ) ) . '"></div>';
}
$html .= sprintf( '<div %1$s>%2$s<div class="kb-off-canvas-inner-wrap">%3$s<div class="kb-off-canvas-inner">%4$s</div></div></div>', $wrapper_attributes, $overlay, $icon, $content );

return $html;
}
Expand Down
123 changes: 95 additions & 28 deletions src/assets/js/kb-off-canvas-trigger.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,106 @@
document.addEventListener('DOMContentLoaded', function () {
const triggers = document.querySelectorAll('.wp-block-kadence-off-canvas-trigger');
triggers.forEach(function (trigger) {
trigger.addEventListener('click', function () {
const headerContainer = trigger.closest('.wp-block-kadence-header');
const offCanvas = headerContainer.querySelector('.wp-block-kadence-off-canvas');

if (offCanvas) {
offCanvas.classList.toggle('active');
/**
* File kb-off-canvas-trigger.js.
*
* Handles toggling the off canvas navigation.
*/
(function () {
const handleOffCanvas = function (triggerButtons, offCanvasArea, closeButton) {
const focusableElementsString =
'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]';
let focusableElements = offCanvasArea.querySelectorAll(focusableElementsString);
focusableElements = Array.prototype.slice.call(focusableElements);
let firstFocusableElement = focusableElements[0];

Check failure on line 12 in src/assets/js/kb-off-canvas-trigger.js

View workflow job for this annotation

GitHub Actions / lint

'firstFocusableElement' is never reassigned. Use 'const' instead
let lastFocusableElement = focusableElements[focusableElements.length - 1];

Check failure on line 13 in src/assets/js/kb-off-canvas-trigger.js

View workflow job for this annotation

GitHub Actions / lint

'lastFocusableElement' is never reassigned. Use 'const' instead

const openOffCanvas = function (event) {
event.target.classList.add('triggered');
offCanvasArea.classList.add('show-off-canvas');
setTimeout(function () {
offCanvasArea.classList.add('active');
triggerButtons.forEach((button) => button.setAttribute('aria-expanded', 'true'));
firstFocusableElement.focus();
}, 10);
};

const closeOffCanvas = function () {
offCanvasArea.classList.remove('active');
triggerButtons.forEach((button) => button.setAttribute('aria-expanded', 'false'));
for (let i = 0; i < triggerButtons.length; i++) {
if (triggerButtons[i].classList.contains('triggered')) {
triggerButtons[i].focus();
triggerButtons[i].classList.remove('triggered');
}
}
setTimeout(function () {
offCanvasArea.classList.remove('show-off-canvas');
}, 250);
};

triggerButtons.forEach((button) => {
button.addEventListener('click', openOffCanvas);
});
});

const overlays = document.querySelectorAll('.kb-off-canvas-overlay');
overlays.forEach(function (overlay) {
overlay.addEventListener('click', function () {
const uniqueId = overlay.getAttribute('data-unique-id');
closeButton.addEventListener('click', closeOffCanvas);

if (uniqueId) {
const offCanvas = document.querySelector('.wp-block-kadence-off-canvas' + uniqueId);
function handleKeyDown(event) {
const isTabPressed = event.key === 'Tab' || event.keyCode === 9;

if (offCanvas) {
offCanvas.classList.toggle('active');
if (!isTabPressed) {
return;
}

if (event.shiftKey) {
if (document.activeElement === firstFocusableElement) {
event.preventDefault();
lastFocusableElement.focus();
}
} else {
if (document.activeElement === lastFocusableElement) {

Check failure on line 58 in src/assets/js/kb-off-canvas-trigger.js

View workflow job for this annotation

GitHub Actions / lint

Unexpected if as the only statement in an else block
event.preventDefault();
firstFocusableElement.focus();
}
}
});
});
}

const closeTriggers = document.querySelectorAll('.kb-off-canvas-close');
closeTriggers.forEach(function (trigger) {
trigger.addEventListener('click', function () {
const offCanvas = trigger.closest('.wp-block-kadence-off-canvas');
function handleEscape(event) {
if (event.key === 'Escape' || event.keyCode === 27) {
closeOffCanvas();
}
}

if (offCanvas) {
offCanvas.classList.toggle('active');
// Close modal on outside click.
document.addEventListener('click', function (event) {
var target = event.target;
var modal = document.querySelector('.kb-off-canvas-overlay');
if (target === modal) {
closeOffCanvas();
}
});
});
});

offCanvasArea.addEventListener('keydown', handleKeyDown);
document.addEventListener('keydown', handleEscape);
// Handle closing off canvas when a link is clicked.
var menuLinks = offCanvasArea.querySelectorAll('a:not(.kt-tab-title)');
// No point if no links.
if (menuLinks.length) {
for (let i = 0; i < menuLinks.length; i++) {
menuLinks[i].addEventListener('click', function (event) {
closeOffCanvas();
});
}
}
};

const initOffCanvas = function () {
const triggerButtons = document.querySelectorAll('.wp-block-kadence-off-canvas-trigger');
const offCanvasArea = document.querySelector('.wp-block-kadence-off-canvas');
const closeButton = offCanvasArea.querySelector('.kb-off-canvas-close');

if (triggerButtons.length > 0 && offCanvasArea && closeButton) {
handleOffCanvas(triggerButtons, offCanvasArea, closeButton);
}
};

// Initialize immediately for already loaded DOM
initOffCanvas();
})();
3 changes: 3 additions & 0 deletions src/blocks/header/children/off-canvas-trigger/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@
background: none;
box-shadow: none;
}
svg {
pointer-events: none;
}
}
2 changes: 1 addition & 1 deletion src/blocks/header/children/off-canvas/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@
},
"closeIconColor": {
"type": "string",
"default": "#fffff"
"default": ""
},
"closeIconColorTablet": {
"type": "string",
Expand Down
2 changes: 1 addition & 1 deletion src/blocks/header/children/off-canvas/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
border: 0;
background: transparent;
cursor: pointer;
z-index: 11;
z-index: 0;
display: inline-flex;
align-items: center;
-webkit-appearance: none;
Expand Down
Loading

0 comments on commit f169f23

Please sign in to comment.