diff --git a/.circleci/config.yml b/.circleci/config.yml index 01fbf8c6c2..b463c2109c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ executors: parameters: current_golden_images_hash: type: string - default: d9aee952df2073fc366c8f9673ae761da6c196a5 + default: b9ba5bb4f00c3616870378c9791129c484f30e92 wireit_cache_name: type: string default: wireit diff --git a/packages/color-wheel/src/ColorWheel.ts b/packages/color-wheel/src/ColorWheel.ts index d91161a28a..c11f3738b2 100644 --- a/packages/color-wheel/src/ColorWheel.ts +++ b/packages/color-wheel/src/ColorWheel.ts @@ -31,6 +31,7 @@ import { ColorValue, HSL, } from '@spectrum-web-components/reactive-controllers/src/Color.js'; +import { LanguageResolutionController } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; import styles from './color-wheel.css.js'; @@ -63,6 +64,8 @@ export class ColorWheel extends Focusable { @property({ type: Number }) public step = 1; + private languageResolver = new LanguageResolutionController(this); + private colorController = new ColorController(this, { /* c8 ignore next 3 */ applyColorToState: () => { @@ -264,7 +267,7 @@ export class ColorWheel extends Focusable { const pointY = event.clientY - centerY; const value = (Math.atan2(pointY, pointX) * 180) / Math.PI; - return (360 + (360 + value)) % 360; + return (360 + (360 + (this.isLTR ? value : 180 - value))) % 360; } private handleGradientPointerdown(event: PointerEvent): void { @@ -314,7 +317,9 @@ export class ColorWheel extends Focusable { // Calculate handle position on the wheel. const translateX = - (radius - trackWidth / 2) * Math.cos((this.value * Math.PI) / 180); + (this.isLTR ? 1 : -1) * + (radius - trackWidth / 2) * + Math.cos((this.value * Math.PI) / 180); const translateY = (radius - trackWidth / 2) * Math.sin((this.value * Math.PI) / 180); const handleLocationStyles = `transform: translate(${translateX}px, ${translateY}px);`; @@ -377,6 +382,16 @@ export class ColorWheel extends Focusable { max="360" step=${this.step} .value=${String(this.value)} + aria-valuetext=${`${new Intl.NumberFormat( + this.languageResolver.language, + { + maximumFractionDigits: 0, + minimumIntegerDigits: 1, + style: 'unit', + unit: 'degree', + unitDisplay: 'narrow', + } + ).format(this.value)}`} @input=${this.handleInput} @change=${this.handleChange} @keydown=${this.handleKeydown} diff --git a/packages/color-wheel/src/color-wheel.css b/packages/color-wheel/src/color-wheel.css index 67551c097c..2ff2d0a188 100644 --- a/packages/color-wheel/src/color-wheel.css +++ b/packages/color-wheel/src/color-wheel.css @@ -37,3 +37,8 @@ governing permissions and limitations under the License. inline-size: var(--mod-colorwheel-width, var(--spectrum-colorwheel-width)); z-index: 0; } + +:host([dir='rtl']) .wheel, +:host([dir='rtl']) ::slotted([slot='gradient']) { + transform: scaleX(-1); +} diff --git a/packages/color-wheel/test/color-wheel.test.ts b/packages/color-wheel/test/color-wheel.test.ts index 5a8d1fe31e..128cbfae6a 100644 --- a/packages/color-wheel/test/color-wheel.test.ts +++ b/packages/color-wheel/test/color-wheel.test.ts @@ -628,4 +628,27 @@ describe('ColorWheel', () => { expect(el.value).to.equal(hue); expect(tinyHSLA.equals(el.color)).to.be.true; }); + it('should flip orientation with dir="rtl"', async () => { + const el = await fixture( + html` + + ` + ); + + await elementUpdated(el); + + const root = el.shadowRoot ? el.shadowRoot : el; + expect( + getComputedStyle(root.querySelector('.wheel') as HTMLElement) + .transform + ).to.equal('none'); + + el.setAttribute('dir', 'rtl'); + + await elementUpdated(el); + expect( + getComputedStyle(root.querySelector('.wheel') as HTMLElement) + .transform + ).to.equal('matrix(-1, 0, 0, 1, 0, 0)'); + }); });