Skip to content

Commit

Permalink
feat: introduce rounded corners for cutout (configurable)
Browse files Browse the repository at this point in the history
  • Loading branch information
josias-r committed Nov 24, 2022
1 parent 01b91a0 commit 82bdfaa
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 8 deletions.
5 changes: 5 additions & 0 deletions src/lib/boarding-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export interface BoardingSharedOptions {
* @default true
*/
animate: boolean;
/**
* Rounded corner radius for cutout (px)
* @default 5
*/
radius: number;
/**
* Options to be passed to scrollIntoView if supported by browser
* @default { behavior: 'instant', block: 'center' }
Expand Down
5 changes: 5 additions & 0 deletions src/lib/boarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
SHOULD_STRICT_CLICK_HANDLE,
CLASS_NO_CLICK_BODY,
CLASS_STRICT_CLICK_BODY,
OVERLAY_RADIUS,
} from "./common/constants";
import { assertIsElement } from "./common/utils";
import HighlightElement from "./core/highlight-element";
Expand Down Expand Up @@ -69,6 +70,7 @@ class Boarding {
strictClickHandling = SHOULD_STRICT_CLICK_HANDLE, // Whether to only allow clicking the highlighted element
animate = SHOULD_ANIMATE_OVERLAY, // Whether to animate or not
padding = OVERLAY_PADDING, // Spacing around the element from the overlay
radius = OVERLAY_RADIUS, // Rounded corners for cutout
scrollIntoViewOptions = {
behavior: "auto",
block: "center",
Expand All @@ -83,6 +85,7 @@ class Boarding {
strictClickHandling,
animate,
padding,
radius,
scrollIntoViewOptions,
allowClose,
keyboardControl,
Expand All @@ -98,6 +101,7 @@ class Boarding {
this.overlay = new Overlay({
animate: this.options.animate,
padding: this.options.padding,
radius: this.options.radius,
onReset: this.options.onReset,
opacity: this.options.opacity,
onOverlayClick: () => {
Expand Down Expand Up @@ -698,6 +702,7 @@ class Boarding {
onPrevious: currentStep.onPrevious || this.options.onPrevious,
strictClickHandling: currentStep.strictClickHandling,
padding: currentStep.padding, // note this is ONLY the stepLvl padding, the "custom padding", so we can later check if it exists using getCustomPadding
radius: currentStep.radius, // note this is ONLY the stepLvl radius, the "custom radius", so we can later check if it exists using getCustomRadius
},
popover,
});
Expand Down
1 change: 1 addition & 0 deletions src/lib/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const OVERLAY_OPACITY = 0.75;
export const OVERLAY_RADIUS = 5;
export const OVERLAY_PADDING = 10;
export const POPOVER_OFFSET = 10;

Expand Down
26 changes: 21 additions & 5 deletions src/lib/core/cutout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface CutoutDefinition {
height: number;
};
padding?: number;
radius?: number;
fillColor?: string;
opacity?: number;
animated?: boolean;
Expand All @@ -16,15 +17,30 @@ export interface CutoutDefinition {
export function generateSvgCutoutPathString({
hightlightBox,
padding = 0,
radius = 0,
}: CutoutDefinition) {
const windowX = window.innerWidth;
const windowY = window.innerHeight;

const highlightBoxX1 = hightlightBox.x - padding;
const highlightBoxY1 = hightlightBox.y - padding;
const highlightBoxX2 = hightlightBox.x + hightlightBox.width + padding;
const highlightBoxY2 = hightlightBox.y + hightlightBox.height + padding;
return `M${windowX},0L0,0L0,${windowY}L${windowX},${windowY}L${windowX},0ZM${highlightBoxX2},${highlightBoxY1}L${highlightBoxX1},${highlightBoxY1}L${highlightBoxX1},${highlightBoxY2}L${highlightBoxX2},${highlightBoxY2}L${highlightBoxX2},${highlightBoxY1}Z`;
const highlightBoxWidthBase = hightlightBox.width + padding * 2;
const highlightBoxHeightBase = hightlightBox.height + padding * 2;

// prevent glitches when highlightBox is too small for radius
const limitedRadius = Math.min(
radius,
highlightBoxWidthBase / 2,
highlightBoxHeightBase / 2
);
// no value below 0 allowed + round down
const normalizedRadius = Math.floor(Math.max(limitedRadius, 0));

const highlightBoxX = hightlightBox.x - padding + normalizedRadius;
const highlightBoxY = hightlightBox.y - padding;
const highlightBoxWidth = highlightBoxWidthBase - normalizedRadius * 2;
const highlightBoxHeight = highlightBoxHeightBase - normalizedRadius * 2;

return `M${windowX},0L0,0L0,${windowY}L${windowX},${windowY}L${windowX},0Z
M${highlightBoxX},${highlightBoxY} h${highlightBoxWidth} a${normalizedRadius},${normalizedRadius} 0 0 1 ${normalizedRadius},${normalizedRadius} v${highlightBoxHeight} a${normalizedRadius},${normalizedRadius} 0 0 1 -${normalizedRadius},${normalizedRadius} h-${highlightBoxWidth} a${normalizedRadius},${normalizedRadius} 0 0 1 -${normalizedRadius},-${normalizedRadius} v-${highlightBoxHeight} a${normalizedRadius},${normalizedRadius} 0 0 1 ${normalizedRadius},-${normalizedRadius} z`;
}

export function createSvgCutout({
Expand Down
9 changes: 8 additions & 1 deletion src/lib/core/highlight-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type HighlightElementSupportedSharedOptions = Pick<
/** The options of popover that will come from the top-level but can also be overwritten */
export interface HighlightElementHybridOptions
extends Partial<
Pick<BoardingSharedOptions, "padding" | "strictClickHandling">
Pick<BoardingSharedOptions, "padding" | "radius" | "strictClickHandling">
> {
/**
* Callback to be called when element is about to be highlighted
Expand Down Expand Up @@ -138,6 +138,13 @@ class HighlightElement {
return this.options.padding;
}

/**
* Return the element's custom radius option if available
*/
public getCustomRadius() {
return this.options.radius;
}

/**
* Is called when the element is about to be highlighted
*/
Expand Down
25 changes: 23 additions & 2 deletions src/lib/core/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import HighlightElement from "./highlight-element";
/** The top-level options that are shared between multiple classes that overlay supports */
type OverlaySupportedSharedOptions = Pick<
BoardingSharedOptions,
"animate" | "padding"
"animate" | "padding" | "radius"
>;

/** The options of overlay that will come from the top-level */
Expand All @@ -43,7 +43,7 @@ interface OverlayOptions

type AnimatableCutoutDefinition = Pick<
CutoutDefinition,
"padding" | "hightlightBox"
"padding" | "hightlightBox" | "radius"
>;

/**
Expand Down Expand Up @@ -203,17 +203,26 @@ class Overlay {
: {
hightlightBox: fromElement.getElement().getBoundingClientRect(),
padding: fromElement.getCustomPadding(),
radius: fromElement.getCustomRadius(),
};

const toRect = toElement.getElement().getBoundingClientRect();
const toPadding = checkOptionalValue(
this.options.padding,
toElement.getCustomPadding()
);
const toRadius = checkOptionalValue(
this.options.radius,
toElement.getCustomRadius()
);
const fromPadding = checkOptionalValue(
this.options.padding,
fromDefinition.padding
);
const fromRadius = checkOptionalValue(
this.options.radius,
fromDefinition.radius
);

const x = easeInOutQuad(
ellapsed,
Expand Down Expand Up @@ -245,10 +254,17 @@ class Overlay {
toPadding - fromPadding,
duration
);
const radius = easeInOutQuad(
ellapsed,
fromRadius,
toRadius - fromRadius,
duration
);

const newCutoutPosition: AnimatableCutoutDefinition = {
hightlightBox: { x: x, y: y, width: width, height: height },
padding: padding,
radius,
};
this.activeSvgCutoutDefinition = newCutoutPosition;
this.updateCutoutPosition(newCutoutPosition);
Expand Down Expand Up @@ -282,6 +298,10 @@ class Overlay {
this.options.padding,
this.currentHighlightedElement.getCustomPadding()
),
radius: checkOptionalValue(
this.options.radius,
this.currentHighlightedElement.getCustomRadius()
),
};
// update cutout
this.updateCutoutPosition(newCutoutPosition);
Expand Down Expand Up @@ -349,6 +369,7 @@ class Overlay {
hightlightBox: definition.hightlightBox,
padding: definition.padding,
opacity: this.options.opacity,
radius: definition.radius,
animated: this.options.animate,
};

Expand Down

0 comments on commit 82bdfaa

Please sign in to comment.