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

Add modal overlay opening x,y offset settings. #1833

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs-src/tutorials/02-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ You can also always manually advance the Tour by calling `myTour.next()`.
- `id`: The string to use as the `id` for the step. If an id is not passed one will be generated.
- `modalOverlayOpeningPadding`: An amount of padding to add around the modal overlay opening
- `modalOverlayOpeningRadius`: An amount of border radius to add around the modal overlay opening
- `modalOverlayOpeningXOffset`: An amount to offset the modal overlay opening in the x-direction
- `modalOverlayOpeningYOffset`: An amount to offset the modal overlay opening in the y-direction
- `popperOptions`: Extra options to pass to [Popper](https://popper.js.org/docs/v2/constructors/#options)
- `showOn`: A function that, when it returns true, will show the step. If it returns false, the step will be skipped.
- `scrollTo`: Should the element be scrolled to when this step is shown? If true, uses the default `scrollIntoView`, if an object, passes that object as the params to `scrollIntoView` i.e. `{behavior: 'smooth', block: 'center'}`
Expand Down
14 changes: 11 additions & 3 deletions src/js/components/shepherd-modal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
* Uses the bounds of the element we want the opening overtop of to set the dimensions of the opening and position it
* @param {Number} modalOverlayOpeningPadding An amount of padding to add around the modal overlay opening
* @param {Number} modalOverlayOpeningRadius An amount of border radius to add around the modal overlay opening
* @param {Number} modalOverlayOpeningXOffset An amount to offset the modal overlay opening in the x-direction
* @param {Number} modalOverlayOpeningYOffset An amount to offset the modal overlay opening in the y-direction
* @param {HTMLElement} scrollParent The scrollable parent of the target element
* @param {HTMLElement} targetElement The element the opening will expose
*/
export function positionModal(
modalOverlayOpeningPadding = 0,
modalOverlayOpeningRadius = 0,
modalOverlayOpeningXOffset = 0,
modalOverlayOpeningYOffset = 0,
scrollParent,
targetElement
) {
Expand All @@ -55,8 +59,8 @@
openingProperties = {
width: width + modalOverlayOpeningPadding * 2,
height: height + modalOverlayOpeningPadding * 2,
x: (x || left) - modalOverlayOpeningPadding,
y: y - modalOverlayOpeningPadding,
x: (x || left) + modalOverlayOpeningXOffset - modalOverlayOpeningPadding,
y: y + modalOverlayOpeningYOffset - modalOverlayOpeningPadding,
r: modalOverlayOpeningRadius
};
} else {
Expand Down Expand Up @@ -129,7 +133,9 @@
function _styleForStep(step) {
const {
modalOverlayOpeningPadding,
modalOverlayOpeningRadius
modalOverlayOpeningRadius,
modalOverlayOpeningXOffset,
modalOverlayOpeningYOffset
} = step.options;

const scrollParent = _getScrollParent(step.target);
Expand All @@ -140,6 +146,8 @@
positionModal(
modalOverlayOpeningPadding,
modalOverlayOpeningRadius,
modalOverlayOpeningXOffset,
modalOverlayOpeningYOffset,
scrollParent,
step.target
);
Expand Down
10 changes: 10 additions & 0 deletions src/types/step.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ declare namespace Step {
*/
modalOverlayOpeningRadius?: number;

/**
* An amount to offset the modal overlay opening in the x-direction
*/
modalOverlayOpeningXOffset?: number;

/**
* An amount to offset the modal overlay opening in the y-direction
*/
modalOverlayOpeningYOffset?: number;

/**
* Extra [options to pass to Popper]{@link https://popper.js.org/docs/v2/}
*/
Expand Down
2 changes: 1 addition & 1 deletion test/cypress/integration/modal.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ describe('Modal mode', () => {
cy.get('.shepherd-modal-is-visible').should('have.length', 1);
});
});
});
});
104 changes: 96 additions & 8 deletions test/unit/components/shepherd-modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ const classPrefix = '';

