Skip to content

Commit

Permalink
Changes:
Browse files Browse the repository at this point in the history
* improved Offcanvas/Modal support for Tooltip/Popover (when closing offcanvas/modal, will also close any visible tooltip / popover)
* simplified `styleTip` for more accurate coordinates
* reversed some changes for `getElementContainer` utility
* version bump
  • Loading branch information
thednp committed Jan 21, 2022
1 parent ee98b2b commit ea1eda7
Show file tree
Hide file tree
Showing 19 changed files with 878 additions and 394 deletions.
12 changes: 11 additions & 1 deletion assets/css/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,14 @@ nav.border-bottom {
}
[dir="rtl"] .absolute-svg {
left: 1rem; right: auto
}
}

.img-tip-modal,
.svg-tip-modal {
position: absolute; top:250px;
}
.img-tip-modal {right:0}
.svg-tip-modal {right:90px}

[dir="rtl"] .img-tip-modal { right: auto; left: 0 }
[dir="rtl"] .svg-tip-modal { right: auto; left: 90px }
126 changes: 76 additions & 50 deletions dist/bootstrap-native.esm.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Native JavaScript for Bootstrap v4.1.0alpha1 (https://thednp.github.io/bootstrap.native/)
* Native JavaScript for Bootstrap v4.1.0alpha2 (https://thednp.github.io/bootstrap.native/)
* Copyright 2015-2022 © dnp_theme
* Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
*/
Expand Down Expand Up @@ -458,7 +458,7 @@ function normalizeOptions(element, defaultOps, inputOps, ns) {
return normalOps;
}

var version = "4.1.0alpha1";
var version = "4.1.0alpha2";

const Version = version;

Expand Down Expand Up @@ -2558,16 +2558,49 @@ function getParentNode(node) {
*/
const isTableElement = (element) => ['TABLE', 'TD', 'TH'].includes(element.tagName);

/**
* Checks if an element is an `HTMLElement`.
*
* @param {any} element the target object
* @returns {boolean} the query result
*/
const isHTMLElement = (element) => element instanceof HTMLElement;

/**
* Returns an `HTMLElement` to be used as default value for *options.container*
* for `Tooltip` / `Popover` components.
*
* When `getOffset` is *true*, it returns the `offsetParent` for tooltip/popover
* offsets computation similar to **floating-ui**.
* @see https://github.com/floating-ui/floating-ui
*
* @param {HTMLElement | Element} element the target
* @returns {HTMLElement | HTMLBodyElement} the query result
* @param {boolean=} getOffset when *true* it will return an `offsetParent`
* @returns {HTMLElement | HTMLBodyElement | Window | globalThis} the query result
*/
function getElementContainer(element) {
function getElementContainer(element, getOffset) {
const majorBlockTags = ['HTML', 'BODY'];

if (getOffset) {
/** @type {any} */
let { offsetParent } = element;
const win = getWindow(element);
// const { innerWidth } = getDocumentElement(element);

while (offsetParent && (isTableElement(offsetParent)
|| (isHTMLElement(offsetParent)
&& getElementStyle(offsetParent, 'position') !== 'fixed'))) {
offsetParent = offsetParent.offsetParent;
}

if (!offsetParent || (offsetParent
&& (majorBlockTags.includes(offsetParent.tagName)
|| getElementStyle(offsetParent, 'position') === 'static'))) {
offsetParent = win;
}
return offsetParent;
}

/** @type {(HTMLElement)[]} */
const containers = [];
/** @type {any} */
Expand Down Expand Up @@ -3601,26 +3634,6 @@ const isMedia = (element) => element
&& [SVGElement, HTMLImageElement, HTMLVideoElement]
.some((mediaType) => element instanceof mediaType);

const { userAgent: userAgentString } = navigator;

/**
* A global namespace for `navigator.userAgent` string.
*/
const userAgent = userAgentString;

/**
* A global boolean for Gecko browsers. When writing this file,
* Gecko was not supporting `userAgentData`.
*/
const isFirefox = userAgent ? userAgent.includes('Firefox') : false;

/**
* Check if an element is an `<svg>` or any other SVG element.
* @param {any} element the target element
* @returns {boolean} the query result
*/
const isSVGElement = (element) => element instanceof SVGElement;

/**
* Returns an `{x,y}` object with the target
* `HTMLElement` / `Node` scroll position.
Expand Down Expand Up @@ -3696,7 +3709,7 @@ var tipClassPositions = {
function styleTip(self, e) {
const tipClasses = /\b(top|bottom|start|end)+/;
const {
element, tooltip, options, arrow,
element, tooltip, options, arrow, offsetParent,
} = self;
const tipPositions = { ...tipClassPositions };

Expand All @@ -3716,27 +3729,28 @@ function styleTip(self, e) {
const windowHeight = documentElement.clientHeight;
const { container } = options;
let { placement } = options;
const parentIsBody = container.tagName === 'BODY';
// const parentIsBody = container.tagName === 'BODY';
const { left: parentLeft, right: parentRight } = getBoundingClientRect(container, true);
const parentWidth = container.clientWidth;
const parentPosition = getElementStyle(container, 'position');
// const absoluteParent = parentPosition === 'absolute';
const fixedParent = parentPosition === 'fixed';
// const fixedParent = parentPosition === 'fixed';
// const absoluteTarget = getElementStyle(element, 'position') === 'absolute';
const staticParent = parentPosition === 'static';
const absoluteTarget = getElementStyle(element, 'position') === 'absolute';
const stickyFixedParent = ['sticky', 'fixed'].includes(parentPosition);
const leftBoundry = 0;
const rightBoundry = container.clientWidth + parentLeft + (windowWidth - parentRight) - 1;
const rightBoundry = stickyFixedParent ? parentWidth + parentLeft
: parentWidth + parentLeft + (windowWidth - parentRight) - 1;
const {
width: elemWidth,
height: elemHeight,
left: elemRectLeft,
right: elemRectRight,
top: elemRectTop,
} = getBoundingClientRect(element, true);
const offsetParent = parentIsBody || staticParent ? getWindow(element) : container;

const scroll = getNodeScroll(offsetParent);
const isSVG = isSVGElement(element);
const { x, y } = getRectRelativeToOffsetParent(element, offsetParent, scroll);

// reset arrow style
setElementStyle(arrow, { top: '', left: '', right: '' });
let topPosition;
Expand Down Expand Up @@ -3809,23 +3823,17 @@ function styleTip(self, e) {
if (e && isMedia(element)) {
let eX = 0;
let eY = 0;

if (parentIsBody || staticParent) {
if (staticParent) {
eX = e.pageX;
eY = e.pageY;
} else if (['sticky', 'fixed'].includes(parentPosition)) {
eX = e.clientX + scroll.x;
eY = e.clientY + scroll.y;
// parentPosition === 'relative | static | absolute'
} else {
// @ts-ignore -- Firefix breaks here
eX = e.layerX + ((isSVG && !isFirefox) || absoluteTarget ? x : 0);
// @ts-ignore -- Firefix breaks here
eY = e.layerY + ((isSVG && !isFirefox) || absoluteTarget ? y : 0);
eX = e.clientX - container.offsetLeft + scroll.x;
eY = e.clientY - container.offsetTop + scroll.y;
}

// some weird RTL bug
const scrollbarWidth = parentRight - container.clientWidth;
eX -= RTL && fixedParent ? scrollbarWidth : 0;
const scrollbarWidth = parentRight - parentWidth;
eX -= RTL && stickyFixedParent ? scrollbarWidth : 0;

if (placement === 'top') {
topPosition = eY - tipHeight - arrowWidth;
Expand Down Expand Up @@ -3953,6 +3961,13 @@ const { userAgentData: uaDATA } = navigator;
*/
const userAgentData = uaDATA;

const { userAgent: userAgentString } = navigator;

/**
* A global namespace for `navigator.userAgent` string.
*/
const userAgent = userAgentString;

const appleBrands = /(iPhone|iPod|iPad)/;

/**
Expand Down Expand Up @@ -4243,8 +4258,8 @@ function toggleTooltipHandlers(self, add) {
action(element, mousedownEvent, self.show);
action(element, mouseenterEvent, self.show);

if (dismissible) {
if (btn) action(btn, mouseclickEvent, self.hide);
if (dismissible && btn) {
action(btn, mouseclickEvent, self.hide);
} else {
action(element, mouseleaveEvent, self.hide);
action(getDocument(element), touchstartEvent, tooltipTouchHandler, passiveHandler);
Expand All @@ -4267,17 +4282,24 @@ function toggleTooltipHandlers(self, add) {
*/
function toggleTooltipOpenHandlers(self, add) {
const action = add ? on : off;
const { element, options } = self;
const { element, options, offsetParent } = self;
const { container } = options;
const { offsetHeight, scrollHeight } = container;
const win = getWindow(element);
const scrollTarget = offsetHeight !== scrollHeight ? container : win;
const parentModal = closest(element, `.${modalString}`);
const parentOffcanvas = closest(element, `.${offcanvasString}`);

if (!isMedia(element)) {
const win = getWindow(element);
const overflow = offsetHeight !== scrollHeight;
const scrollTarget = overflow || offsetParent !== win ? container : win;
// @ts-ignore
action(win, resizeEvent, self.update, passiveHandler);
action(scrollTarget, scrollEvent, self.update, passiveHandler);
}

// dismiss tooltips inside modal / offcanvas
if (parentModal) on(parentModal, `hide.bs.${modalString}`, self.hide);
if (parentOffcanvas) on(parentOffcanvas, `hide.bs.${offcanvasString}`, self.hide);
}

/**
Expand Down Expand Up @@ -4342,6 +4364,8 @@ class Tooltip extends BaseComponent {
}
/** @type {any} */
self.arrow = {};
/** @type {any} */
self.offsetParent = {};
/** @type {boolean} */
self.enabled = true;
/** @type {string} Set unique ID for `aria-describedby`. */
Expand Down Expand Up @@ -4424,6 +4448,8 @@ class Tooltip extends BaseComponent {
// append to container
container.append(tooltip);
setAttribute(element, ariaDescribedBy, `#${id}`);
// set offsetParent
self.offsetParent = getElementContainer(tooltip, true);

self.update(e);
toggleTooltipOpenHandlers(self, true);
Expand All @@ -4442,7 +4468,6 @@ class Tooltip extends BaseComponent {
*/
hide() {
const self = this;

const { options, tooltip, element } = self;
const { container, animation, delay } = options;

Expand All @@ -4452,6 +4477,7 @@ class Tooltip extends BaseComponent {
Timer.set(element, () => {
const hideTooltipEvent = OriginalEvent(`hide.bs.${toLowerCase(self.name)}`);
dispatchEvent(element, hideTooltipEvent);

if (hideTooltipEvent.defaultPrevented) return;

// @ts-ignore
Expand Down
4 changes: 2 additions & 2 deletions dist/bootstrap-native.esm.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit ea1eda7

Please sign in to comment.