Skip to content

Commit

Permalink
feature(DockedDisplayPlugin) implemented docked display plugin materi…
Browse files Browse the repository at this point in the history
  • Loading branch information
gselderslaghs committed Jan 5, 2025
1 parent 65ddf18 commit 9eaa469
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 7 deletions.
20 changes: 13 additions & 7 deletions sass/components/_global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ textarea {
font-family: $font-stack;
}

a { color: $link-color; text-decoration: none;
a { color: $link-color; text-decoration: none;
-webkit-tap-highlight-color: transparent; // Gets rid of tap active state
}

Expand Down Expand Up @@ -117,7 +117,7 @@ i {

// Modal
html.noscroll {
position: fixed;
position: fixed;
overflow-y: scroll;
width: 100%;
}
Expand Down Expand Up @@ -526,7 +526,7 @@ $spacing-shortcuts: ("margin": "m", "padding": "p") !default;
$spacing-directions: ("top": "t", "right": "r", "bottom": "b", "left": "l") !default;
$spacing-horizontal: "x" !default;
$spacing-vertical: "y" !default;
$spacing-values: ("0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem, "5": 1.5rem, "6": 3rem, "auto": auto) !default;
$spacing-values: ("0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem, "5": 1.5rem, "6": 3rem, "auto": auto) !default;

@each $property, $shortcut in $spacing-shortcuts{
@each $name, $value in $spacing-values{
Expand All @@ -537,7 +537,7 @@ $spacing-values: ("0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem, "5
// (t, b, r, l) spacing
@each $direction, $suffix in $spacing-directions{
.#{$shortcut}#{$suffix}-#{$name}{
#{$property}-#{$direction}: $value !important
#{$property}-#{$direction}: $value !important
}
}
// x spacing
Expand All @@ -552,7 +552,13 @@ $spacing-values: ("0": 0, "1": 0.25rem, "2": 0.5rem, "3": 0.75rem, "4": 1rem, "5
.#{$shortcut}#{$spacing-vertical}-#{$name}{
#{$property}-top: $value !important;
#{$property}-bottom: $value !important;
}
}
}
}
}
}
}

// Docked display
.display-docked {
position: absolute;
opacity: 0;
}
87 changes: 87 additions & 0 deletions src/plugin/dockedDisplayPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Utils } from '../utils';

export interface DockedDisplayPluginOptions {
/**
* Margin between element and docked container
*/
margin: number,
/**
* Transition movement
*/
transition: number,
/**
* Transition duration
*/
duration: number
}

const _defaults: DockedDisplayPluginOptions = {
margin: 5,
transition: 10,
duration: 250
}

export class DockedDisplayPlugin {
private readonly el: HTMLElement;
private readonly container: HTMLDivElement;
private options: Partial<DockedDisplayPluginOptions>;
private visible: boolean;

constructor(el: HTMLElement, container: HTMLElement, options: Partial<DockedDisplayPluginOptions>) {
this.el = el;
this.options = {
..._defaults,
...options
};

this.container = document.createElement('div');
this.container.classList.add('display-docked');
this.container.append(container);
el.parentElement.append(this.container);

document.addEventListener('click', (e) => {
if (this.visible && !(this.el === <HTMLElement>e.target) && !((<HTMLElement>e.target).closest('.display-docked'))) {
this.hide();
}
});
}

/**
* Initializes instance of DockedDisplayPlugin
* @param el HTMLElement to position to
* @param container HTMLElement to be positioned
* @param options Plugin options
*/
static init(el: HTMLElement, container: HTMLElement, options?: Partial<DockedDisplayPluginOptions>): DockedDisplayPlugin {
return new DockedDisplayPlugin(el, container, options);
}

show = () => {
if (this.visible) return;
this.visible = true;
const coordinates = Utils._setAbsolutePosition(this.el, this.container, 'bottom', this.options.margin, this.options.transition);
this.container.style.left = '16px';
// @todo move to Util? -> duplicate code fragment with tooltip
// easeOutCubic
this.container.style.transition = `
transform ${this.options.duration}ms ease-out,
opacity ${this.options.duration}ms ease-out`;
setTimeout(() => {
this.container.style.transform = `translateX(${coordinates.x}px) translateY(${coordinates.y}px)`;
this.container.style.opacity = (1).toString();
}, 1);
};

hide = () => {
if (!this.visible) return;
this.visible = false;
// @todo move to Util? -> duplicate code fragment with tooltip
this.container.style.transition = `
transform ${this.options.duration}ms ease-out,
opacity ${this.options.duration}ms ease-out`;
setTimeout(() => {
this.container.style.transform = `translateX(0px) translateY(0px)`;
this.container.style.opacity = '0';
}, 1);
};
}
80 changes: 80 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,84 @@ export class Utils {
return result;
};
}

static _setAbsolutePosition(
origin: HTMLElement,
container: HTMLElement,
position: string,
margin: number,
transitionMovement: number
) {
const originHeight = origin.offsetHeight,
originWidth = origin.offsetWidth,
containerHeight = container.offsetHeight,
containerWidth = container.offsetWidth;
let xMovement = 0,
yMovement = 0,
targetTop = origin.getBoundingClientRect().top + Utils.getDocumentScrollTop(),
targetLeft = origin.getBoundingClientRect().left + Utils.getDocumentScrollLeft();

if (position === 'top') {
targetTop += -containerHeight - margin;
targetLeft += originWidth / 2 - containerWidth / 2;
yMovement = -transitionMovement;
} else if (position === 'right') {
targetTop += originHeight / 2 - containerHeight / 2;
targetLeft += originWidth + margin;
xMovement = transitionMovement;
} else if (position === 'left') {
targetTop += originHeight / 2 - containerHeight / 2;
targetLeft += -containerWidth - margin;
xMovement = -transitionMovement;
} else {
targetTop += originHeight + margin;
targetLeft += originWidth / 2 - containerWidth / 2;
yMovement = transitionMovement;
}

const newCoordinates = Utils._repositionWithinScreen(
targetLeft,
targetTop,
containerWidth,
containerHeight,
margin,
transitionMovement
);

container.style.top = newCoordinates.y + 'px';
container.style.left = newCoordinates.x + 'px';

return {x: xMovement, y: yMovement};
}

static _repositionWithinScreen(x: number, y: number, width: number, height: number, margin: number, transitionMovement: number) {
const scrollLeft = Utils.getDocumentScrollLeft();
const scrollTop = Utils.getDocumentScrollTop();
let newX = x - scrollLeft;
let newY = y - scrollTop;

const bounding: Bounding = {
left: newX,
top: newY,
width: width,
height: height
};
const offset = margin + transitionMovement;
const edges = Utils.checkWithinContainer(document.body, bounding, offset);

if (edges.left) {
newX = offset;
} else if (edges.right) {
newX -= newX + width - window.innerWidth;
}
if (edges.top) {
newY = offset;
} else if (edges.bottom) {
newY -= newY + height - window.innerHeight;
}
return {
x: newX + scrollLeft,
y: newY + scrollTop
};
}
}

0 comments on commit 9eaa469

Please sign in to comment.