@rio-cloud/rio-uikit 0.16.4-beta.25 → 0.16.4-beta.26
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/Colors.d.ts +1 -21
- package/Colors.js +1 -2
- package/Multiselect.d.ts +2 -12
- package/Multiselect.js +2 -2
- package/Select.d.ts +2 -5
- package/Select.js +2 -2
- package/components/applicationLayout/ApplicationLayoutBody.d.ts +1 -1
- package/components/applicationLayout/ApplicationLayoutBody.js +14 -6
- package/components/assetTree/AssetTree.js +2 -1
- package/components/assetTree/Tree.js +1 -1
- package/components/editableContent/EditableContent.js +1 -1
- package/components/map/components/features/ContextMenu.js +3 -1
- package/components/selects/BaseSelectDropdown.d.ts +56 -0
- package/components/selects/BaseSelectDropdown.js +176 -0
- package/components/selects/ClearButton.d.ts +8 -0
- package/components/selects/ClearButton.js +11 -0
- package/components/selects/DropdownHeader.d.ts +7 -13
- package/components/selects/DropdownHeader.js +4 -12
- package/components/selects/Multiselect.d.ts +130 -98
- package/components/selects/Multiselect.js +143 -287
- package/components/selects/MultiselectToggleCounter.d.ts +9 -0
- package/components/selects/MultiselectToggleCounter.js +14 -0
- package/components/selects/MultiselectToggleFilter.d.ts +9 -0
- package/components/selects/MultiselectToggleFilter.js +13 -0
- package/components/selects/MultiselectTogglePlaceholder.d.ts +6 -0
- package/components/selects/MultiselectTogglePlaceholder.js +7 -0
- package/components/selects/MultiselectToggleSelection.d.ts +11 -0
- package/components/selects/MultiselectToggleSelection.js +29 -0
- package/components/selects/NoItemMessage.d.ts +7 -0
- package/components/selects/NoItemMessage.js +11 -0
- package/components/selects/Select.d.ts +128 -98
- package/components/selects/Select.js +114 -266
- package/components/selects/SelectFilter.d.ts +8 -0
- package/components/selects/SelectFilter.js +11 -0
- package/components/selects/SelectedOption.d.ts +12 -0
- package/components/selects/SelectedOption.js +24 -0
- package/components/selects/WithFeedback.d.ts +27 -0
- package/components/selects/WithFeedback.js +12 -0
- package/components/sidebars/Sidebar.js +3 -2
- package/components/smoothScrollbars/SmoothScrollbars.d.ts +16 -0
- package/components/smoothScrollbars/SmoothScrollbars.js +26 -0
- package/index.d.ts +4 -4
- package/index.js +4 -4
- package/lib/es/Colors.d.ts +1 -21
- package/lib/es/Colors.js +5 -3
- package/lib/es/Multiselect.d.ts +2 -12
- package/lib/es/Multiselect.js +3 -2
- package/lib/es/Select.d.ts +2 -5
- package/lib/es/Select.js +3 -2
- package/lib/es/components/applicationLayout/ApplicationLayoutBody.d.ts +1 -1
- package/lib/es/components/applicationLayout/ApplicationLayoutBody.js +14 -6
- package/lib/es/components/assetTree/AssetTree.js +2 -1
- package/lib/es/components/assetTree/Tree.js +1 -1
- package/lib/es/components/editableContent/EditableContent.js +1 -1
- package/lib/es/components/map/components/features/ContextMenu.js +3 -1
- package/lib/es/components/selects/BaseSelectDropdown.d.ts +56 -0
- package/lib/es/components/selects/BaseSelectDropdown.js +181 -0
- package/lib/es/components/selects/ClearButton.d.ts +8 -0
- package/lib/es/components/selects/ClearButton.js +14 -0
- package/lib/es/components/selects/DropdownHeader.d.ts +7 -13
- package/lib/es/components/selects/DropdownHeader.js +4 -13
- package/lib/es/components/selects/Multiselect.d.ts +130 -98
- package/lib/es/components/selects/Multiselect.js +141 -288
- package/lib/es/components/selects/MultiselectToggleCounter.d.ts +9 -0
- package/lib/es/components/selects/MultiselectToggleCounter.js +16 -0
- package/lib/es/components/selects/MultiselectToggleFilter.d.ts +9 -0
- package/lib/es/components/selects/MultiselectToggleFilter.js +16 -0
- package/lib/es/components/selects/MultiselectTogglePlaceholder.d.ts +6 -0
- package/lib/es/components/selects/MultiselectTogglePlaceholder.js +9 -0
- package/lib/es/components/selects/MultiselectToggleSelection.d.ts +11 -0
- package/lib/es/components/selects/MultiselectToggleSelection.js +32 -0
- package/lib/es/components/selects/NoItemMessage.d.ts +7 -0
- package/lib/es/components/selects/NoItemMessage.js +13 -0
- package/lib/es/components/selects/Select.d.ts +128 -98
- package/lib/es/components/selects/Select.js +112 -267
- package/lib/es/components/selects/SelectFilter.d.ts +8 -0
- package/lib/es/components/selects/SelectFilter.js +14 -0
- package/lib/es/components/selects/SelectedOption.d.ts +12 -0
- package/lib/es/components/selects/SelectedOption.js +26 -0
- package/lib/es/components/selects/WithFeedback.d.ts +27 -0
- package/lib/es/components/selects/WithFeedback.js +15 -0
- package/lib/es/components/sidebars/Sidebar.js +3 -2
- package/lib/es/components/smoothScrollbars/SmoothScrollbars.d.ts +16 -0
- package/lib/es/components/smoothScrollbars/SmoothScrollbars.js +29 -0
- package/lib/es/index.d.ts +4 -4
- package/lib/es/index.js +10 -8
- package/lib/es/types.d.ts +0 -67
- package/lib/es/version.json +1 -1
- package/package.json +6 -5
- package/types.d.ts +0 -67
- package/version.json +1 -1
package/Colors.d.ts
CHANGED
|
@@ -1,21 +1 @@
|
|
|
1
|
-
|
|
2
|
-
type Colors = {
|
|
3
|
-
'gray-darkest': string;
|
|
4
|
-
'gray-darker': string;
|
|
5
|
-
'gray-dark': string;
|
|
6
|
-
gray: string;
|
|
7
|
-
'gray-light': string;
|
|
8
|
-
'gray-lighter': string;
|
|
9
|
-
'gray-lightest': string;
|
|
10
|
-
'color-highlight-darkest': string;
|
|
11
|
-
'color-highlight-darker': string;
|
|
12
|
-
'color-highlight-dark': string;
|
|
13
|
-
'color-highlight': string;
|
|
14
|
-
'color-highlight-light': string;
|
|
15
|
-
'color-highlight-lighter': string;
|
|
16
|
-
'color-highlight-lightest': string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const colors: Colors;
|
|
20
|
-
export default colors;
|
|
21
|
-
}
|
|
1
|
+
export { default } from './styles/variables/colors/colors.json';
|
package/Colors.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { _colors as default };
|
|
1
|
+
export { default } from './styles/variables/colors/colors.json';
|
package/Multiselect.d.ts
CHANGED
|
@@ -1,12 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export { MultiselectOption } from './types';
|
|
5
|
-
export { MultiselectCounterMessage } from './types';
|
|
6
|
-
|
|
7
|
-
export default class Multiselect<T extends MultiselectOption> extends React.Component<MultiselectProps<T>> {
|
|
8
|
-
static SIZE_SM = 'sm';
|
|
9
|
-
static SIZE_LG = 'lg';
|
|
10
|
-
static SIZE_SMALL = 'small';
|
|
11
|
-
static SIZE_LARGE = 'large';
|
|
12
|
-
}
|
|
1
|
+
export { default } from './components/selects/Multiselect';
|
|
2
|
+
export * from './components/selects/Multiselect';
|
package/Multiselect.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
export { default } from './components/selects/Multiselect';
|
|
2
|
+
export * from './components/selects/Multiselect';
|
package/Select.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export { SelectOption } from './types';
|
|
5
|
-
export default class Select<T extends SelectOption> extends React.Component<SelectProps<T>> {}
|
|
1
|
+
export { default } from './components/selects/Select';
|
|
2
|
+
export * from './components/selects/Select';
|
package/Select.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
export { default } from './components/selects/Select';
|
|
2
|
+
export * from './components/selects/Select';
|
|
@@ -3,10 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle, } from 'react';
|
|
4
4
|
import debounce from 'lodash/fp/debounce';
|
|
5
5
|
import classNames from 'classnames';
|
|
6
|
+
import SmoothScrollbars from '../smoothScrollbars/SmoothScrollbars';
|
|
6
7
|
const RESIZE_THROTTLING = 200;
|
|
7
8
|
const DEFAULT_BOTTOM_BAR_HEIGHT = 54;
|
|
8
9
|
const ApplicationLayoutBody = forwardRef((props, ref) => {
|
|
9
|
-
const { className, innerClassName, forceScrollbar =
|
|
10
|
+
const { className, innerClassName, forceScrollbar = true, enableScrollToTop = true, banner, navigation, bottomBar, bottomBarHeight = DEFAULT_BOTTOM_BAR_HEIGHT, children } = props, remainingProps = __rest(props, ["className", "innerClassName", "forceScrollbar", "enableScrollToTop", "banner", "navigation", "bottomBar", "bottomBarHeight", "children"]);
|
|
10
11
|
const [offset, setOffset] = useState(0);
|
|
11
12
|
const moduleContentRef = useRef(null);
|
|
12
13
|
const layoutBodyRef = useRef(null);
|
|
@@ -19,24 +20,31 @@ const ApplicationLayoutBody = forwardRef((props, ref) => {
|
|
|
19
20
|
}, [bottomBarHeight]);
|
|
20
21
|
const handleScroll = debounce(RESIZE_THROTTLING)(() => {
|
|
21
22
|
if (moduleContentRef.current) {
|
|
22
|
-
setOffset(moduleContentRef.current.
|
|
23
|
+
setOffset(moduleContentRef.current.getScrollTop());
|
|
23
24
|
}
|
|
24
25
|
});
|
|
25
26
|
const handleToTop = () => {
|
|
27
|
+
var _a;
|
|
26
28
|
if (!moduleContentRef.current) {
|
|
27
29
|
return;
|
|
28
30
|
}
|
|
29
|
-
const
|
|
31
|
+
const scrollWrapper = moduleContentRef.current.container;
|
|
32
|
+
const scrollingElement = scrollWrapper.firstElementChild;
|
|
33
|
+
const currentScroll = (_a = scrollingElement === null || scrollingElement === void 0 ? void 0 : scrollingElement.scrollTop) !== null && _a !== void 0 ? _a : 0;
|
|
30
34
|
if (currentScroll > 0) {
|
|
31
35
|
window.requestAnimationFrame(handleToTop);
|
|
32
|
-
|
|
36
|
+
scrollingElement === null || scrollingElement === void 0 ? void 0 : scrollingElement.scrollTo(0, currentScroll - currentScroll / 5);
|
|
37
|
+
scrollWrapper.classList.add('is-scrolling-to-top');
|
|
33
38
|
setOffset(currentScroll);
|
|
34
39
|
}
|
|
40
|
+
else {
|
|
41
|
+
scrollWrapper.classList.remove('is-scrolling-to-top');
|
|
42
|
+
}
|
|
35
43
|
};
|
|
36
44
|
const classes = classNames('ApplicationLayoutBody', bottomBar && 'has-footer', className);
|
|
37
|
-
const innerClasses = classNames('module-content',
|
|
45
|
+
const innerClasses = classNames('module-content', innerClassName && innerClassName);
|
|
38
46
|
const offsetThreshold = window.innerHeight * 0.1;
|
|
39
47
|
const scrollToTopClasses = classNames('scroll-to-top', offset > offsetThreshold && 'in');
|
|
40
|
-
return (_jsxs(React.Fragment, { children: [_jsxs("div", Object.assign({}, remainingProps, { ref: layoutBodyRef, className: classes }, { children: [_jsxs("div", Object.assign({ className: 'module-content-wrapper' }, { children: [navigation && navigation, banner && banner, _jsx(
|
|
48
|
+
return (_jsxs(React.Fragment, { children: [_jsxs("div", Object.assign({}, remainingProps, { ref: layoutBodyRef, className: classes }, { children: [_jsxs("div", Object.assign({ className: 'module-content-wrapper' }, { children: [navigation && navigation, banner && banner, _jsx(SmoothScrollbars, Object.assign({ ref: moduleContentRef, slideIn: !forceScrollbar, largeTrack: true, trackOffset: true, className: innerClasses, onScroll: handleScroll }, { children: children }))] })), enableScrollToTop && (_jsx("span", Object.assign({ className: scrollToTopClasses }, { children: _jsx("button", Object.assign({ type: 'button', className: 'btn btn-primary btn-icon-only', onClick: handleToTop }, { children: _jsx("span", { className: 'rioglyph rioglyph-arrow-up' }) })) })))] })), bottomBar && bottomBar] }));
|
|
41
49
|
});
|
|
42
50
|
export default ApplicationLayoutBody;
|
|
@@ -12,6 +12,7 @@ import TreeSidebar from './TreeSidebar';
|
|
|
12
12
|
import getWidthInBoundaries from '../../utils/getWidthInBoundaries';
|
|
13
13
|
import mergeRefs from '../../utils/mergeRefs';
|
|
14
14
|
import usePrevious from '../../usePrevious';
|
|
15
|
+
import SmoothScrollbars from '../smoothScrollbars/SmoothScrollbars';
|
|
15
16
|
const DEFAULT_WIDTH = 350;
|
|
16
17
|
const DEFAULT_MIN_WIDTH = 100;
|
|
17
18
|
const DEFAULT_MAX_WIDTH = 0;
|
|
@@ -99,7 +100,7 @@ const AssetTree = memo(forwardRef((props, ref) => {
|
|
|
99
100
|
setIsResize(false);
|
|
100
101
|
onResizeEnd();
|
|
101
102
|
};
|
|
102
|
-
return (_jsxs("div", Object.assign({}, remainingProps, { className: classes, style: style, ref: mergedRefs }, { children: [_jsx("div", { className: resizeLimitClasses, style: resizeLimitStyle }), _jsxs("div", Object.assign({ className: 'AssetTreeContent' }, { children: [_jsx(TreeSidebar, Object.assign({ onSelectCategory: handleSelectCategory, currentCategoryId: currentCategoryId, onClick: handleToggleTreeContent }, { children: isArray(children) ? children : [children] })), _jsx(
|
|
103
|
+
return (_jsxs("div", Object.assign({}, remainingProps, { className: classes, style: style, ref: mergedRefs }, { children: [_jsx("div", { className: resizeLimitClasses, style: resizeLimitStyle }), _jsxs("div", Object.assign({ className: 'AssetTreeContent' }, { children: [_jsx(TreeSidebar, Object.assign({ onSelectCategory: handleSelectCategory, currentCategoryId: currentCategoryId, onClick: handleToggleTreeContent }, { children: isArray(children) ? children : [children] })), _jsx(SmoothScrollbars, Object.assign({ slideIn: true, className: 'AssetTreeBody' }, { children: useOffscreen ? renderTreesOffscreen(childrenArray, currentCategoryId) : category }))] })), resizable && isOpen && (_jsx(Resizer, { onResizeStart: handleResizeStart, onResize: handleResize, onResizeEnd: handleResizeEnd, direction: Resizer.HORIZONTAL, position: Resizer.RIGHT }))] })));
|
|
103
104
|
}));
|
|
104
105
|
AssetTree.displayName = 'AssetTree';
|
|
105
106
|
Object.assign(AssetTree, TreeMode);
|
|
@@ -256,7 +256,7 @@ const Tree = React.memo((props) => {
|
|
|
256
256
|
const hasSearchAndNoGroups = hasInternalSearchValue() && isEmpty(state.groupedItems) && hasExternalGroups;
|
|
257
257
|
const hideSelectAll = hasSearchAndNoItems || hasSearchAndNoGroups;
|
|
258
258
|
const isIndeterminate = hasPartiallySelectedGroups() || hasPartiallySelectedItems();
|
|
259
|
-
const treeClassNames = classNames('Tree',
|
|
259
|
+
const treeClassNames = classNames('Tree', className);
|
|
260
260
|
const treeHeadClasses = classNames('TreeHead', 'display-flex gap-5', 'padding-15');
|
|
261
261
|
const shouldRenderTree = () => hasGroups() && !hasInternalSearchValue();
|
|
262
262
|
const content = cond([
|
|
@@ -99,7 +99,7 @@ const EditableContent = (props) => {
|
|
|
99
99
|
}
|
|
100
100
|
const textWrapperClasses = classNames(className, isEditMode && 'opacity-0');
|
|
101
101
|
const overlayWrapperClasses = classNames('EditableContentEditor', 'display-flex gap-5', 'padding-5', 'rounded', 'shadow-accent', 'z-index-max', 'bg-white', editorClassName);
|
|
102
|
-
const inputWrapperClasses = classNames('display-flex flex-column gap-5', 'margin-0',
|
|
102
|
+
const inputWrapperClasses = classNames('display-flex flex-column gap-5', 'margin-0', 'form-group has-feedback', hasError && 'has-error');
|
|
103
103
|
const inputClasses = classNames('form-control', size === 'lg' && 'input-lg', inputClassName);
|
|
104
104
|
const inputStyle = {
|
|
105
105
|
minWidth: '100px',
|
|
@@ -3,7 +3,9 @@ import { useContext, useRef, useLayoutEffect } from 'react';
|
|
|
3
3
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
4
4
|
import { MapContext } from '../context';
|
|
5
5
|
const HERE_ITEM_CLASS = 'H_context_menu_item';
|
|
6
|
-
const centeredSpinner =
|
|
6
|
+
const centeredSpinner =
|
|
7
|
+
// eslint-disable-next-line max-len
|
|
8
|
+
'<svg aria-labelledby="ggtrwic-aria" role="img" height="14" width="135px" class="ContentLoader use-mix-blend-mode"><title id="ggtrwic-aria">Loading...</title><rect role="presentation" x="0" y="0" width="100%" height="100%" clip-path="url(#ggtrwic-diff)" style="fill: url("#ggtrwic-animated-diff");"></rect><defs><clipPath id="ggtrwic-diff"><rect width="100%" height="100%" rx="3" ry="3"></rect></clipPath><linearGradient id="ggtrwic-animated-diff"><stop offset="0%" stop-color="#f5f6f7" stop-opacity="1"><animate attributeName="offset" values="-2; -2; 1" keyTimes="0; 0.25; 1" dur="2s" repeatCount="indefinite"></animate></stop><stop offset="50%" stop-color="#aaaaaa" stop-opacity="1"><animate attributeName="offset" values="-1; -1; 2" keyTimes="0; 0.25; 1" dur="2s" repeatCount="indefinite"></animate></stop><stop offset="100%" stop-color="#f5f6f7" stop-opacity="1"><animate attributeName="offset" values="0; 0; 3" keyTimes="0; 0.25; 1" dur="2s" repeatCount="indefinite"></animate></stop></linearGradient></defs></svg>';
|
|
7
9
|
const getDOMMenuItems = () => document.getElementsByClassName(HERE_ITEM_CLASS);
|
|
8
10
|
// Query DOM nodes for "H_context_menu_item" and update label when children label has changed.
|
|
9
11
|
// This function allows to use HTML markup for the menu items in the second render
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type OptionDOMValue = {
|
|
3
|
+
id: string;
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
export type SelectOption = {
|
|
7
|
+
/**
|
|
8
|
+
* Used to identify an option
|
|
9
|
+
*/
|
|
10
|
+
id: string;
|
|
11
|
+
/**
|
|
12
|
+
* The option item text
|
|
13
|
+
*/
|
|
14
|
+
label: string | React.ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Icon to be displayed in front of the label
|
|
17
|
+
*/
|
|
18
|
+
icon?: React.ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Defines whether the menu item is selected or not
|
|
21
|
+
*
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
selected?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Setting "disabled" to true will disable the respective item
|
|
27
|
+
*
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Will treat the given value as a menu header
|
|
33
|
+
*/
|
|
34
|
+
header?: boolean;
|
|
35
|
+
};
|
|
36
|
+
export type BaseSelectDropdownProps = {
|
|
37
|
+
options?: SelectOption[];
|
|
38
|
+
isOpen?: boolean;
|
|
39
|
+
updateDOMValues?: (values: OptionDOMValue[] | undefined) => void;
|
|
40
|
+
onOpen?: (hasDropup: boolean) => void;
|
|
41
|
+
onSelect?: (selectedItem: SelectOption | undefined) => void;
|
|
42
|
+
onClose?: () => void;
|
|
43
|
+
placeholder?: string | React.ReactNode;
|
|
44
|
+
dropup?: boolean;
|
|
45
|
+
pullRight?: boolean;
|
|
46
|
+
autoDropDirection?: boolean;
|
|
47
|
+
noItemMessage?: string | React.ReactNode;
|
|
48
|
+
focusedItemIndex?: number;
|
|
49
|
+
dropdownClassName?: string;
|
|
50
|
+
requestItemDOMValues?: boolean;
|
|
51
|
+
keyboardUsed?: boolean;
|
|
52
|
+
useActiveClass?: boolean;
|
|
53
|
+
};
|
|
54
|
+
declare const BaseSelectDropdown: (props: BaseSelectDropdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
55
|
+
export declare const filterOptions: (itemDOMValues: OptionDOMValue[], filterValue: string, options: SelectOption[]) => SelectOption[];
|
|
56
|
+
export default BaseSelectDropdown;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// @ts-ignore-next-line importsNotUsedAsValues
|
|
3
|
+
import { useState, useRef, useLayoutEffect } from 'react';
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
import isEmpty from 'lodash/fp/isEmpty';
|
|
6
|
+
import noop from 'lodash/fp/noop';
|
|
7
|
+
import { useDropDirection } from '../../utils/useDropDirection';
|
|
8
|
+
import { scrollItemIntoView, UP, DOWN } from '../../utils/scrollItemIntoView';
|
|
9
|
+
import useEffectOnce from '../../hooks/useEffectOnce';
|
|
10
|
+
import useKey from '../../useKey';
|
|
11
|
+
import DropdownHeader from './DropdownHeader';
|
|
12
|
+
import NoItemMessage from './NoItemMessage';
|
|
13
|
+
const DATA_ATTRIBUTE_ID = 'data-item-id';
|
|
14
|
+
const DEFAULT_FOCUSED_ITEM_INDEX = 0;
|
|
15
|
+
const HIGHLIGHT_CLASS = 'focus';
|
|
16
|
+
const BaseSelectDropdown = (props) => {
|
|
17
|
+
const { isOpen = false, updateDOMValues = noop, onOpen = noop, onSelect = noop, onClose = noop, options = [], autoDropDirection = true, dropup = false, pullRight = false, useActiveClass = false, focusedItemIndex: externalFocusedItemIndex, keyboardUsed: externalKeyboardUsed, noItemMessage, dropdownClassName, } = props;
|
|
18
|
+
const [focusedItemIndex, setFocusedItemIndex] = useState(externalFocusedItemIndex || DEFAULT_FOCUSED_ITEM_INDEX);
|
|
19
|
+
const [keyboardUsed, setKeyboardUsed] = useState(externalKeyboardUsed);
|
|
20
|
+
const dropdownMenuRef = useRef(null);
|
|
21
|
+
useEffectOnce(() => {
|
|
22
|
+
// all available items need to be rendered in order to know their DOM value
|
|
23
|
+
// which will be used for filtering in the parent component
|
|
24
|
+
const currentItemDOMValues = updateItemDOMValues();
|
|
25
|
+
updateDOMValues(currentItemDOMValues);
|
|
26
|
+
});
|
|
27
|
+
// Overwrite position of dropdown menu in case auto drop is enabled
|
|
28
|
+
const dropDirection = useDropDirection({ pullRight, dropup, autoDropDirection, dropdownMenuRef }, [isOpen]);
|
|
29
|
+
// Add or remove the "dropup" class from the parent Select/Multiselect component to position
|
|
30
|
+
// the dropdown element accordingly via CSS
|
|
31
|
+
useLayoutEffect(() => {
|
|
32
|
+
if (dropdownMenuRef.current) {
|
|
33
|
+
const parent = dropdownMenuRef.current.parentElement;
|
|
34
|
+
if (dropDirection.dropup) {
|
|
35
|
+
parent === null || parent === void 0 ? void 0 : parent.classList.add('dropup');
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
parent === null || parent === void 0 ? void 0 : parent.classList.remove('dropup');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, [dropDirection, dropdownMenuRef]);
|
|
42
|
+
// update internal state for isOpen
|
|
43
|
+
const [previousIsOpen, setPreviousIsOpen] = useState(isOpen);
|
|
44
|
+
if (isOpen && !previousIsOpen) {
|
|
45
|
+
onOpen(dropDirection.dropup);
|
|
46
|
+
setPreviousIsOpen(isOpen);
|
|
47
|
+
}
|
|
48
|
+
else if (!isOpen && previousIsOpen) {
|
|
49
|
+
onClose();
|
|
50
|
+
setPreviousIsOpen(isOpen);
|
|
51
|
+
}
|
|
52
|
+
useKey(event => {
|
|
53
|
+
if (isOpen) {
|
|
54
|
+
switch (event.key) {
|
|
55
|
+
case 'Escape': {
|
|
56
|
+
// close dropdown on esc
|
|
57
|
+
onClose();
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case 'Tab': {
|
|
61
|
+
// close dropdown on tab
|
|
62
|
+
onClose();
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'Enter': {
|
|
66
|
+
// select item on enter
|
|
67
|
+
selectOptionOnEnter(event);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case 'ArrowUp': {
|
|
71
|
+
// prevent scrolling the page when dropdown menu is open
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
// select item above on arrow up key
|
|
74
|
+
focusOption(UP);
|
|
75
|
+
scrollItemIntoView(UP, dropdownMenuRef.current, getFocusedOptionNode());
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case 'ArrowDown': {
|
|
79
|
+
// prevent scrolling the page when dropdown menu is open
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
// select item below on arrow down key
|
|
82
|
+
focusOption(DOWN);
|
|
83
|
+
scrollItemIntoView(DOWN, dropdownMenuRef.current, getFocusedOptionNode());
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
default:
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const focusOption = (direction) => {
|
|
92
|
+
let nextFocusedItem = 0;
|
|
93
|
+
switch (direction) {
|
|
94
|
+
case UP: {
|
|
95
|
+
nextFocusedItem = focusedItemIndex <= 0 ? focusedItemIndex : focusedItemIndex - 1;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case DOWN: {
|
|
99
|
+
nextFocusedItem = focusedItemIndex === options.length - 1 ? focusedItemIndex : focusedItemIndex + 1;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
default:
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
// In case the next item index is negative, means outside the bounds of the items,
|
|
106
|
+
// reset it depending on the current direction
|
|
107
|
+
const indexLimit = direction === UP ? options.length - 1 : 0;
|
|
108
|
+
setFocusedItemIndex(nextFocusedItem < 0 ? indexLimit : nextFocusedItem);
|
|
109
|
+
setKeyboardUsed(true);
|
|
110
|
+
};
|
|
111
|
+
const getOptionNodes = () => {
|
|
112
|
+
const node = dropdownMenuRef.current;
|
|
113
|
+
return (node === null || node === void 0 ? void 0 : node.getElementsByTagName('a')) || [];
|
|
114
|
+
};
|
|
115
|
+
const updateItemDOMValues = () => {
|
|
116
|
+
if (dropdownMenuRef.current) {
|
|
117
|
+
const optionNodes = getOptionNodes();
|
|
118
|
+
const itemDOMValuesMapped = [...optionNodes].map(item => {
|
|
119
|
+
return {
|
|
120
|
+
id: item.getAttribute(DATA_ATTRIBUTE_ID),
|
|
121
|
+
text: item.textContent,
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
return itemDOMValuesMapped;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const getFocusedOptionNode = () => {
|
|
128
|
+
const optionNodes = getOptionNodes();
|
|
129
|
+
return [...optionNodes].find(item => item.className.includes(HIGHLIGHT_CLASS));
|
|
130
|
+
};
|
|
131
|
+
const selectOptionOnEnter = (event) => {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
// When no filter result was found, avoid selecting anything
|
|
134
|
+
if (isEmpty(options)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const match = getFocusedOptionNode();
|
|
138
|
+
if (match) {
|
|
139
|
+
const selectedItem = options.find(option => option.id === match.getAttribute(DATA_ATTRIBUTE_ID));
|
|
140
|
+
onSelect(selectedItem);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const handleOptionChange = (event) => {
|
|
144
|
+
event.preventDefault();
|
|
145
|
+
const optionId = event.currentTarget.getElementsByTagName('input')[0].value;
|
|
146
|
+
const selectedItem = options.find(option => option.id === optionId);
|
|
147
|
+
onSelect(selectedItem);
|
|
148
|
+
};
|
|
149
|
+
const dropdownMenuClasses = classNames('dropdown-menu', dropDirection.pullRight && 'pull-right', dropdownClassName);
|
|
150
|
+
// Don't show the dropdown, when no match are found when filtering unless there is a not found message
|
|
151
|
+
if (isEmpty(options)) {
|
|
152
|
+
return _jsx(NoItemMessage, { noItemMessage: noItemMessage, className: dropdownMenuClasses });
|
|
153
|
+
}
|
|
154
|
+
return (_jsx("ul", Object.assign({ className: dropdownMenuClasses, ref: dropdownMenuRef, role: 'menu' }, { children: options.map((option, index) => {
|
|
155
|
+
if (option.header) {
|
|
156
|
+
return _jsx(DropdownHeader, { icon: option.icon, label: option.label }, option.id);
|
|
157
|
+
}
|
|
158
|
+
// Show focused style only when keyboard is in use
|
|
159
|
+
const anchorClassNames = classNames('display-flex align-items-center', keyboardUsed && focusedItemIndex === index ? HIGHLIGHT_CLASS : '', option.disabled && 'pointer-events-none');
|
|
160
|
+
const wrapperClassNames = classNames(option.disabled && 'disabled', useActiveClass && option.selected && 'active');
|
|
161
|
+
return (_jsx("li", Object.assign({ className: wrapperClassNames, role: 'listitem' }, { children: _jsxs("a", Object.assign({ role: 'menuitem', className: anchorClassNames, "data-item-id": option.id, "data-item-index": index,
|
|
162
|
+
// Note, we need to assign the click callback only when it's not disabled
|
|
163
|
+
// otherwise the functions is still triggered
|
|
164
|
+
// biome-ignore lint/a11y/useValidAnchor: due to old structure and backwards compatibility
|
|
165
|
+
onClick: option.disabled ? undefined : handleOptionChange }, { children: [_jsxs("span", { children: [option.icon && _jsx("span", Object.assign({ className: 'margin-right-5' }, { children: option.icon })), option.label] }), _jsx("input", { type: 'hidden', value: option.id })] })) }), option.id));
|
|
166
|
+
}) })));
|
|
167
|
+
};
|
|
168
|
+
export const filterOptions = (itemDOMValues, filterValue, options) => {
|
|
169
|
+
const filteredDOMValues = itemDOMValues.filter(item => item.text.toLowerCase().includes(filterValue.toLowerCase()));
|
|
170
|
+
// Filter the options according to the filtered DOM values and map the IDs since the filter cannot be done
|
|
171
|
+
// on the options itself as they might contain arbitrary components
|
|
172
|
+
return options.filter(option => {
|
|
173
|
+
return filteredDOMValues.find(domValue => domValue.id === option.id);
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
export default BaseSelectDropdown;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SelectOption } from './Select';
|
|
2
|
+
export type ClearButtonProps = {
|
|
3
|
+
showClear: boolean;
|
|
4
|
+
selectedItem: SelectOption | null;
|
|
5
|
+
onClear: () => void;
|
|
6
|
+
};
|
|
7
|
+
declare const ClearButton: (props: ClearButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default ClearButton;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @ts-ignore-next-line importsNotUsedAsValues
|
|
3
|
+
import 'react';
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
import isNil from 'lodash/fp/isNil';
|
|
6
|
+
const ClearButton = (props) => {
|
|
7
|
+
const { showClear, selectedItem, onClear } = props;
|
|
8
|
+
const clearButtonClassNames = classNames('clearButton', (!showClear || isNil(selectedItem)) && 'hide pointer-events-none');
|
|
9
|
+
return (_jsx("span", Object.assign({ className: clearButtonClassNames, onClick: onClear }, { children: _jsx("span", { className: 'clearButtonIcon rioglyph rioglyph-remove-sign' }) })));
|
|
10
|
+
};
|
|
11
|
+
export default ClearButton;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type DropdownHeaderProps = {
|
|
3
|
+
icon?: React.ReactNode;
|
|
4
|
+
center?: boolean;
|
|
5
|
+
label: string | React.ReactNode;
|
|
6
|
+
};
|
|
7
|
+
declare const DropdownHeader: (props: DropdownHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
1
8
|
export default DropdownHeader;
|
|
2
|
-
declare function DropdownHeader(props: any): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
declare namespace DropdownHeader {
|
|
4
|
-
namespace defaultProps {
|
|
5
|
-
const center: boolean;
|
|
6
|
-
}
|
|
7
|
-
namespace propTypes {
|
|
8
|
-
export const icon: PropTypes.Requireable<string>;
|
|
9
|
-
const center_1: PropTypes.Requireable<boolean>;
|
|
10
|
-
export { center_1 as center };
|
|
11
|
-
export const label: PropTypes.Requireable<NonNullable<PropTypes.ReactNodeLike>>;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
import PropTypes from "prop-types";
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
const DropdownHeader = props => {
|
|
5
|
-
const { icon, label, center } = props;
|
|
2
|
+
// @ts-ignore-next-line importsNotUsedAsValues
|
|
3
|
+
import 'react';
|
|
4
|
+
const DropdownHeader = (props) => {
|
|
5
|
+
const { icon, label, center = true } = props;
|
|
6
6
|
return (_jsx("li", Object.assign({ className: `dropdown-header ${center ? 'center' : ''}` }, { children: _jsxs("span", Object.assign({ className: 'dropdown-header-text' }, { children: [icon && _jsx("span", Object.assign({ className: 'margin-right-5' }, { children: icon })), label] })) })));
|
|
7
7
|
};
|
|
8
|
-
DropdownHeader.defaultProps = {
|
|
9
|
-
center: true,
|
|
10
|
-
};
|
|
11
|
-
DropdownHeader.propTypes = {
|
|
12
|
-
icon: PropTypes.string,
|
|
13
|
-
center: PropTypes.bool,
|
|
14
|
-
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
15
|
-
};
|
|
16
8
|
export default DropdownHeader;
|