diff --git a/src/components/breadcrumb/breadcrumb.ts b/src/components/breadcrumb/breadcrumb.ts index 75cc32e6..9716be13 100644 --- a/src/components/breadcrumb/breadcrumb.ts +++ b/src/components/breadcrumb/breadcrumb.ts @@ -1,6 +1,7 @@ import { html, LitElement } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import '../../components/icon/icon'; +import { LocalizeController } from '../../utilities/localize'; import styles from './breadcrumb.styles'; import type SlBreadcrumbItem from '../../components/breadcrumb-item/breadcrumb-item'; @@ -22,6 +23,9 @@ export default class SlBreadcrumb extends LitElement { @query('slot') defaultSlot: HTMLSlotElement; @query('slot[name="separator"]') separatorSlot: HTMLSlotElement; + private readonly localize = new LocalizeController(this); + private separatorDir = this.localize.dir(); + /** * The label to use for the breadcrumb control. This will not be shown, but it will be announced by screen readers and * other assistive devices. @@ -35,6 +39,7 @@ export default class SlBreadcrumb extends LitElement { // Clone it, remove ids, and slot it const clone = separator.cloneNode(true) as HTMLElement; [clone, ...clone.querySelectorAll('[id]')].forEach(el => el.removeAttribute('id')); + clone.setAttribute('data-default', ''); clone.slot = 'separator'; return clone; @@ -49,7 +54,13 @@ export default class SlBreadcrumb extends LitElement { // Append separators to each item if they don't already have one const separator = item.querySelector('[slot="separator"]'); if (separator === null) { + // No separator exists, add one item.append(this.getSeparator()); + } else if (separator.hasAttribute('data-default')) { + // A default separator exists, replace it + separator.replaceWith(this.getSeparator()); + } else { + // The user provided a custom separator, leave it alone } // The last breadcrumb item is the "current page" @@ -62,13 +73,21 @@ export default class SlBreadcrumb extends LitElement { } render() { + // We clone the separator and inject them into breadcrumb items, so we need to regenerate the default ones when + // directionality changes. We do this by storing the current separator direction, waiting for render, then calling + // the function that regenerates them. + if (this.separatorDir !== this.localize.dir()) { + this.separatorDir = this.localize.dir(); + this.updateComplete.then(() => this.handleSlotChange()); + } + return html` `; } diff --git a/src/components/split-panel/split-panel.ts b/src/components/split-panel/split-panel.ts index 203c8f01..7f6c798f 100644 --- a/src/components/split-panel/split-panel.ts +++ b/src/components/split-panel/split-panel.ts @@ -101,6 +101,8 @@ export default class SlSplitPanel extends LitElement { } handleDrag(event: PointerEvent) { + const isRtl = this.localize.dir() === 'rtl'; + if (this.disabled) { return; } @@ -130,6 +132,10 @@ export default class SlSplitPanel extends LitElement { snapPoint = parseFloat(value); } + if (isRtl && !this.vertical) { + snapPoint = this.size - snapPoint; + } + if ( newPositionInPixels >= snapPoint - this.snapThreshold && newPositionInPixels <= snapPoint + this.snapThreshold @@ -206,6 +212,7 @@ export default class SlSplitPanel extends LitElement { render() { const gridTemplate = this.vertical ? 'gridTemplateRows' : 'gridTemplateColumns'; const gridTemplateAlt = this.vertical ? 'gridTemplateColumns' : 'gridTemplateRows'; + const isRtl = this.localize.dir() === 'rtl'; const primary = ` clamp( 0%, @@ -220,9 +227,17 @@ export default class SlSplitPanel extends LitElement { const secondary = 'auto'; if (this.primary === 'end') { - this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`; + if (isRtl && !this.vertical) { + this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`; + } else { + this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`; + } } else { - this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`; + if (isRtl && !this.vertical) { + this.style[gridTemplate] = `${secondary} var(--divider-width) ${primary}`; + } else { + this.style[gridTemplate] = `${primary} var(--divider-width) ${secondary}`; + } } // Unset the alt grid template property diff --git a/src/components/tab-group/tab-group.styles.ts b/src/components/tab-group/tab-group.styles.ts index 72d75f25..ac7cf770 100644 --- a/src/components/tab-group/tab-group.styles.ts +++ b/src/components/tab-group/tab-group.styles.ts @@ -51,6 +51,16 @@ export default css` right: 0; } + .tab-group--rtl .tab-group__scroll-button--start { + left: auto; + right: 0; + } + + .tab-group--rtl .tab-group__scroll-button--end { + left: 0; + right: auto; + } + /* * Top */ diff --git a/src/components/tab-group/tab-group.ts b/src/components/tab-group/tab-group.ts index ce5fdf13..d624649a 100644 --- a/src/components/tab-group/tab-group.ts +++ b/src/components/tab-group/tab-group.ts @@ -176,6 +176,7 @@ export default class SlTabGroup extends LitElement { // Move focus left or right if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) { const activeEl = document.activeElement; + const isRtl = this.localize.dir() === 'rtl'; if (activeEl?.tagName.toLowerCase() === 'sl-tab') { let index = this.tabs.indexOf(activeEl as SlTab); @@ -185,12 +186,12 @@ export default class SlTabGroup extends LitElement { } else if (event.key === 'End') { index = this.tabs.length - 1; } else if ( - (['top', 'bottom'].includes(this.placement) && event.key === 'ArrowLeft') || + (['top', 'bottom'].includes(this.placement) && event.key === (isRtl ? 'ArrowRight' : 'ArrowLeft')) || (['start', 'end'].includes(this.placement) && event.key === 'ArrowUp') ) { index--; } else if ( - (['top', 'bottom'].includes(this.placement) && event.key === 'ArrowRight') || + (['top', 'bottom'].includes(this.placement) && event.key === (isRtl ? 'ArrowLeft' : 'ArrowRight')) || (['start', 'end'].includes(this.placement) && event.key === 'ArrowDown') ) { index++; @@ -221,14 +222,20 @@ export default class SlTabGroup extends LitElement { handleScrollToStart() { this.nav.scroll({ - left: this.nav.scrollLeft - this.nav.clientWidth, + left: + this.localize.dir() === 'rtl' + ? this.nav.scrollLeft + this.nav.clientWidth + : this.nav.scrollLeft - this.nav.clientWidth, behavior: 'smooth' }); } handleScrollToEnd() { this.nav.scroll({ - left: this.nav.scrollLeft + this.nav.clientWidth, + left: + this.localize.dir() === 'rtl' + ? this.nav.scrollLeft - this.nav.clientWidth + : this.nav.scrollLeft + this.nav.clientWidth, behavior: 'smooth' }); } @@ -356,6 +363,8 @@ export default class SlTabGroup extends LitElement { } render() { + const isRtl = this.localize.dir() === 'rtl'; + return html`