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: handle target elements within an iframe #2551

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions landing/css/welcome.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
! tailwindcss v3.3.6 | MIT License | https://tailwindcss.com
*/

/*
Expand Down Expand Up @@ -119,8 +119,10 @@ strong {
}

/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/

code,
Expand All @@ -129,8 +131,12 @@ samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* 1 */
font-size: 1em;
font-feature-settings: normal;
/* 2 */
font-variation-settings: normal;
/* 3 */
font-size: 1em;
/* 4 */
}

/*
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
"test": "yarn lint:js && yarn test:ci",
"pretest:ci": "yarn build",
"test:ci": "yarn test:unit:ci && yarn test:cy:ci:chrome",
"test:cy:ci:chrome": "start-server-and-test start-test-server http://localhost:9002 cy:run:chrome",
"test:cy:watch": "start-server-and-test start-test-server http://localhost:9002 cy:open",
"test:cy:ci:chrome": "start-server-and-test start-test-server http://127.0.0.1:9002 cy:run:chrome",
"test:cy:watch": "start-server-and-test start-test-server http://127.0.0.1:9002 cy:open",
"test:unit:ci": "jest --coverage",
"test:unit:watch": "jest --watch",
"view-coverage": "http-server -p 9003 ./coverage/lcov-report -o",
Expand Down
51 changes: 48 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 | { topLeft: Number, bottomLeft: Number, bottomRight: Number, topRight: 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,9 +133,12 @@
function _styleForStep(step) {
const {
modalOverlayOpeningPadding,
modalOverlayOpeningRadius
modalOverlayOpeningRadius,
modalOverlayOpeningXOffset = 0,
modalOverlayOpeningYOffset = 0
} = step.options;

const iframeOffset = _getIframeOffset(step.target);
const scrollParent = _getScrollParent(step.target);

// Setup recursive function to call requestAnimationFrame to update the modal opening position
Expand All @@ -140,6 +147,8 @@
positionModal(
modalOverlayOpeningPadding,
modalOverlayOpeningRadius,
modalOverlayOpeningXOffset + iframeOffset.left,
modalOverlayOpeningYOffset + iframeOffset.top,
scrollParent,
step.target
);
Expand Down Expand Up @@ -174,6 +183,42 @@
return _getScrollParent(element.parentElement);
}

/**
* Get the top and left offset required to position the modal overlay cutout
* when the target element is within an iframe
* @param {HTMLElement} element The target element
* @private
*/
function _getIframeOffset(element) {
let offset = {
top: 0,
left: 0
};

if (!element) {
return offset;
}

let targetWindow = element.ownerDocument.defaultView;

while (targetWindow !== window.top) {
const targetIframe = targetWindow?.frameElement;

if (targetIframe) {
const targetIframeRect = targetIframe.getBoundingClientRect();

offset.top +=
targetIframeRect.top + (targetIframeRect.scrollTop ?? 0);
offset.left +=
targetIframeRect.left + (targetIframeRect.scrollLeft ?? 0);
}

targetWindow = targetWindow.parent;
}

return offset;
}

/**
* Get the visible height of the target element relative to its scrollParent.
* If there is no scroll parent, the height of the element is returned.
Expand Down
53 changes: 41 additions & 12 deletions src/types/step.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ declare class Step extends Evented {
* @param options The options for the step
* @return The newly created Step instance
*/
constructor(tour: Tour, options: Step.StepOptions);//TODO superheri Note: Return on constructor is not possible in typescript. Could this be possible to make this the same for the constructor of the Step class?
constructor(tour: Tour, options: Step.StepOptions); //TODO superheri Note: Return on constructor is not possible in typescript. Could this be possible to make this the same for the constructor of the Step class?

/**
* The string used as the `id` for the step.
Expand Down Expand Up @@ -41,13 +41,13 @@ declare class Step extends Evented {
* Returns the element for the step
* @return The element instance. undefined if it has never been shown, null if it has been destroyed
*/
getElement(): HTMLElement | null | undefined
getElement(): HTMLElement | null | undefined;

/**
* Returns the target for the step
* @returns The element instance. undefined if it has never been shown, null if query string has not been found
*/
getTarget(): HTMLElement | null | undefined
getTarget(): HTMLElement | null | undefined;

/**
* Returns the tour for the step
Expand Down Expand Up @@ -130,7 +130,7 @@ declare namespace Step {
* A function that returns a promise.
* When the promise resolves, the rest of the `show` code for the step will execute.
*/
beforeShowPromise?: (() => Promise<any>);
beforeShowPromise?: () => Promise<any>;

/**
* An array of buttons to add to the step. These will be rendered in a
Expand Down Expand Up @@ -181,6 +181,16 @@ declare namespace Step {
topRight?: 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 FloatingUI]{@link https://floating-ui.com/docs/tutorial/}
*/
Expand All @@ -195,13 +205,13 @@ declare namespace Step {
* A function that lets you override the default scrollTo behavior and
* define a custom action to do the scrolling, and possibly other logic.
*/
scrollToHandler?: ((element: HTMLElement) => void);
scrollToHandler?: (element: HTMLElement) => void;

/**
* A function that, when it returns `true`, will show the step.
* If it returns `false`, the step will be skipped.
*/
showOn?: (() => boolean);
showOn?: () => boolean;

/**
* The text in the body of the step. It can be one of four types:
Expand All @@ -212,7 +222,11 @@ declare namespace Step {
* - `Function` to be executed when the step is built. It must return one of the three options above.
* ```
*/
text?: string | ReadonlyArray<string> | HTMLElement | (() => string | ReadonlyArray<string> | HTMLElement);
text?:
| string
| ReadonlyArray<string>
| HTMLElement
| (() => string | ReadonlyArray<string> | HTMLElement);

/**
* The step's title. It becomes an `h3` at the top of the step.
Expand All @@ -236,10 +250,25 @@ declare namespace Step {
when?: StepOptionsWhen;
}

type PopperPlacement = 'top'|'top-start'|'top-end'|'bottom'|'bottom-start'|'bottom-end'|'right'|'right-start'|'right-end'|'left'|'left-start'|'left-end';
type PopperPlacement =
| 'top'
| 'top-start'
| 'top-end'
| 'bottom'
| 'bottom-start'
| 'bottom-end'
| 'right'
| 'right-start'
| 'right-end'
| 'left'
| 'left-start'
| 'left-end';

interface StepOptionsAttachTo {
element?: HTMLElement | string | (() => HTMLElement | string | null | undefined);
element?:
| HTMLElement
| string
| (() => HTMLElement | string | null | undefined);
on?: PopperPlacement;
}

Expand All @@ -260,7 +289,7 @@ declare namespace Step {
* }
* ```
*/
action?: ((this: Tour) => void);
action?: (this: Tour) => void;

/**
* Extra classes to apply to the `<a>`
Expand Down Expand Up @@ -290,7 +319,7 @@ declare namespace Step {
}

interface StepOptionsButtonEvent {
[key: string]: (() => void);
[key: string]: () => void;
}

interface StepOptionsCancelIcon {
Expand All @@ -299,7 +328,7 @@ declare namespace Step {
}

interface StepOptionsWhen {
[key: string]: ((this: Step) => void);
[key: string]: (this: Step) => void;
}
}

Expand Down
Loading
Loading