Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dom): handle slotted parent transform position #8158

Merged
merged 5 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/js/utils/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,15 @@ export function getPointerPosition(el, event) {
translated.y += values[13];
}

item = item.parentNode;
if (item.assignedSlot && item.assignedSlot.parentElement && window.WebKitCSSMatrix) {
const transformValue = window.getComputedStyle(item.assignedSlot.parentElement).transform;
const matrix = new window.WebKitCSSMatrix(transformValue);

translated.x += matrix.m41;
translated.y += matrix.m42;
}

item = item.parentNode || item.host;
}
}

Expand Down
16 changes: 16 additions & 0 deletions test/unit/utils/custom-element.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,23 @@ export class TestCustomElement extends HTMLElement {
}
}

export class TestSlotElement extends HTMLElement {

constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const wrapperEl = document.createElement('div');

wrapperEl.style = this.dataset.style;
const slot = document.createElement('slot');

wrapperEl.appendChild(slot);
shadowRoot.appendChild(wrapperEl);
}
}

// Not supported on Chrome < 54
if ('customElements' in window) {
window.customElements.define('test-custom-element', TestCustomElement);
window.customElements.define('test-slot-element', TestSlotElement);
}
84 changes: 84 additions & 0 deletions test/unit/utils/dom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import document from 'global/document';
import sinon from 'sinon';
import * as Dom from '../../../src/js/utils/dom.js';
import TestHelpers from '../test-helpers.js';
import * as browser from '../../../src/js/utils/browser.js';

QUnit.module('utils/dom');

Expand Down Expand Up @@ -687,6 +688,89 @@ QUnit.test('isSingleLeftClick() checks return values for mousedown event', funct
assert.ok(Dom.isSingleLeftClick(mouseEvent), 'a touch event on simulated mobiles is a single left click');
});

QUnit.test('dom.getPointerPosition should return position with translated', function(assert) {
const wrapper = document.createElement('div');

const width = '100px';
const height = '50px';

wrapper.style.width = width;
wrapper.style.height = height;
wrapper.style.position = 'absolute';
wrapper.style.top = '0';
wrapper.style.left = '0';

let position;

document.body.appendChild(wrapper);
const event = {
offsetX: 20,
offsetY: 0,
target: wrapper
};

position = Dom.getPointerPosition(wrapper, event);

// Default click on element without any transform
assert.deepEqual(position, { x: 0.2, y: 1 });

const origIOS = browser.IS_IOS;

wrapper.style.transform = 'translate(5px)';

const transformedTouch = {
offsetX: 20,
offsetY: 0,
target: wrapper,
changedTouches: [
{
pageX: 20,
pageY: 0
}
]
};

// Ignore translate x/y when not in IOS
position = Dom.getPointerPosition(wrapper, transformedTouch);
assert.deepEqual(position, { x: 0.2, y: 1 });

// Add calculate with IOS to true
browser.stub_IS_IOS(true);
position = Dom.getPointerPosition(wrapper, transformedTouch);
assert.deepEqual(position, { x: 0.15, y: 1 });

// Create complex template where position of each video is controlled by
// a web component with transform
wrapper.style.transform = '';
const progressStyle = `position: absolute; height: ${height}; width: ${width};`;

wrapper.innerHTML = `
<test-slot-element id="slides" style="position: absolute" data-style="position: relative; transform: translate(5px);">
<div class="video-01">
<div class="progress-01" style="${progressStyle}"></div>
</div>
<div class="video-02">
<div class="progress-02" style="${progressStyle}"></div>
</div>
</test-slot-element>
`;
document.body.appendChild(wrapper);

const slottedProgressBar = wrapper.querySelector('div.progress-02');

// Handle slot elements pointer position
transformedTouch.target = slottedProgressBar;
position = Dom.getPointerPosition(slottedProgressBar, transformedTouch);
assert.deepEqual(position, { x: 0.15, y: 1 });

// Non IOS slot element pointer position
browser.stub_IS_IOS(false);
position = Dom.getPointerPosition(slottedProgressBar, transformedTouch);
assert.deepEqual(position, { x: 0.20, y: 1 });

browser.stub_IS_IOS(origIOS);
});

QUnit.test('Dom.copyStyleSheetsToWindow() copies all style sheets to a window', function(assert) {
/**
* This test is checking that styles are copied by comparing strings in original stylesheets to those in
Expand Down