@db-ux/react-core-components 2.0.9 → 2.0.10-popover-d7e8b9a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/custom-select/custom-select.js +29 -2
- package/dist/components/custom-select/model.d.ts +3 -2
- package/dist/components/icon/model.d.ts +1 -3
- package/dist/components/icon/model.js +0 -1
- package/dist/components/popover/model.d.ts +0 -1
- package/dist/components/popover/popover.js +60 -9
- package/dist/components/select/model.d.ts +2 -1
- package/dist/components/tooltip/model.d.ts +5 -3
- package/dist/components/tooltip/tooltip.js +60 -11
- package/dist/shared/model.d.ts +11 -3
- package/dist/utils/document-scroll-listener.d.ts +9 -0
- package/dist/utils/document-scroll-listener.js +38 -0
- package/dist/utils/floating-components.d.ts +7 -0
- package/dist/utils/floating-components.js +290 -0
- package/dist/utils/index.d.ts +0 -13
- package/dist/utils/index.js +0 -70
- package/dist/utils/navigation.d.ts +1 -1
- package/dist/utils/navigation.js +1 -1
- package/package.json +3 -3
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { filterPassingProps, getRootProps } from "../../utils/react";
|
|
4
4
|
import { useState, useRef, useEffect, forwardRef } from "react";
|
|
5
|
-
import { cls, delay, getBoolean, getBooleanAsString, getHideProp, getSearchInput,
|
|
5
|
+
import { cls, delay, getBoolean, getBooleanAsString, getHideProp, getSearchInput, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
|
|
6
6
|
import { DEFAULT_CLOSE_BUTTON, DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_LABEL, DEFAULT_LABEL_ID_SUFFIX, DEFAULT_MESSAGE, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_PLACEHOLDER_ID_SUFFIX, DEFAULT_REMOVE, DEFAULT_SELECT_ID_SUFFIX, DEFAULT_SELECTED, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
|
|
7
7
|
import DBCustomSelectList from "../custom-select-list/custom-select-list";
|
|
8
8
|
import DBCustomSelectListItem from "../custom-select-list-item/custom-select-list-item";
|
|
@@ -13,6 +13,8 @@ import DBButton from "../button/button";
|
|
|
13
13
|
import DBTooltip from "../tooltip/tooltip";
|
|
14
14
|
import DBInput from "../input/input";
|
|
15
15
|
import { DocumentClickListener } from "../../utils/document-click-listener";
|
|
16
|
+
import { DocumentScrollListener } from "../../utils/document-scroll-listener";
|
|
17
|
+
import { handleFixedDropdown } from "../../utils/floating-components";
|
|
16
18
|
function DBCustomSelectFn(props, component) {
|
|
17
19
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
18
20
|
props = Object.assign({ clearSelectionText: "Clear selection", showClearSelection: true }, props);
|
|
@@ -45,6 +47,15 @@ function DBCustomSelectFn(props, component) {
|
|
|
45
47
|
const [_hasNoOptions, set_hasNoOptions] = useState(() => false);
|
|
46
48
|
const [_documentClickListenerCallbackId, set_documentClickListenerCallbackId,] = useState(() => undefined);
|
|
47
49
|
const [_internalChangeTimestamp, set_internalChangeTimestamp] = useState(() => 0);
|
|
50
|
+
const [_documentScrollListenerCallbackId, set_documentScrollListenerCallbackId,] = useState(() => undefined);
|
|
51
|
+
const [_observer, set_observer] = useState(() => undefined);
|
|
52
|
+
function handleDocumentScroll(event) {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
if (((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.contains) &&
|
|
55
|
+
((_b = event === null || event === void 0 ? void 0 : event.target) === null || _b === void 0 ? void 0 : _b.contains(detailsRef.current))) {
|
|
56
|
+
handleAutoPlacement();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
48
59
|
function hasValidState() {
|
|
49
60
|
var _a;
|
|
50
61
|
return !!((_a = props.validMessage) !== null && _a !== void 0 ? _a : props.validation === "valid");
|
|
@@ -92,7 +103,9 @@ function DBCustomSelectFn(props, component) {
|
|
|
92
103
|
}
|
|
93
104
|
if (event.target.open) {
|
|
94
105
|
set_documentClickListenerCallbackId(new DocumentClickListener().addCallback((event) => handleDocumentClose(event)));
|
|
106
|
+
set_documentScrollListenerCallbackId(new DocumentScrollListener().addCallback((event) => handleDocumentScroll(event)));
|
|
95
107
|
handleAutoPlacement();
|
|
108
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.observe(detailsRef.current);
|
|
96
109
|
if (!event.target.dataset.test) {
|
|
97
110
|
// We need this workaround for snapshot testing
|
|
98
111
|
handleOpenByKeyboardFocus();
|
|
@@ -102,6 +115,10 @@ function DBCustomSelectFn(props, component) {
|
|
|
102
115
|
if (_documentClickListenerCallbackId) {
|
|
103
116
|
new DocumentClickListener().removeCallback(_documentClickListenerCallbackId);
|
|
104
117
|
}
|
|
118
|
+
if (_documentScrollListenerCallbackId) {
|
|
119
|
+
new DocumentScrollListener().removeCallback(_documentScrollListenerCallbackId);
|
|
120
|
+
}
|
|
121
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.unobserve(detailsRef.current);
|
|
105
122
|
}
|
|
106
123
|
}
|
|
107
124
|
function getNativeSelectValue() {
|
|
@@ -156,8 +173,10 @@ function DBCustomSelectFn(props, component) {
|
|
|
156
173
|
if (detailsRef.current) {
|
|
157
174
|
const dropdown = detailsRef.current.querySelector("article");
|
|
158
175
|
if (dropdown) {
|
|
176
|
+
// This is a workaround for Angular
|
|
159
177
|
delay(() => {
|
|
160
|
-
|
|
178
|
+
var _a;
|
|
179
|
+
handleFixedDropdown(dropdown, detailsRef.current, (_a = props.placement) !== null && _a !== void 0 ? _a : "bottom");
|
|
161
180
|
}, 1);
|
|
162
181
|
}
|
|
163
182
|
}
|
|
@@ -400,6 +419,14 @@ function DBCustomSelectFn(props, component) {
|
|
|
400
419
|
set_selectedLabelsId(mId + "-selected-labels");
|
|
401
420
|
set_infoTextId(mId + "-info");
|
|
402
421
|
set_invalidMessage(props.invalidMessage || DEFAULT_INVALID_MESSAGE);
|
|
422
|
+
set_observer(new IntersectionObserver((payload) => {
|
|
423
|
+
if (detailsRef.current) {
|
|
424
|
+
const entry = payload.find(({ target }) => target === detailsRef.current);
|
|
425
|
+
if (entry && !entry.isIntersecting && detailsRef.current.open) {
|
|
426
|
+
detailsRef.current.open = false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}));
|
|
403
430
|
}, []);
|
|
404
431
|
useEffect(() => {
|
|
405
432
|
if (detailsRef.current) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseFormProps, CloseEventState, CustomFormProps, FormMessageProps, FormState, FromValidState, GlobalProps, GlobalState, IconProps, PlacementVerticalType,
|
|
1
|
+
import { BaseFormProps, CloseEventState, CustomFormProps, DocumentScrollState, FormMessageProps, FormState, FromValidState, GlobalProps, GlobalState, IconProps, PlacementVerticalType, RequiredProps, ShowIconProps, ShowLabelProps, ValidationType, WidthType } from '../../shared/model';
|
|
2
2
|
import { DBCustomSelectFormFieldDefaultProps } from '../custom-select-form-field/model';
|
|
3
3
|
import { CustomSelectDropdownWidthType } from '../custom-select-dropdown/model';
|
|
4
4
|
import { DBCustomSelectListItemExtraProps } from '../custom-select-list-item/model';
|
|
@@ -189,5 +189,6 @@ export type DBCustomSelectDefaultState = {
|
|
|
189
189
|
getSelectAllLabel: () => string;
|
|
190
190
|
selectAllChecked: boolean;
|
|
191
191
|
selectAllIndeterminate: boolean;
|
|
192
|
+
handleAutoPlacement: () => void;
|
|
192
193
|
};
|
|
193
|
-
export type DBCustomSelectState = DBCustomSelectDefaultState & GlobalState & FormState & FromValidState & CloseEventState &
|
|
194
|
+
export type DBCustomSelectState = DBCustomSelectDefaultState & GlobalState & FormState & FromValidState & CloseEventState & DocumentScrollState;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { GlobalProps, GlobalState, IconProps, TextProps } from '../../shared/model';
|
|
2
|
-
export declare const IconVariantList: readonly ["default", "inverted", "filled"];
|
|
3
|
-
export type IconVariantType = (typeof IconVariantList)[number];
|
|
4
2
|
export declare const IconWeightList: readonly ["16", "20", "24", "32", "48", "64"];
|
|
5
3
|
export type IconWeightType = (typeof IconWeightList)[number];
|
|
6
4
|
export type DBIconDefaultProps = {
|
|
7
|
-
variant?:
|
|
5
|
+
variant?: string;
|
|
8
6
|
weight?: IconWeightType;
|
|
9
7
|
};
|
|
10
8
|
export type DBIconProps = DBIconDefaultProps & GlobalProps & IconProps & TextProps;
|
|
@@ -13,6 +13,5 @@ export type DBPopoverProps = DBPopoverDefaultProps & GlobalProps & SpacingProps
|
|
|
13
13
|
export type DBPopoverDefaultState = {
|
|
14
14
|
isExpanded?: boolean;
|
|
15
15
|
getTrigger: () => Element | null;
|
|
16
|
-
handleLeave: (event: any) => void;
|
|
17
16
|
};
|
|
18
17
|
export type DBPopoverState = DBPopoverDefaultState & GlobalState & PopoverState & InitializedState;
|
|
@@ -2,29 +2,66 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { filterPassingProps, getRootProps } from "../../utils/react";
|
|
4
4
|
import { useState, useRef, useEffect, forwardRef } from "react";
|
|
5
|
-
import { cls,
|
|
5
|
+
import { cls, delay as utilsDelay, getBooleanAsString } from "../../utils";
|
|
6
|
+
import { handleFixedPopover } from "../../utils/floating-components";
|
|
7
|
+
import { DocumentScrollListener } from "../../utils/document-scroll-listener";
|
|
6
8
|
function DBPopoverFn(props, component) {
|
|
7
9
|
var _a;
|
|
8
10
|
const _ref = component || useRef(component);
|
|
9
11
|
const [initialized, setInitialized] = useState(() => false);
|
|
10
12
|
const [isExpanded, setIsExpanded] = useState(() => false);
|
|
13
|
+
const [_documentScrollListenerCallbackId, set_documentScrollListenerCallbackId,] = useState(() => undefined);
|
|
14
|
+
const [_observer, set_observer] = useState(() => undefined);
|
|
15
|
+
function handleEscape(event) {
|
|
16
|
+
if (!event || event.key === "Escape") {
|
|
17
|
+
// TODO: Recursive for any child
|
|
18
|
+
for (const child of Array.from(_ref.current.children)) {
|
|
19
|
+
child.blur();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
11
23
|
function handleAutoPlacement() {
|
|
12
|
-
setIsExpanded(true);
|
|
13
24
|
if (!_ref.current)
|
|
14
25
|
return;
|
|
15
26
|
const article = _ref.current.querySelector("article");
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
if (article) {
|
|
28
|
+
// This is a workaround for angular
|
|
29
|
+
utilsDelay(() => {
|
|
30
|
+
var _a;
|
|
31
|
+
handleFixedPopover(article, _ref.current, (_a = props.placement) !== null && _a !== void 0 ? _a : "bottom");
|
|
32
|
+
}, 1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function handleDocumentScroll(event) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
if (((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.contains) && ((_b = event === null || event === void 0 ? void 0 : event.target) === null || _b === void 0 ? void 0 : _b.contains(_ref.current))) {
|
|
38
|
+
handleAutoPlacement();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function handleEnter() {
|
|
42
|
+
setIsExpanded(true);
|
|
43
|
+
set_documentScrollListenerCallbackId(new DocumentScrollListener().addCallback((event) => handleDocumentScroll(event)));
|
|
44
|
+
handleAutoPlacement();
|
|
45
|
+
const child = getTrigger();
|
|
46
|
+
if (child) {
|
|
47
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.observe(child);
|
|
48
|
+
}
|
|
19
49
|
}
|
|
20
50
|
function handleLeave(event) {
|
|
21
|
-
const element = event.target;
|
|
22
|
-
const parent = element.parentNode;
|
|
51
|
+
const element = event === null || event === void 0 ? void 0 : event.target;
|
|
52
|
+
const parent = element === null || element === void 0 ? void 0 : element.parentNode;
|
|
23
53
|
if (!parent ||
|
|
24
54
|
(element.parentNode.querySelector(":focus") !== element &&
|
|
25
55
|
element.parentNode.querySelector(":focus-within") !== element &&
|
|
26
56
|
element.parentNode.querySelector(":hover") !== element)) {
|
|
27
57
|
setIsExpanded(false);
|
|
58
|
+
if (_documentScrollListenerCallbackId) {
|
|
59
|
+
new DocumentScrollListener().removeCallback(_documentScrollListenerCallbackId);
|
|
60
|
+
}
|
|
61
|
+
const child = getTrigger();
|
|
62
|
+
if (child) {
|
|
63
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.unobserve(child);
|
|
64
|
+
}
|
|
28
65
|
}
|
|
29
66
|
}
|
|
30
67
|
function getTrigger() {
|
|
@@ -51,11 +88,25 @@ function DBPopoverFn(props, component) {
|
|
|
51
88
|
}, []);
|
|
52
89
|
useEffect(() => {
|
|
53
90
|
if (_ref.current && initialized) {
|
|
91
|
+
setInitialized(false);
|
|
54
92
|
const child = getTrigger();
|
|
55
93
|
if (child) {
|
|
56
94
|
child.ariaHasPopup = "true";
|
|
57
95
|
}
|
|
58
|
-
|
|
96
|
+
handleAutoPlacement();
|
|
97
|
+
_ref.current.addEventListener("keydown", (event) => handleEscape(event));
|
|
98
|
+
["mouseenter", "focusin"].forEach((event) => {
|
|
99
|
+
_ref.current.addEventListener(event, () => handleEnter());
|
|
100
|
+
});
|
|
101
|
+
["mouseleave", "focusout"].forEach((event) => {
|
|
102
|
+
_ref.current.addEventListener(event, () => handleLeave());
|
|
103
|
+
});
|
|
104
|
+
set_observer(new IntersectionObserver((payload) => {
|
|
105
|
+
const entry = payload.find(({ target }) => target === getTrigger());
|
|
106
|
+
if (entry && !entry.isIntersecting) {
|
|
107
|
+
handleEscape(false);
|
|
108
|
+
}
|
|
109
|
+
}));
|
|
59
110
|
}
|
|
60
111
|
}, [_ref.current, initialized]);
|
|
61
112
|
useEffect(() => {
|
|
@@ -66,7 +117,7 @@ function DBPopoverFn(props, component) {
|
|
|
66
117
|
}
|
|
67
118
|
}
|
|
68
119
|
}, [_ref.current, isExpanded]);
|
|
69
|
-
return (React.createElement("div", Object.assign({ ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: props.id }, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-popover", props.className)
|
|
120
|
+
return (React.createElement("div", Object.assign({ ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: props.id }, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-popover", props.className) }),
|
|
70
121
|
React.createElement(React.Fragment, null, props.trigger),
|
|
71
122
|
React.createElement("article", { className: "db-popover-content", "data-spacing": props.spacing, "data-gap": getBooleanAsString(props.gap), "data-animation": getBooleanAsString((_a = props.animation) !== null && _a !== void 0 ? _a : true), "data-open": getBooleanAsString(props.open), "data-delay": props.delay, "data-width": props.width, "data-placement": props.placement }, props.children)));
|
|
72
123
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ChangeEventProps, ChangeEventState, ClickEventProps, ClickEventState, FocusEventProps, FocusEventState, FormMessageProps, FormProps, FormSizeProps, FormState, FromValidState, GlobalProps, GlobalState, IconProps, InitializedState, InputEventProps, InputEventState, ShowIconProps } from '../../shared/model';
|
|
2
2
|
export type DBSelectDefaultProps = {
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* @deprecated
|
|
5
|
+
* Enables multiple select, but it isn't styled, please use DBCustomSelect/db-custom-select instead
|
|
5
6
|
*/
|
|
6
7
|
multiple?: boolean;
|
|
7
8
|
/**
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { ClickEventState, EmphasisProps, GlobalProps, GlobalState, InitializedState, PlacementProps, PopoverProps, PopoverState } from '../../shared/model';
|
|
1
|
+
import { ClickEventState, DocumentScrollState, EmphasisProps, GlobalProps, GlobalState, InitializedState, PlacementProps, PopoverProps, PopoverState } from '../../shared/model';
|
|
2
2
|
export type DBTooltipDefaultProps = {
|
|
3
3
|
showArrow?: boolean | string;
|
|
4
4
|
};
|
|
5
5
|
export type DBTooltipProps = DBTooltipDefaultProps & GlobalProps & EmphasisProps & PlacementProps & PopoverProps;
|
|
6
|
-
export type DBTooltipDefaultState = {
|
|
7
|
-
|
|
6
|
+
export type DBTooltipDefaultState = {
|
|
7
|
+
getParent: () => HTMLElement;
|
|
8
|
+
};
|
|
9
|
+
export type DBTooltipState = DBTooltipDefaultState & GlobalState & ClickEventState<HTMLElement> & PopoverState & InitializedState & DocumentScrollState;
|
|
@@ -2,19 +2,62 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { filterPassingProps, getRootProps } from "../../utils/react";
|
|
4
4
|
import { useState, useRef, useEffect, forwardRef } from "react";
|
|
5
|
-
import { cls,
|
|
5
|
+
import { cls, delay as utilsDelay, getBooleanAsString, uuid, } from "../../utils";
|
|
6
6
|
import { DEFAULT_ID } from "../../shared/constants";
|
|
7
|
+
import { handleFixedPopover } from "../../utils/floating-components";
|
|
8
|
+
import { DocumentScrollListener } from "../../utils/document-scroll-listener";
|
|
7
9
|
function DBTooltipFn(props, component) {
|
|
8
10
|
var _a, _b;
|
|
9
11
|
const _ref = component || useRef(component);
|
|
10
12
|
const [_id, set_id] = useState(() => DEFAULT_ID);
|
|
11
13
|
const [initialized, setInitialized] = useState(() => false);
|
|
14
|
+
const [_documentScrollListenerCallbackId, set_documentScrollListenerCallbackId,] = useState(() => undefined);
|
|
15
|
+
const [_observer, set_observer] = useState(() => undefined);
|
|
12
16
|
function handleClick(event) {
|
|
13
17
|
event.stopPropagation();
|
|
14
18
|
}
|
|
15
|
-
function
|
|
16
|
-
if (
|
|
17
|
-
|
|
19
|
+
function handleEscape(event) {
|
|
20
|
+
if ((!event || event.key === "Escape") &&
|
|
21
|
+
_ref.current &&
|
|
22
|
+
getComputedStyle(_ref.current).visibility === "visible") {
|
|
23
|
+
getParent().blur();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getParent() {
|
|
27
|
+
let parent = _ref.current.parentElement;
|
|
28
|
+
if (parent && parent.localName.includes("tooltip")) {
|
|
29
|
+
// Angular workaround
|
|
30
|
+
parent = parent.parentElement;
|
|
31
|
+
}
|
|
32
|
+
return parent;
|
|
33
|
+
}
|
|
34
|
+
function handleAutoPlacement(parent) {
|
|
35
|
+
if (!parent)
|
|
36
|
+
return;
|
|
37
|
+
if (_ref.current) {
|
|
38
|
+
// This is a workaround for angular
|
|
39
|
+
utilsDelay(() => {
|
|
40
|
+
var _a;
|
|
41
|
+
handleFixedPopover(_ref.current, parent, (_a = props.placement) !== null && _a !== void 0 ? _a : "bottom");
|
|
42
|
+
}, 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function handleDocumentScroll(event, parent) {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
if (((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.contains) && ((_b = event === null || event === void 0 ? void 0 : event.target) === null || _b === void 0 ? void 0 : _b.contains(_ref.current))) {
|
|
48
|
+
handleAutoPlacement(parent);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function handleLeave() {
|
|
52
|
+
if (_documentScrollListenerCallbackId) {
|
|
53
|
+
new DocumentScrollListener().removeCallback(_documentScrollListenerCallbackId);
|
|
54
|
+
}
|
|
55
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.unobserve(getParent());
|
|
56
|
+
}
|
|
57
|
+
function handleEnter(parent) {
|
|
58
|
+
set_documentScrollListenerCallbackId(new DocumentScrollListener().addCallback((event) => handleDocumentScroll(event, parent)));
|
|
59
|
+
handleAutoPlacement(parent);
|
|
60
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.observe(getParent());
|
|
18
61
|
}
|
|
19
62
|
useEffect(() => {
|
|
20
63
|
set_id(props.id || "tooltip-" + uuid());
|
|
@@ -22,18 +65,24 @@ function DBTooltipFn(props, component) {
|
|
|
22
65
|
}, []);
|
|
23
66
|
useEffect(() => {
|
|
24
67
|
if (_ref.current && initialized && _id) {
|
|
25
|
-
|
|
26
|
-
if (parent && parent.localName.includes("tooltip")) {
|
|
27
|
-
// Angular workaround
|
|
28
|
-
parent = parent.parentElement;
|
|
29
|
-
}
|
|
68
|
+
const parent = getParent();
|
|
30
69
|
if (parent) {
|
|
31
|
-
["mouseenter", "
|
|
32
|
-
parent.addEventListener(event, () =>
|
|
70
|
+
["mouseenter", "focusin"].forEach((event) => {
|
|
71
|
+
parent.addEventListener(event, () => handleEnter(parent));
|
|
72
|
+
});
|
|
73
|
+
parent.addEventListener("keydown", (event) => handleEscape(event));
|
|
74
|
+
["mouseleave", "focusout"].forEach((event) => {
|
|
75
|
+
parent.addEventListener(event, () => handleLeave());
|
|
33
76
|
});
|
|
34
77
|
parent.setAttribute("data-has-tooltip", "true");
|
|
35
78
|
parent.setAttribute("aria-describedby", _id);
|
|
36
79
|
}
|
|
80
|
+
set_observer(new IntersectionObserver((payload) => {
|
|
81
|
+
const entry = payload.find(({ target }) => target === getParent());
|
|
82
|
+
if (entry && !entry.isIntersecting) {
|
|
83
|
+
handleEscape(false);
|
|
84
|
+
}
|
|
85
|
+
}));
|
|
37
86
|
setInitialized(false);
|
|
38
87
|
}
|
|
39
88
|
}, [_ref.current, initialized]);
|
package/dist/shared/model.d.ts
CHANGED
|
@@ -150,9 +150,6 @@ export type PopoverProps = {
|
|
|
150
150
|
*/
|
|
151
151
|
width?: PopoverWidthType;
|
|
152
152
|
};
|
|
153
|
-
export type PopoverState = {
|
|
154
|
-
handleAutoPlacement: () => void;
|
|
155
|
-
};
|
|
156
153
|
export type NameProps = {
|
|
157
154
|
/**
|
|
158
155
|
* The name attribute gives the name of the element to group it.
|
|
@@ -493,3 +490,14 @@ export type ValueLabelType = {
|
|
|
493
490
|
value: string;
|
|
494
491
|
label?: string;
|
|
495
492
|
};
|
|
493
|
+
export type DocumentScrollState = {
|
|
494
|
+
_documentScrollListenerCallbackId?: string;
|
|
495
|
+
handleDocumentScroll: (event: any, parent?: HTMLElement) => void;
|
|
496
|
+
_observer?: IntersectionObserver;
|
|
497
|
+
};
|
|
498
|
+
export type PopoverState = {
|
|
499
|
+
handleEscape: (event: any) => void;
|
|
500
|
+
handleAutoPlacement: (parent?: HTMLElement) => void;
|
|
501
|
+
handleEnter: (parent?: HTMLElement) => void;
|
|
502
|
+
handleLeave: (event?: any) => void;
|
|
503
|
+
} & DocumentScrollState;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { uuid } from './index';
|
|
2
|
+
export class DocumentScrollListener {
|
|
3
|
+
static runCallbacks(event) {
|
|
4
|
+
for (const callback of Object.values(DocumentScrollListener.callbacks)) {
|
|
5
|
+
if (typeof callback === 'function') {
|
|
6
|
+
callback(event);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
constructor() {
|
|
11
|
+
this.ticking = false;
|
|
12
|
+
if (DocumentScrollListener._instance) {
|
|
13
|
+
return DocumentScrollListener._instance;
|
|
14
|
+
}
|
|
15
|
+
DocumentScrollListener._instance = this;
|
|
16
|
+
if (self.document) {
|
|
17
|
+
self.document.addEventListener('scroll', event => {
|
|
18
|
+
if (!this.ticking) {
|
|
19
|
+
window.requestAnimationFrame(() => {
|
|
20
|
+
DocumentScrollListener.runCallbacks(event);
|
|
21
|
+
this.ticking = false;
|
|
22
|
+
});
|
|
23
|
+
this.ticking = true;
|
|
24
|
+
}
|
|
25
|
+
}, true);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
addCallback(callback) {
|
|
29
|
+
const callbackID = uuid();
|
|
30
|
+
DocumentScrollListener.callbacks[callbackID] = callback;
|
|
31
|
+
return callbackID;
|
|
32
|
+
}
|
|
33
|
+
removeCallback(id) {
|
|
34
|
+
delete DocumentScrollListener.callbacks[id];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
DocumentScrollListener.callbacks = {};
|
|
38
|
+
DocumentScrollListener._instance = null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface DBDataOutsidePair {
|
|
2
|
+
vx?: 'left' | 'right';
|
|
3
|
+
vy?: 'top' | 'bottom';
|
|
4
|
+
}
|
|
5
|
+
export declare const handleDataOutside: (el: HTMLElement) => DBDataOutsidePair;
|
|
6
|
+
export declare const handleFixedDropdown: (element: HTMLElement, parent: HTMLElement, placement: string) => void;
|
|
7
|
+
export declare const handleFixedPopover: (element: HTMLElement, parent: HTMLElement, placement: string) => void;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// TODO: We should reevaluate this as soon as CSS Anchor Positioning is supported in all relevant browsers
|
|
2
|
+
const isInView = (el) => {
|
|
3
|
+
var _a;
|
|
4
|
+
const { top, bottom, left, right } = el.getBoundingClientRect();
|
|
5
|
+
const { innerHeight, innerWidth } = window;
|
|
6
|
+
let outTop = top < 0;
|
|
7
|
+
let outBottom = bottom > innerHeight;
|
|
8
|
+
let outLeft = left < 0;
|
|
9
|
+
let outRight = right > innerWidth;
|
|
10
|
+
// We need to check if it was already outside
|
|
11
|
+
const outsideY = el.dataset['outsideVy'];
|
|
12
|
+
const outsideX = el.dataset['outsideVx'];
|
|
13
|
+
const parentRect = (_a = el === null || el === void 0 ? void 0 : el.parentElement) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
14
|
+
if (parentRect) {
|
|
15
|
+
if (outsideY) {
|
|
16
|
+
const position = el.dataset['outsideVy'];
|
|
17
|
+
if (position === 'top') {
|
|
18
|
+
outTop = parentRect.top - (bottom - parentRect.bottom) < 0;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
outBottom = parentRect.bottom + (parentRect.top - top) > innerHeight;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (outsideX) {
|
|
25
|
+
const position = el.dataset['outsideVx'];
|
|
26
|
+
if (position === 'left') {
|
|
27
|
+
outLeft = parentRect.left - (right - parentRect.right) < 0;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
outRight = parentRect.right + (parentRect.left - left) > innerWidth;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
outTop,
|
|
36
|
+
outBottom,
|
|
37
|
+
outLeft,
|
|
38
|
+
outRight
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export const handleDataOutside = (el) => {
|
|
42
|
+
const { outTop, outBottom, outLeft, outRight } = isInView(el);
|
|
43
|
+
let dataOutsidePair = {};
|
|
44
|
+
if (outTop || outBottom) {
|
|
45
|
+
dataOutsidePair = {
|
|
46
|
+
vy: outTop ? 'top' : 'bottom'
|
|
47
|
+
};
|
|
48
|
+
el.dataset['outsideVy'] = dataOutsidePair.vy;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
delete el.dataset['outsideVy'];
|
|
52
|
+
}
|
|
53
|
+
if (outLeft || outRight) {
|
|
54
|
+
dataOutsidePair = Object.assign(Object.assign({}, dataOutsidePair), { vx: outRight ? 'right' : 'left' });
|
|
55
|
+
el.dataset['outsideVx'] = dataOutsidePair.vx;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
delete el.dataset['outsideVx'];
|
|
59
|
+
}
|
|
60
|
+
return dataOutsidePair;
|
|
61
|
+
};
|
|
62
|
+
export const handleFixedDropdown = (element, parent, placement) => {
|
|
63
|
+
// We skip this if we are in mobile it's already fixed
|
|
64
|
+
if (getComputedStyle(element).zIndex === '9999')
|
|
65
|
+
return;
|
|
66
|
+
const { top, bottom, childHeight, childWidth, width, right, left, correctedPlacement } = getFloatingProps(element, parent, placement);
|
|
67
|
+
const fullWidth = element.dataset['width'] === 'full';
|
|
68
|
+
if (fullWidth) {
|
|
69
|
+
element.style.inlineSize = `${width}px`;
|
|
70
|
+
}
|
|
71
|
+
if (correctedPlacement === 'top' || correctedPlacement === 'bottom' || correctedPlacement === 'top-start' || correctedPlacement === 'bottom-start') {
|
|
72
|
+
element.style.insetInlineStart = `${left}px`;
|
|
73
|
+
}
|
|
74
|
+
else if (correctedPlacement === 'top-end' || correctedPlacement === 'bottom-end') {
|
|
75
|
+
element.style.insetInlineStart = `${right - childWidth}px`;
|
|
76
|
+
}
|
|
77
|
+
if (correctedPlacement === null || correctedPlacement === void 0 ? void 0 : correctedPlacement.startsWith('top')) {
|
|
78
|
+
element.style.insetBlockStart = `${top - childHeight}px`;
|
|
79
|
+
}
|
|
80
|
+
else if (correctedPlacement === null || correctedPlacement === void 0 ? void 0 : correctedPlacement.startsWith('bottom')) {
|
|
81
|
+
element.style.insetBlockStart = `${bottom}px`;
|
|
82
|
+
}
|
|
83
|
+
element.style.position = 'fixed';
|
|
84
|
+
};
|
|
85
|
+
const getFloatingProps = (element, parent, placement) => {
|
|
86
|
+
const childRect = element.getBoundingClientRect();
|
|
87
|
+
const { top, height, bottom, right, left, width } = parent.getBoundingClientRect();
|
|
88
|
+
const { innerHeight, innerWidth } = window;
|
|
89
|
+
let childHeight = childRect.height;
|
|
90
|
+
let childWidth = childRect.width;
|
|
91
|
+
if (placement === 'bottom' || placement === 'top') {
|
|
92
|
+
childWidth = childWidth / 2;
|
|
93
|
+
}
|
|
94
|
+
if (placement === 'left' || placement === 'right') {
|
|
95
|
+
childHeight = childHeight / 2;
|
|
96
|
+
}
|
|
97
|
+
const outsideBottom = bottom + childHeight > innerHeight;
|
|
98
|
+
const outsideTop = top - childHeight < 0;
|
|
99
|
+
const outsideLeft = left - childWidth < 0;
|
|
100
|
+
const outsideRight = right + childWidth > innerWidth;
|
|
101
|
+
let correctedPlacement = placement;
|
|
102
|
+
if (placement.startsWith('bottom')) {
|
|
103
|
+
if (outsideBottom) {
|
|
104
|
+
correctedPlacement = placement === null || placement === void 0 ? void 0 : placement.replace('bottom', 'top');
|
|
105
|
+
if (outsideLeft && outsideRight) {
|
|
106
|
+
correctedPlacement = 'top';
|
|
107
|
+
}
|
|
108
|
+
else if (outsideLeft) {
|
|
109
|
+
correctedPlacement = 'top-start';
|
|
110
|
+
}
|
|
111
|
+
else if (outsideRight) {
|
|
112
|
+
correctedPlacement = 'top-end';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
if (outsideLeft && outsideRight) {
|
|
117
|
+
correctedPlacement = 'bottom';
|
|
118
|
+
}
|
|
119
|
+
else if (outsideLeft) {
|
|
120
|
+
correctedPlacement = 'bottom-start';
|
|
121
|
+
}
|
|
122
|
+
else if (outsideRight) {
|
|
123
|
+
correctedPlacement = 'bottom-end';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (placement.startsWith('top')) {
|
|
128
|
+
if (outsideTop) {
|
|
129
|
+
correctedPlacement = placement === null || placement === void 0 ? void 0 : placement.replace('top', 'bottom');
|
|
130
|
+
if (outsideLeft && outsideRight) {
|
|
131
|
+
correctedPlacement = 'bottom';
|
|
132
|
+
}
|
|
133
|
+
else if (outsideLeft) {
|
|
134
|
+
correctedPlacement = 'bottom-start';
|
|
135
|
+
}
|
|
136
|
+
else if (outsideRight) {
|
|
137
|
+
correctedPlacement = 'bottom-end';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (outsideLeft && outsideRight) {
|
|
142
|
+
correctedPlacement = 'top';
|
|
143
|
+
}
|
|
144
|
+
else if (outsideLeft) {
|
|
145
|
+
correctedPlacement = 'top-start';
|
|
146
|
+
}
|
|
147
|
+
else if (outsideRight) {
|
|
148
|
+
correctedPlacement = 'top-end';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (placement.startsWith('left')) {
|
|
153
|
+
if (outsideLeft) {
|
|
154
|
+
correctedPlacement = placement === null || placement === void 0 ? void 0 : placement.replace('left', 'right');
|
|
155
|
+
if (outsideBottom && outsideTop) {
|
|
156
|
+
correctedPlacement = 'right';
|
|
157
|
+
}
|
|
158
|
+
else if (outsideBottom) {
|
|
159
|
+
correctedPlacement = 'right-end';
|
|
160
|
+
}
|
|
161
|
+
else if (outsideTop) {
|
|
162
|
+
correctedPlacement = 'right-start';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
if (outsideBottom && outsideTop) {
|
|
167
|
+
correctedPlacement = 'left';
|
|
168
|
+
}
|
|
169
|
+
else if (outsideBottom) {
|
|
170
|
+
correctedPlacement = 'left-end';
|
|
171
|
+
}
|
|
172
|
+
else if (outsideTop) {
|
|
173
|
+
correctedPlacement = 'left-start';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (correctedPlacement.startsWith('right')) {
|
|
178
|
+
if (outsideRight) {
|
|
179
|
+
correctedPlacement = placement === null || placement === void 0 ? void 0 : placement.replace('right', 'left');
|
|
180
|
+
if (outsideBottom && outsideTop) {
|
|
181
|
+
correctedPlacement = 'left';
|
|
182
|
+
}
|
|
183
|
+
else if (outsideBottom) {
|
|
184
|
+
correctedPlacement = 'left-end';
|
|
185
|
+
}
|
|
186
|
+
else if (outsideTop) {
|
|
187
|
+
correctedPlacement = 'left-start';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
if (outsideBottom && outsideTop) {
|
|
192
|
+
correctedPlacement = 'right';
|
|
193
|
+
}
|
|
194
|
+
else if (outsideBottom) {
|
|
195
|
+
correctedPlacement = 'right-end';
|
|
196
|
+
}
|
|
197
|
+
else if (outsideTop) {
|
|
198
|
+
correctedPlacement = 'right-start';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
top,
|
|
204
|
+
bottom,
|
|
205
|
+
right,
|
|
206
|
+
height,
|
|
207
|
+
width,
|
|
208
|
+
left,
|
|
209
|
+
childHeight: childRect.height,
|
|
210
|
+
childWidth: childRect.width,
|
|
211
|
+
correctedPlacement,
|
|
212
|
+
innerWidth,
|
|
213
|
+
innerHeight
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
export const handleFixedPopover = (element, parent, placement) => {
|
|
217
|
+
var _a;
|
|
218
|
+
const distance = (_a = getComputedStyle(element).getPropertyValue('--db-popover-distance')) !== null && _a !== void 0 ? _a : '0px';
|
|
219
|
+
const { top, height, width, childHeight, childWidth, right, left, bottom, correctedPlacement, innerWidth, innerHeight } = getFloatingProps(element, parent, placement);
|
|
220
|
+
// Tooltip arrow position
|
|
221
|
+
if (childWidth > width && (correctedPlacement.startsWith('bottom') || correctedPlacement.startsWith('top'))) {
|
|
222
|
+
const diff = width / 2 / childWidth * 100;
|
|
223
|
+
if (correctedPlacement.endsWith('start')) {
|
|
224
|
+
element.style.setProperty('--db-tooltip-arrow-inline-start', `${diff}%`);
|
|
225
|
+
}
|
|
226
|
+
else if (correctedPlacement.endsWith('end')) {
|
|
227
|
+
element.style.setProperty('--db-tooltip-arrow-inline-start', `${100 - diff}%`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (childHeight > height && (correctedPlacement.startsWith('left') || correctedPlacement.startsWith('bottom'))) {
|
|
231
|
+
const diff = height / 2 / childHeight * 100;
|
|
232
|
+
if (correctedPlacement.endsWith('start')) {
|
|
233
|
+
element.style.setProperty('--db-tooltip-arrow-block-start', `${diff}%`);
|
|
234
|
+
}
|
|
235
|
+
else if (correctedPlacement.endsWith('end')) {
|
|
236
|
+
element.style.setProperty('--db-tooltip-arrow-block-start', `${100 - diff}%`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Popover position
|
|
240
|
+
if (correctedPlacement === 'right' || correctedPlacement === 'left') {
|
|
241
|
+
// center horizontally
|
|
242
|
+
element.style.insetBlockStart = `${top + height / 2}px`;
|
|
243
|
+
}
|
|
244
|
+
else if (correctedPlacement === 'right-start' || correctedPlacement === 'left-start') {
|
|
245
|
+
const end = top + childHeight;
|
|
246
|
+
element.style.insetBlockStart = `${top}px`;
|
|
247
|
+
element.style.insetBlockEnd = `${end > innerHeight ? innerHeight : end}px`;
|
|
248
|
+
}
|
|
249
|
+
else if (correctedPlacement === 'right-end' || correctedPlacement === 'left-end') {
|
|
250
|
+
const start = bottom - childHeight;
|
|
251
|
+
element.style.insetBlockStart = `${start < 0 ? 0 : start}px`;
|
|
252
|
+
element.style.insetBlockEnd = `${bottom}px`;
|
|
253
|
+
}
|
|
254
|
+
else if (correctedPlacement === 'top' || correctedPlacement === 'bottom') {
|
|
255
|
+
// center vertically
|
|
256
|
+
element.style.insetInlineStart = `${left + width / 2}px`;
|
|
257
|
+
}
|
|
258
|
+
else if (correctedPlacement === 'top-start' || correctedPlacement === 'bottom-start') {
|
|
259
|
+
const end = left + childWidth;
|
|
260
|
+
element.style.insetInlineStart = `${left}px`;
|
|
261
|
+
element.style.insetInlineEnd = `${end > innerWidth ? innerWidth : end}px`;
|
|
262
|
+
}
|
|
263
|
+
else if (correctedPlacement === 'top-end' || correctedPlacement === 'bottom-end') {
|
|
264
|
+
const start = left - childWidth;
|
|
265
|
+
element.style.insetInlineStart = `${right - childWidth}px`;
|
|
266
|
+
element.style.insetInlineEnd = `${start < 0 ? 0 : start}px`;
|
|
267
|
+
}
|
|
268
|
+
if (correctedPlacement === null || correctedPlacement === void 0 ? void 0 : correctedPlacement.startsWith('right')) {
|
|
269
|
+
const end = right + childWidth;
|
|
270
|
+
element.style.insetInlineStart = `calc(${right}px + ${distance})`;
|
|
271
|
+
element.style.insetInlineEnd = `calc(${end > innerWidth ? innerWidth : end}px + ${distance})`;
|
|
272
|
+
}
|
|
273
|
+
else if (correctedPlacement === null || correctedPlacement === void 0 ? void 0 : correctedPlacement.startsWith('left')) {
|
|
274
|
+
const start = left - childWidth;
|
|
275
|
+
element.style.insetInlineStart = `calc(${start < 0 ? 0 : start}px - ${distance})`;
|
|
276
|
+
element.style.insetInlineEnd = `calc(${right}px - ${distance})`;
|
|
277
|
+
}
|
|
278
|
+
else if (correctedPlacement === null || correctedPlacement === void 0 ? void 0 : correctedPlacement.startsWith('top')) {
|
|
279
|
+
const start = top - childHeight;
|
|
280
|
+
element.style.insetBlockStart = `calc(${start < 0 ? 0 : start}px - ${distance})`;
|
|
281
|
+
element.style.insetBlockEnd = `calc(${bottom}px - ${distance})`;
|
|
282
|
+
}
|
|
283
|
+
else if (correctedPlacement === null || correctedPlacement === void 0 ? void 0 : correctedPlacement.startsWith('bottom')) {
|
|
284
|
+
const end = bottom + childHeight;
|
|
285
|
+
element.style.insetBlockStart = `calc(${bottom}px + ${distance})`;
|
|
286
|
+
element.style.insetBlockEnd = `calc(${end > innerHeight ? innerHeight : end}px + ${distance})`;
|
|
287
|
+
}
|
|
288
|
+
element.style.position = 'fixed';
|
|
289
|
+
element.setAttribute('data-corrected-placement', correctedPlacement);
|
|
290
|
+
};
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -7,19 +7,6 @@ export type ClassNameArg = string | {
|
|
|
7
7
|
[key: string]: boolean | undefined;
|
|
8
8
|
} | undefined;
|
|
9
9
|
export declare const cls: (...args: ClassNameArg[]) => string;
|
|
10
|
-
export declare const visibleInVX: (el: Element) => boolean;
|
|
11
|
-
export declare const visibleInVY: (el: Element) => boolean;
|
|
12
|
-
export declare const isInView: (el: Element) => {
|
|
13
|
-
outTop: boolean;
|
|
14
|
-
outBottom: boolean;
|
|
15
|
-
outLeft: boolean;
|
|
16
|
-
outRight: boolean;
|
|
17
|
-
};
|
|
18
|
-
export interface DBDataOutsidePair {
|
|
19
|
-
vx?: 'left' | 'right';
|
|
20
|
-
vy?: 'top' | 'bottom';
|
|
21
|
-
}
|
|
22
|
-
export declare const handleDataOutside: (el: Element) => DBDataOutsidePair;
|
|
23
10
|
export declare const isArrayOfStrings: (value: unknown) => value is string[];
|
|
24
11
|
export declare const hasVoiceOver: () => boolean;
|
|
25
12
|
export declare const delay: (fn: () => void, ms: number) => Promise<unknown>;
|
package/dist/utils/index.js
CHANGED
|
@@ -37,76 +37,6 @@ export const cls = (...args) => {
|
|
|
37
37
|
}
|
|
38
38
|
return result.trim();
|
|
39
39
|
};
|
|
40
|
-
export const visibleInVX = (el) => {
|
|
41
|
-
const { left, right } = el.getBoundingClientRect();
|
|
42
|
-
const { innerWidth } = window;
|
|
43
|
-
return left >= 0 && right <= innerWidth;
|
|
44
|
-
};
|
|
45
|
-
export const visibleInVY = (el) => {
|
|
46
|
-
const { top, bottom } = el.getBoundingClientRect();
|
|
47
|
-
const { innerHeight } = window;
|
|
48
|
-
return top >= 0 && bottom <= innerHeight;
|
|
49
|
-
};
|
|
50
|
-
export const isInView = (el) => {
|
|
51
|
-
var _a;
|
|
52
|
-
const { top, bottom, left, right } = el.getBoundingClientRect();
|
|
53
|
-
const { innerHeight, innerWidth } = window;
|
|
54
|
-
let outTop = top < 0;
|
|
55
|
-
let outBottom = bottom > innerHeight;
|
|
56
|
-
let outLeft = left < 0;
|
|
57
|
-
let outRight = right > innerWidth;
|
|
58
|
-
// We need to check if it was already outside
|
|
59
|
-
const outsideY = el.hasAttribute('data-outside-vy');
|
|
60
|
-
const outsideX = el.hasAttribute('data-outside-vx');
|
|
61
|
-
const parentRect = (_a = el === null || el === void 0 ? void 0 : el.parentElement) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
62
|
-
if (parentRect) {
|
|
63
|
-
if (outsideY) {
|
|
64
|
-
const position = el.getAttribute('data-outside-vy');
|
|
65
|
-
if (position === 'top') {
|
|
66
|
-
outTop = parentRect.top - (bottom - parentRect.bottom) < 0;
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
outBottom = parentRect.bottom + (parentRect.top - top) > innerHeight;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (outsideX) {
|
|
73
|
-
const position = el.getAttribute('data-outside-vx');
|
|
74
|
-
if (position === 'left') {
|
|
75
|
-
outLeft = parentRect.left - (right - parentRect.right) < 0;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
outRight = parentRect.right + (parentRect.left - left) > innerWidth;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
outTop,
|
|
84
|
-
outBottom,
|
|
85
|
-
outLeft,
|
|
86
|
-
outRight
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
export const handleDataOutside = (el) => {
|
|
90
|
-
const { outTop, outBottom, outLeft, outRight } = isInView(el);
|
|
91
|
-
let dataOutsidePair = {};
|
|
92
|
-
if (outTop || outBottom) {
|
|
93
|
-
dataOutsidePair = {
|
|
94
|
-
vy: outTop ? 'top' : 'bottom'
|
|
95
|
-
};
|
|
96
|
-
el.setAttribute('data-outside-vy', dataOutsidePair.vy);
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
el.removeAttribute('data-outside-vy');
|
|
100
|
-
}
|
|
101
|
-
if (outLeft || outRight) {
|
|
102
|
-
dataOutsidePair = Object.assign(Object.assign({}, dataOutsidePair), { vx: outRight ? 'right' : 'left' });
|
|
103
|
-
el.setAttribute('data-outside-vx', dataOutsidePair.vx);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
el.removeAttribute('data-outside-vx');
|
|
107
|
-
}
|
|
108
|
-
return dataOutsidePair;
|
|
109
|
-
};
|
|
110
40
|
export const isArrayOfStrings = (value) => Array.isArray(value) && value.every(item => typeof item === 'string');
|
|
111
41
|
const appleOs = ['Mac', 'iPhone', 'iPad', 'iPod'];
|
|
112
42
|
export const hasVoiceOver = () => typeof window !== 'undefined' && appleOs.some(os => window.navigator.userAgent.includes(os));
|
|
@@ -15,7 +15,7 @@ export declare class NavigationItemSafeTriangle {
|
|
|
15
15
|
private initialized;
|
|
16
16
|
private mouseX;
|
|
17
17
|
private mouseY;
|
|
18
|
-
constructor(element: HTMLElement | null, subNavigation:
|
|
18
|
+
constructor(element: HTMLElement | null, subNavigation: HTMLElement | null);
|
|
19
19
|
private init;
|
|
20
20
|
enableFollow(): void;
|
|
21
21
|
disableFollow(): void;
|
package/dist/utils/navigation.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@db-ux/react-core-components",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10-popover-d7e8b9a",
|
|
4
4
|
"description": "React components for @db-ux/core-components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"sideEffects": false,
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@db-ux/core-components": "2.0.
|
|
42
|
-
"@db-ux/core-foundations": "2.0.
|
|
41
|
+
"@db-ux/core-components": "2.0.10-popover-d7e8b9a",
|
|
42
|
+
"@db-ux/core-foundations": "2.0.10-popover-d7e8b9a"
|
|
43
43
|
}
|
|
44
44
|
}
|