@db-ux/react-core-components 2.1.2 → 2.2.1
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 +32 -9
- package/dist/components/custom-select/model.d.ts +3 -3
- package/dist/components/input/input.js +1 -1
- package/dist/components/popover/model.d.ts +0 -1
- package/dist/components/popover/popover.js +60 -9
- package/dist/components/select/select.js +5 -5
- package/dist/components/textarea/model.d.ts +4 -0
- package/dist/components/textarea/textarea.js +3 -3
- package/dist/components/tooltip/model.d.ts +5 -3
- package/dist/components/tooltip/tooltip.js +60 -11
- package/dist/shared/model.d.ts +18 -3
- package/dist/shared/model.js +1 -0
- 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 +4 -13
- package/dist/utils/index.js +5 -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,
|
|
5
|
+
import { cls, delay, getBoolean, getBooleanAsString, getHideProp, getOptionKey, 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
|
const [_searchValue, set_searchValue] = useState(() => undefined);
|
|
49
60
|
function hasValidState() {
|
|
50
61
|
var _a;
|
|
@@ -93,7 +104,9 @@ function DBCustomSelectFn(props, component) {
|
|
|
93
104
|
}
|
|
94
105
|
if (event.target.open) {
|
|
95
106
|
set_documentClickListenerCallbackId(new DocumentClickListener().addCallback((event) => handleDocumentClose(event)));
|
|
107
|
+
set_documentScrollListenerCallbackId(new DocumentScrollListener().addCallback((event) => handleDocumentScroll(event)));
|
|
96
108
|
handleAutoPlacement();
|
|
109
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.observe(detailsRef.current);
|
|
97
110
|
if (!event.target.dataset.test) {
|
|
98
111
|
// We need this workaround for snapshot testing
|
|
99
112
|
handleOpenByKeyboardFocus();
|
|
@@ -103,6 +116,10 @@ function DBCustomSelectFn(props, component) {
|
|
|
103
116
|
if (_documentClickListenerCallbackId) {
|
|
104
117
|
new DocumentClickListener().removeCallback(_documentClickListenerCallbackId);
|
|
105
118
|
}
|
|
119
|
+
if (_documentScrollListenerCallbackId) {
|
|
120
|
+
new DocumentScrollListener().removeCallback(_documentScrollListenerCallbackId);
|
|
121
|
+
}
|
|
122
|
+
_observer === null || _observer === void 0 ? void 0 : _observer.unobserve(detailsRef.current);
|
|
106
123
|
}
|
|
107
124
|
}
|
|
108
125
|
function getNativeSelectValue() {
|
|
@@ -136,10 +153,6 @@ function DBCustomSelectFn(props, component) {
|
|
|
136
153
|
}
|
|
137
154
|
return false;
|
|
138
155
|
}
|
|
139
|
-
function getOptionKey(option) {
|
|
140
|
-
var _a, _b;
|
|
141
|
-
return ((_b = (_a = option.id) !== null && _a !== void 0 ? _a : option.value) !== null && _b !== void 0 ? _b : uuid()).toString();
|
|
142
|
-
}
|
|
143
156
|
function getTagRemoveLabel(index) {
|
|
144
157
|
if (props.removeTagsTexts && props.removeTagsTexts.length > index) {
|
|
145
158
|
return props.removeTagsTexts.at(index);
|
|
@@ -157,8 +170,10 @@ function DBCustomSelectFn(props, component) {
|
|
|
157
170
|
if (detailsRef.current) {
|
|
158
171
|
const dropdown = detailsRef.current.querySelector("article");
|
|
159
172
|
if (dropdown) {
|
|
173
|
+
// This is a workaround for Angular
|
|
160
174
|
delay(() => {
|
|
161
|
-
|
|
175
|
+
var _a;
|
|
176
|
+
handleFixedDropdown(dropdown, detailsRef.current, (_a = props.placement) !== null && _a !== void 0 ? _a : "bottom");
|
|
162
177
|
}, 1);
|
|
163
178
|
}
|
|
164
179
|
}
|
|
@@ -414,6 +429,14 @@ function DBCustomSelectFn(props, component) {
|
|
|
414
429
|
set_selectedLabelsId(mId + "-selected-labels");
|
|
415
430
|
set_infoTextId(mId + "-info");
|
|
416
431
|
set_invalidMessage(props.invalidMessage || DEFAULT_INVALID_MESSAGE);
|
|
432
|
+
set_observer(new IntersectionObserver((payload) => {
|
|
433
|
+
if (detailsRef.current) {
|
|
434
|
+
const entry = payload.find(({ target }) => target === detailsRef.current);
|
|
435
|
+
if (entry && !entry.isIntersecting && detailsRef.current.open) {
|
|
436
|
+
detailsRef.current.open = false;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}));
|
|
417
440
|
}, []);
|
|
418
441
|
useEffect(() => {
|
|
419
442
|
if (detailsRef.current) {
|
|
@@ -566,13 +589,13 @@ function DBCustomSelectFn(props, component) {
|
|
|
566
589
|
? "above"
|
|
567
590
|
: props.variant, "data-required": getBooleanAsString(props.required), "data-placement": props.placement, "data-selected-type": props.multiple ? props.selectedType : "text", "data-hide-label": getHideProp(props.showLabel), "data-icon": props.icon, "data-hide-icon": getHideProp(props.showIcon) }),
|
|
568
591
|
React.createElement("label", { id: _labelId }, (_a = props.label) !== null && _a !== void 0 ? _a : DEFAULT_LABEL,
|
|
569
|
-
React.createElement("select", { role: "none", hidden: true, id: _selectId, tabIndex: -1, ref: selectRef, form: props.form, name: props.name, multiple: getBoolean(props.multiple, "multiple"), disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), onChange: (event) => satisfyReact(event) }, ((_b = props.options) === null || _b === void 0 ? void 0 : _b.length) ? (React.createElement(React.Fragment, null, (_c = props.options) === null || _c === void 0 ? void 0 : _c.map((option) => (React.createElement("option", { disabled: option.disabled, value: option.value, key: "native-select-option-"
|
|
592
|
+
React.createElement("select", { role: "none", hidden: true, id: _selectId, tabIndex: -1, ref: selectRef, form: props.form, name: props.name, multiple: getBoolean(props.multiple, "multiple"), disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), onChange: (event) => satisfyReact(event) }, ((_b = props.options) === null || _b === void 0 ? void 0 : _b.length) ? (React.createElement(React.Fragment, null, (_c = props.options) === null || _c === void 0 ? void 0 : _c.map((option) => (React.createElement("option", { disabled: option.disabled, value: option.value, key: getOptionKey(option, "native-select-option-") }, getOptionLabel(option)))))) : null)),
|
|
570
593
|
React.createElement("details", { ref: detailsRef, open: props.open, onToggle: (event) => handleDropdownToggle(event), onKeyDown: (event) => handleKeyboardPress(event) },
|
|
571
594
|
props.children,
|
|
572
595
|
props.options ? (React.createElement(React.Fragment, null,
|
|
573
596
|
React.createElement("summary", { className: "db-custom-select-form-field", id: _summaryId, "aria-disabled": getBooleanAsString(props.disabled), "aria-labelledby": _labelId },
|
|
574
597
|
(_selectedLabels === null || _selectedLabels === void 0 ? void 0 : _selectedLabels.length) ? (React.createElement("span", { "data-visually-hidden": getBooleanAsString(props.selectedType === "tag"), id: _selectedLabelsId }, _selectedLabels)) : null,
|
|
575
|
-
props.selectedType === "tag" ? (React.createElement("div", null, _selectedOptions === null || _selectedOptions === void 0 ? void 0 : _selectedOptions.map((option, index) => (React.createElement(DBTag, { emphasis: "strong", behavior: "removable", removeButton: getTagRemoveLabel(index), onRemove: (event) => handleTagRemove(option, event), key: "tag-"
|
|
598
|
+
props.selectedType === "tag" ? (React.createElement("div", null, _selectedOptions === null || _selectedOptions === void 0 ? void 0 : _selectedOptions.map((option, index) => (React.createElement(DBTag, { emphasis: "strong", behavior: "removable", removeButton: getTagRemoveLabel(index), onRemove: (event) => handleTagRemove(option, event), key: getOptionKey(option, "tag-") }, getOptionLabel(option)))))) : null),
|
|
576
599
|
React.createElement(DBCustomSelectDropdown, { width: props.dropdownWidth },
|
|
577
600
|
searchEnabled ? (React.createElement("div", null,
|
|
578
601
|
React.createElement(DBInput, { type: "search", ref: searchInputRef, name: _id, form: _id, showLabel: false, value: _searchValue, label: (_d = props.searchLabel) !== null && _d !== void 0 ? _d : DEFAULT_LABEL, placeholder: (_e = props.searchPlaceholder) !== null && _e !== void 0 ? _e : props.searchLabel, ariaDescribedBy: _hasNoOptions || props.showLoading
|
|
@@ -585,7 +608,7 @@ function DBCustomSelectFn(props, component) {
|
|
|
585
608
|
React.createElement("label", null,
|
|
586
609
|
React.createElement("input", { type: "checkbox", value: "select-all", ref: selectAllRef, form: _id, checked: selectAllChecked, onChange: (event) => handleSelectAll(event) }),
|
|
587
610
|
getSelectAllLabel())))) : null,
|
|
588
|
-
React.createElement(DBCustomSelectList, { multiple: getBoolean(props.multiple, "multiple"), label: (_h = (_g = props.ariaListLabel) !== null && _g !== void 0 ? _g : props.label) !== null && _h !== void 0 ? _h : DEFAULT_LABEL }, _options === null || _options === void 0 ? void 0 : _options.map((option) => (React.createElement(DBCustomSelectListItem, { type: props.multiple ? "checkbox" : "radio", showDivider: option.showDivider, icon: option.icon, isGroupTitle: option.isGroupTitle, groupTitle: getOptionLabel(option), name: _id, checked: getOptionChecked(option.value), disabled: option.disabled, value: option.value, onChange: (event) => handleSelect(option.value), key: "custom-select-list-item-"
|
|
611
|
+
React.createElement(DBCustomSelectList, { multiple: getBoolean(props.multiple, "multiple"), label: (_h = (_g = props.ariaListLabel) !== null && _g !== void 0 ? _g : props.label) !== null && _h !== void 0 ? _h : DEFAULT_LABEL }, _options === null || _options === void 0 ? void 0 : _options.map((option) => (React.createElement(DBCustomSelectListItem, { type: props.multiple ? "checkbox" : "radio", showDivider: option.showDivider, icon: option.icon, isGroupTitle: option.isGroupTitle, groupTitle: getOptionLabel(option), name: _id, checked: getOptionChecked(option.value), disabled: option.disabled, value: option.value, onChange: (event) => handleSelect(option.value), key: getOptionKey(option, "custom-select-list-item-") }, !option.isGroupTitle ? (React.createElement(React.Fragment, null, getOptionLabel(option))) : null))))))),
|
|
589
612
|
React.createElement("div", null,
|
|
590
613
|
React.createElement(DBButton, { variant: "ghost", width: "full", icon: "cross", size: "small", name: _id, form: _id, onClick: (event) => handleClose("close") }, (_j = props.mobileCloseButtonText) !== null && _j !== void 0 ? _j : DEFAULT_CLOSE_BUTTON))))) : null),
|
|
591
614
|
((_k = props.showClearSelection) !== null && _k !== void 0 ? _k : true) && (_values === null || _values === void 0 ? void 0 : _values.length) ? (React.createElement(DBButton, { icon: "cross", variant: "ghost", size: "small", noText: true, name: _id, form: _id, onClick: (event) => handleClearAll(event) },
|
|
@@ -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';
|
|
@@ -193,7 +193,6 @@ export type DBCustomSelectDefaultState = {
|
|
|
193
193
|
getNativeSelectValue: () => string;
|
|
194
194
|
getOptionLabel: (option: CustomSelectOptionType) => string;
|
|
195
195
|
getOptionChecked: (value?: string) => boolean;
|
|
196
|
-
getOptionKey: (option: CustomSelectOptionType) => string;
|
|
197
196
|
getTagRemoveLabel: (index: number) => string;
|
|
198
197
|
selectAllEnabled: boolean;
|
|
199
198
|
searchEnabled: boolean;
|
|
@@ -215,5 +214,6 @@ export type DBCustomSelectDefaultState = {
|
|
|
215
214
|
getSelectAllLabel: () => string;
|
|
216
215
|
selectAllChecked: boolean;
|
|
217
216
|
selectAllIndeterminate: boolean;
|
|
217
|
+
handleAutoPlacement: () => void;
|
|
218
218
|
};
|
|
219
|
-
export type DBCustomSelectState = DBCustomSelectDefaultState & GlobalState & FormState & FromValidState & CloseEventState &
|
|
219
|
+
export type DBCustomSelectState = DBCustomSelectDefaultState & GlobalState & FormState & FromValidState & CloseEventState & DocumentScrollState;
|
|
@@ -115,7 +115,7 @@ function DBInputFn(props, component) {
|
|
|
115
115
|
}, [props.value]);
|
|
116
116
|
return (React.createElement("div", Object.assign({}, 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-input", props.className), "data-variant": props.variant, "data-hide-label": getHideProp(props.showLabel), "data-hide-icon": getHideProp(props.showIcon), "data-icon": props.icon, "data-icon-after": props.iconAfter, "data-hide-icon-after": getHideProp(props.showIcon) }),
|
|
117
117
|
React.createElement("label", { htmlFor: _id }, (_a = props.label) !== null && _a !== void 0 ? _a : DEFAULT_LABEL),
|
|
118
|
-
React.createElement("input", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, 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: _id, name: props.name, type: props.type || "text", placeholder: (_b = props.placeholder) !== null && _b !== void 0 ? _b : DEFAULT_PLACEHOLDER, disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), step: getNumber(props.step), value: props.value, maxLength: getNumber(props.maxLength, props.maxlength), minLength: getNumber(props.minLength, props.minlength), max: getInputValue(props.max, props.type), min: getInputValue(props.min, props.type), readOnly: getBoolean(props.readOnly, "readOnly") ||
|
|
118
|
+
React.createElement("input", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, "data-field-sizing": props.fieldSizing, 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: _id, name: props.name, type: props.type || "text", placeholder: (_b = props.placeholder) !== null && _b !== void 0 ? _b : DEFAULT_PLACEHOLDER, disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), step: getNumber(props.step), value: props.value, maxLength: getNumber(props.maxLength, props.maxlength), minLength: getNumber(props.minLength, props.minlength), max: getInputValue(props.max, props.type), min: getInputValue(props.min, props.type), readOnly: getBoolean(props.readOnly, "readOnly") ||
|
|
119
119
|
getBoolean(props.readonly, "readonly"), form: props.form, pattern: props.pattern, size: props.size, autoComplete: props.autocomplete, autoFocus: getBoolean(props.autofocus, "autofocus"), onInput: (event) => handleInput(event), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event), list: props.dataList && _dataListId, "aria-describedby": (_c = props.ariaDescribedBy) !== null && _c !== void 0 ? _c : _descByIds })),
|
|
120
120
|
props.dataList ? (React.createElement("datalist", { id: _dataListId }, (_d = getDataList()) === null || _d === void 0 ? void 0 : _d.map((option) => (React.createElement("option", { key: _dataListId + "-option-" + option.value, value: option.value }, option.label))))) : null,
|
|
121
121
|
props.children,
|
|
@@ -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
|
}
|
|
@@ -2,11 +2,11 @@
|
|
|
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, getHideProp, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
|
|
5
|
+
import { cls, delay, getBoolean, getHideProp, getOptionKey, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
|
|
6
6
|
import { DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_LABEL, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_PLACEHOLDER_ID_SUFFIX, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
|
|
7
7
|
import DBInfotext from "../infotext/infotext";
|
|
8
8
|
function DBSelectFn(props, component) {
|
|
9
|
-
var _a, _b, _c, _d;
|
|
9
|
+
var _a, _b, _c, _d, _e;
|
|
10
10
|
const _ref = component || useRef(component);
|
|
11
11
|
const [_id, set_id] = useState(() => undefined);
|
|
12
12
|
const [_messageId, set_messageId] = useState(() => undefined);
|
|
@@ -123,11 +123,11 @@ function DBSelectFn(props, component) {
|
|
|
123
123
|
React.createElement("label", { htmlFor: _id }, (_a = props.label) !== null && _a !== void 0 ? _a : DEFAULT_LABEL),
|
|
124
124
|
React.createElement("select", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, 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"]), { required: getBoolean(props.required, "required"), disabled: getBoolean(props.disabled, "disabled"), id: _id, name: props.name, size: props.size, value: props.value, autoComplete: props.autocomplete, multiple: props.multiple, onInput: (event) => handleInput(event), onClick: (event) => handleClick(event), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event), "aria-describedby": (_b = props.ariaDescribedBy) !== null && _b !== void 0 ? _b : _descByIds }),
|
|
125
125
|
React.createElement("option", { hidden: true }),
|
|
126
|
-
props.options ? (React.createElement(React.Fragment, null, (
|
|
126
|
+
((_c = props.options) === null || _c === void 0 ? void 0 : _c.length) ? (React.createElement(React.Fragment, null, (_d = props.options) === null || _d === void 0 ? void 0 : _d.map((option) => {
|
|
127
127
|
var _a;
|
|
128
|
-
return option.options ? (React.createElement("optgroup", { label: getOptionLabel(option) }, (_a = option.options) === null || _a === void 0 ? void 0 : _a.map((optgroupOption) => (React.createElement("option", {
|
|
128
|
+
return option.options ? (React.createElement("optgroup", { label: getOptionLabel(option), key: getOptionKey(option, "select-optgroup-") }, (_a = option.options) === null || _a === void 0 ? void 0 : _a.map((optgroupOption) => (React.createElement("option", { value: optgroupOption.value, disabled: optgroupOption.disabled, key: getOptionKey(optgroupOption, "select-optgroup-option-") }, getOptionLabel(optgroupOption)))))) : (React.createElement("option", { value: option.value, disabled: option.disabled, key: getOptionKey(option, "select-option-") }, getOptionLabel(option)));
|
|
129
129
|
}))) : (React.createElement(React.Fragment, null, props.children))),
|
|
130
|
-
React.createElement("span", { id: _placeholderId }, (
|
|
130
|
+
React.createElement("span", { id: _placeholderId }, (_e = props.placeholder) !== null && _e !== void 0 ? _e : props.label),
|
|
131
131
|
stringPropVisible(props.message, props.showMessage) ? (React.createElement(DBInfotext, { size: "small", icon: props.messageIcon, id: _messageId }, props.message)) : null,
|
|
132
132
|
hasValidState() ? (React.createElement(DBInfotext, { size: "small", semantic: "successful", id: _validMessageId }, props.validMessage || DEFAULT_VALID_MESSAGE)) : null,
|
|
133
133
|
React.createElement(DBInfotext, { size: "small", semantic: "critical", id: _invalidMessageId }, _invalidMessage),
|
|
@@ -12,6 +12,10 @@ export type DBTextareaDefaultProps = {
|
|
|
12
12
|
* In most browsers, textareas are resizable — you'll notice the drag handle in the right-hand corner, you can control it with this
|
|
13
13
|
*/
|
|
14
14
|
resize?: TextareaResizeType;
|
|
15
|
+
/**
|
|
16
|
+
* Show/Hides drag handle in the right-hand corner - default: true
|
|
17
|
+
*/
|
|
18
|
+
showResizer?: boolean | string;
|
|
15
19
|
/**
|
|
16
20
|
* The number of visible text lines for the control. If it is specified, it must be a positive integer
|
|
17
21
|
*/
|
|
@@ -6,7 +6,7 @@ import DBInfotext from "../infotext/infotext";
|
|
|
6
6
|
import { cls, delay, getBoolean, getHideProp, getNumber, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
|
|
7
7
|
import { DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_LABEL, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_PLACEHOLDER, DEFAULT_ROWS, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
|
|
8
8
|
function DBTextareaFn(props, component) {
|
|
9
|
-
var _a, _b, _c;
|
|
9
|
+
var _a, _b, _c, _d;
|
|
10
10
|
const _ref = component || useRef(component);
|
|
11
11
|
const [_id, set_id] = useState(() => undefined);
|
|
12
12
|
const [_messageId, set_messageId] = useState(() => undefined);
|
|
@@ -102,8 +102,8 @@ function DBTextareaFn(props, component) {
|
|
|
102
102
|
}, [props.value]);
|
|
103
103
|
return (React.createElement("div", Object.assign({}, 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-textarea", props.className), "data-variant": props.variant, "data-hide-label": getHideProp(props.showLabel) }),
|
|
104
104
|
React.createElement("label", { htmlFor: _id }, (_a = props.label) !== null && _a !== void 0 ? _a : DEFAULT_LABEL),
|
|
105
|
-
React.createElement("textarea", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, 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: _id, "data-resize": props.resize, disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), readOnly: getBoolean(props.readOnly, "readOnly") ||
|
|
106
|
-
getBoolean(props.readonly, "readonly"), form: props.form, maxLength: getNumber(props.maxLength, props.maxlength), minLength: getNumber(props.minLength, props.minlength), name: props.name, wrap: props.wrap, spellCheck: props.spellCheck, autoComplete: props.autocomplete, onInput: (event) => handleInput(event), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event), value: props.value, "aria-describedby": (
|
|
105
|
+
React.createElement("textarea", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, "data-field-sizing": props.fieldSizing, 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: _id, "data-resize": props.resize, "data-hide-resizer": getHideProp((_b = props.showResizer) !== null && _b !== void 0 ? _b : true), disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), readOnly: getBoolean(props.readOnly, "readOnly") ||
|
|
106
|
+
getBoolean(props.readonly, "readonly"), form: props.form, maxLength: getNumber(props.maxLength, props.maxlength), minLength: getNumber(props.minLength, props.minlength), name: props.name, wrap: props.wrap, spellCheck: props.spellCheck, autoComplete: props.autocomplete, onInput: (event) => handleInput(event), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event), value: props.value, "aria-describedby": (_c = props.ariaDescribedBy) !== null && _c !== void 0 ? _c : _descByIds, placeholder: (_d = props.placeholder) !== null && _d !== void 0 ? _d : DEFAULT_PLACEHOLDER, rows: getNumber(props.rows, DEFAULT_ROWS), cols: getNumber(props.cols) })),
|
|
107
107
|
stringPropVisible(props.message, props.showMessage) ? (React.createElement(DBInfotext, { size: "small", icon: props.messageIcon, id: _messageId }, props.message)) : null,
|
|
108
108
|
hasValidState() ? (React.createElement(DBInfotext, { size: "small", semantic: "successful", id: _validMessageId }, props.validMessage || DEFAULT_VALID_MESSAGE)) : null,
|
|
109
109
|
React.createElement(DBInfotext, { size: "small", semantic: "critical", id: _invalidMessageId }, _invalidMessage),
|
|
@@ -1,4 +1,4 @@
|
|
|
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 declare const TooltipVariantList: readonly ["description", "label"];
|
|
3
3
|
export type TooltipVariantType = (typeof TooltipVariantList)[number];
|
|
4
4
|
export type DBTooltipDefaultProps = {
|
|
@@ -14,5 +14,7 @@ export type DBTooltipDefaultProps = {
|
|
|
14
14
|
variant?: TooltipVariantType;
|
|
15
15
|
};
|
|
16
16
|
export type DBTooltipProps = DBTooltipDefaultProps & GlobalProps & EmphasisProps & PlacementProps & PopoverProps;
|
|
17
|
-
export type DBTooltipDefaultState = {
|
|
18
|
-
|
|
17
|
+
export type DBTooltipDefaultState = {
|
|
18
|
+
getParent: () => HTMLElement;
|
|
19
|
+
};
|
|
20
|
+
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,14 +65,14 @@ 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
|
if (props.variant === "label") {
|
|
@@ -39,6 +82,12 @@ function DBTooltipFn(props, component) {
|
|
|
39
82
|
parent.setAttribute("aria-describedby", _id);
|
|
40
83
|
}
|
|
41
84
|
}
|
|
85
|
+
set_observer(new IntersectionObserver((payload) => {
|
|
86
|
+
const entry = payload.find(({ target }) => target === getParent());
|
|
87
|
+
if (entry && !entry.isIntersecting) {
|
|
88
|
+
handleEscape(false);
|
|
89
|
+
}
|
|
90
|
+
}));
|
|
42
91
|
setInitialized(false);
|
|
43
92
|
}
|
|
44
93
|
}, [_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.
|
|
@@ -234,6 +231,8 @@ export type CustomFormProps = {
|
|
|
234
231
|
validation?: ValidationType;
|
|
235
232
|
};
|
|
236
233
|
export type FormProps = CustomFormProps & BaseFormProps & RequiredProps & ShowLabelProps & ValueProps;
|
|
234
|
+
export declare const FieldSizingList: readonly ["fixed", "content"];
|
|
235
|
+
export type FieldSizingType = (typeof FieldSizingList)[number];
|
|
237
236
|
export type FormTextProps = {
|
|
238
237
|
/**
|
|
239
238
|
* Maximum length (number of characters) of value
|
|
@@ -259,6 +258,11 @@ export type FormTextProps = {
|
|
|
259
258
|
* The disabled attribute can be set to keep a user from edit on the form element
|
|
260
259
|
*/
|
|
261
260
|
readonly?: boolean | string;
|
|
261
|
+
/**
|
|
262
|
+
* Adds shrinkwrap for input and textarea: https://developer.mozilla.org/en-US/docs/Web/CSS/field-sizing
|
|
263
|
+
* Note: Only supported in Chromium browsers so far
|
|
264
|
+
*/
|
|
265
|
+
fieldSizing?: FieldSizingType;
|
|
262
266
|
};
|
|
263
267
|
export type FormSizeProps = {
|
|
264
268
|
/**
|
|
@@ -493,3 +497,14 @@ export type ValueLabelType = {
|
|
|
493
497
|
value: string;
|
|
494
498
|
label?: string;
|
|
495
499
|
};
|
|
500
|
+
export type DocumentScrollState = {
|
|
501
|
+
_documentScrollListenerCallbackId?: string;
|
|
502
|
+
handleDocumentScroll: (event: any, parent?: HTMLElement) => void;
|
|
503
|
+
_observer?: IntersectionObserver;
|
|
504
|
+
};
|
|
505
|
+
export type PopoverState = {
|
|
506
|
+
handleEscape: (event: any) => void;
|
|
507
|
+
handleAutoPlacement: (parent?: HTMLElement) => void;
|
|
508
|
+
handleEnter: (parent?: HTMLElement) => void;
|
|
509
|
+
handleLeave: (event?: any) => void;
|
|
510
|
+
} & DocumentScrollState;
|
package/dist/shared/model.js
CHANGED
|
@@ -13,6 +13,7 @@ export const PopoverWidthList = ['auto', 'fixed'];
|
|
|
13
13
|
export const SizeList = ['small', 'medium'];
|
|
14
14
|
export const EmphasisList = ['weak', 'strong'];
|
|
15
15
|
export const ValidationList = ['invalid', 'valid', 'no-validation'];
|
|
16
|
+
export const FieldSizingList = ['fixed', 'content'];
|
|
16
17
|
export const LabelVariantList = ['above', 'floating'];
|
|
17
18
|
export const AutoCompleteList = ['off', 'on', 'name', 'honorific-prefix', 'given-name', 'additional-name', 'family-name', 'honorific-suffix', 'nickname', 'email', 'username', 'new-password', 'current-password', 'one-time-code', 'organization-title', 'organization', 'street-address', 'shipping', 'billing', 'address-line1', 'address-line2', 'address-line3', 'address-level4', 'address-level3', 'address-level2', 'address-level1', 'country', 'country-name', 'postal-code', 'cc-name', 'cc-given-name', 'cc-additional-name', 'cc-family-name', 'cc-number', 'cc-exp', 'cc-exp-month', 'cc-exp-year', 'cc-csc', 'cc-type', 'transaction-currency', 'transaction-amount', 'language', 'bday', 'bday-day', 'bday-month', 'bday-year', 'sex', 'tel', 'tel-country-code', 'tel-national', 'tel-area-code', 'tel-local', 'tel-extension', 'impp', 'url', 'photo', 'webauthn'];
|
|
18
19
|
export const LinkCurrentList = ['time', 'true', 'false', 'date', 'page', 'step', 'location'];
|
|
@@ -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>;
|
|
@@ -45,3 +32,7 @@ export declare const getInputValue: (value?: number | string, inputType?: string
|
|
|
45
32
|
export declare const getHideProp: (show?: boolean | string) => any;
|
|
46
33
|
export declare const stringPropVisible: (givenString?: string, showString?: boolean | string) => boolean;
|
|
47
34
|
export declare const getSearchInput: (element: HTMLElement) => HTMLInputElement | null;
|
|
35
|
+
export declare const getOptionKey: (option: {
|
|
36
|
+
id?: string;
|
|
37
|
+
value?: string | number | string[] | undefined;
|
|
38
|
+
}, prefix: string) => string;
|
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));
|
|
@@ -168,3 +98,8 @@ export const stringPropVisible = (givenString, showString) => {
|
|
|
168
98
|
}
|
|
169
99
|
};
|
|
170
100
|
export const getSearchInput = (element) => element.querySelector(`input[type="search"]`);
|
|
101
|
+
export const getOptionKey = (option, prefix) => {
|
|
102
|
+
var _a, _b;
|
|
103
|
+
const key = (_b = (_a = option.id) !== null && _a !== void 0 ? _a : option.value) !== null && _b !== void 0 ? _b : uuid();
|
|
104
|
+
return `${prefix}${key}`;
|
|
105
|
+
};
|
|
@@ -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.1
|
|
3
|
+
"version": "2.2.1",
|
|
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.1
|
|
42
|
-
"@db-ux/core-foundations": "2.1
|
|
41
|
+
"@db-ux/core-components": "2.2.1",
|
|
42
|
+
"@db-ux/core-foundations": "2.2.1"
|
|
43
43
|
}
|
|
44
44
|
}
|