describe('components/ShepherdModal', () => {
describe('closeModalOpening()', function() {
it('sets values back to 0', async() => {
it('sets values back to 0', async () => {
const modalComponent = new ShepherdModal({
target: document.body,
props: {
classPrefix
}
});

await modalComponent.positionModal(0, 0, null, {
await modalComponent.positionModal(0, 0, 0, 0, null, {
getBoundingClientRect() {
return {
height: 250,
Expand All @@ -24,7 +24,8 @@ describe('components/ShepherdModal', () => {
}
});

let modalPath = modalComponent.getElement().querySelector('path');
let modalPath = await modalComponent.getElement().querySelector('path');

expect(modalPath).toHaveAttribute(
'd',
'M1024,768H0V0H1024V768ZM20,20a0,0,0,0,0-0,0V270a0,0,0,0,0,0,0H520a0,0,0,0,0,0-0V20a0,0,0,0,0-0-0Z'
Expand All @@ -43,15 +44,16 @@ describe('components/ShepherdModal', () => {
});

describe('positionModal()', function() {
it('sets the correct attributes when positioning modal opening', async() => {
it('sets the correct attributes when positioning modal opening', async () => {
const modalComponent = new ShepherdModal({
target: document.body,
props: {
classPrefix
}
});

let modalPath = modalComponent.getElement().querySelector('path');
let modalPath = await modalComponent.getElement().querySelector('path');

expect(modalPath).toHaveAttribute(
'd',
'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'
Expand All @@ -65,7 +67,7 @@ describe('components/ShepherdModal', () => {
'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'
);

await modalComponent.positionModal(0, 0, null, {
await modalComponent.positionModal(0, 0, 0, 0, null, {
getBoundingClientRect() {
return {
height: 250,
Expand All @@ -85,6 +87,88 @@ describe('components/ShepherdModal', () => {
modalComponent.$destroy();
});

it('can offset the x-axis', async () => {
const modalComponent = new ShepherdModal({
target: document.body,
props: {
classPrefix
}
});

modalComponent.positionModal(0, 0, 50, 0, null, {
getBoundingClientRect() {
return {
height: 250,
x: 10,
y: 10,
width: 500
};
}}
)

let modalPath = await modalComponent.getElement().querySelector('path');

expect(modalPath).toHaveAttribute('d', 'M1024,768H0V0H1024V768ZM60,10a0,0,0,0,0-0,0V260a0,0,0,0,0,0,0H560a0,0,0,0,0,0-0V10a0,0,0,0,0-0-0Z')

modalComponent.positionModal(0, 0, 100, 0, null, {
getBoundingClientRect() {
return {
height: 250,
x: 10,
y: 10,
width: 500
};
}}
)

modalPath = await modalComponent.getElement().querySelector('path');

expect(modalPath).toHaveAttribute('d', 'M1024,768H0V0H1024V768ZM110,10a0,0,0,0,0-0,0V260a0,0,0,0,0,0,0H610a0,0,0,0,0,0-0V10a0,0,0,0,0-0-0Z')

modalComponent.$destroy();
})

it('can offset the y-axis', async () => {
const modalComponent = new ShepherdModal({
target: document.body,
props: {
classPrefix
}
});

modalComponent.positionModal(0, 0, 0, 35, null, {
getBoundingClientRect() {
return {
height: 250,
x: 10,
y: 10,
width: 500
};
}}
)

let modalPath = await modalComponent.getElement().querySelector('path');

expect(modalPath).toHaveAttribute('d', 'M1024,768H0V0H1024V768ZM10,45a0,0,0,0,0-0,0V295a0,0,0,0,0,0,0H510a0,0,0,0,0,0-0V45a0,0,0,0,0-0-0Z')

modalComponent.positionModal(0, 0, 0, 75, null, {
getBoundingClientRect() {
return {
height: 250,
x: 10,
y: 10,
width: 500
};
}}
)

modalPath = await modalComponent.getElement().querySelector('path');

expect(modalPath).toHaveAttribute('d', 'M1024,768H0V0H1024V768ZM10,85a0,0,0,0,0-0,0V335a0,0,0,0,0,0,0H510a0,0,0,0,0,0-0V85a0,0,0,0,0-0-0Z')

modalComponent.$destroy();
})

it('sets the correct attributes with padding', async() => {
const modalComponent = new ShepherdModal({
target: document.body,
Expand All @@ -99,7 +183,7 @@ describe('components/ShepherdModal', () => {
'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'
);

await modalComponent.positionModal(10, 0, null, {
await modalComponent.positionModal(10, 0, 0, 0, null, {
getBoundingClientRect() {
return {
height: 250,
Expand Down Expand Up @@ -141,7 +225,7 @@ describe('components/ShepherdModal', () => {
'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'
);

await modalComponent.positionModal(0, 10, null, {
await modalComponent.positionModal(0, 10, 0, 0, null, {
getBoundingClientRect() {
return {
height: 250,
Expand Down Expand Up @@ -170,6 +254,8 @@ describe('components/ShepherdModal', () => {
});

await modalComponent.positionModal(
0,
0,
0,
0,
{
Expand Down Expand Up @@ -212,6 +298,8 @@ describe('components/ShepherdModal', () => {
});

await modalComponent.positionModal(
0,
0,
0,
0,
{
Expand Down