@rio-cloud/rio-uikit 1.7.0 → 1.8.0
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/README.md +4 -0
- package/SvgImage.d.ts +2 -0
- package/SvgImage.js +2 -0
- package/TableCol.d.ts +2 -0
- package/TableCol.js +2 -0
- package/TableHead.d.ts +2 -0
- package/TableHead.js +2 -0
- package/components/actionBarItem/ActionBarItemIcon.js +1 -1
- package/components/actionBarItem/ActionBarOverlay.js +1 -1
- package/components/applicationHeader/CollapsedNavItem.js +1 -0
- package/components/assetTree/Tree.d.ts +8 -0
- package/components/assetTree/Tree.js +4 -2
- package/components/assetTree/TreeLeaf.js +1 -1
- package/components/assetTree/TreeSearch.js +1 -1
- package/components/assetTree/TreeSummary.js +1 -1
- package/components/assetTree/TypeCounter.d.ts +2 -0
- package/components/assetTree/TypeCounter.js +1 -1
- package/components/autosuggest/AutoSuggest.js +2 -1
- package/components/banner/Banner.d.ts +6 -0
- package/components/banner/Banner.js +33 -8
- package/components/button/ButtonToolbar.d.ts +1 -1
- package/components/button/ButtonToolbar.js +1 -1
- package/components/button/ToggleButton.js +0 -1
- package/components/clearableInput/ClearableInput.d.ts +20 -7
- package/components/clearableInput/ClearableInput.js +68 -8
- package/components/dialog/Dialog.js +1 -1
- package/components/dialog/FrameDialog.js +1 -1
- package/components/dropdown/ButtonDropdown.d.ts +11 -3
- package/components/dropdown/ButtonDropdown.js +79 -64
- package/components/dropdown/DropdownToggleButton.d.ts +7 -4
- package/components/dropdown/DropdownToggleButton.js +11 -3
- package/components/formLabel/FormLabel.js +24 -4
- package/components/listMenu/ListMenu.js +8 -4
- package/components/map/components/Map.js +1 -1
- package/components/map/components/features/basics/InfoBubble.js +1 -1
- package/components/map/components/features/layers/overlayLayers/IncidentsLayer.js +1 -1
- package/components/mapMarker/SingleMapMarker.js +1 -1
- package/components/menuItems/MenuItem.js +1 -1
- package/components/notification/Notification.js +1 -1
- package/components/overlay/OverlayTrigger.js +1 -1
- package/components/selects/BaseSelectDropdown.js +1 -1
- package/components/selects/Multiselect.d.ts +8 -0
- package/components/selects/Multiselect.js +4 -4
- package/components/smoothScrollbars/SmoothScrollbars.js +1 -1
- package/components/svgImage/SvgElement.d.ts +8 -0
- package/components/svgImage/SvgElement.js +11 -0
- package/components/svgImage/SvgImage.d.ts +30 -0
- package/components/svgImage/SvgImage.js +20 -0
- package/components/svgImage/svgConverter.d.ts +17 -0
- package/components/svgImage/svgConverter.js +78 -0
- package/components/svgImage/useSvgLoader.d.ts +9 -0
- package/components/svgImage/useSvgLoader.js +43 -0
- package/components/switch/Switch.d.ts +4 -0
- package/components/switch/Switch.js +5 -6
- package/components/table/TableCardsSorting.d.ts +0 -1
- package/components/table/TableCol.d.ts +18 -0
- package/components/table/TableCol.js +11 -0
- package/components/table/TableHead.d.ts +33 -0
- package/components/table/TableHead.js +11 -0
- package/components/table/TableSettingsDialog.js +1 -1
- package/components/tag/Tag.js +1 -1
- package/components/timepicker/TimePicker.d.ts +1 -2
- package/components/timepicker/TimePicker.js +35 -8
- package/components/virtualList/VirtualList.js +1 -1
- package/hooks/useLocationSuggestions.d.ts +27 -0
- package/hooks/useLocationSuggestions.js +94 -0
- package/hooks/useOnboarding.d.ts +17 -5
- package/hooks/useOnboarding.js +7 -1
- package/hooks/usePostMessage.js +0 -1
- package/hooks/useSearch.d.ts +63 -0
- package/hooks/useSearch.js +73 -0
- package/hooks/useSorting.d.ts +6 -0
- package/hooks/useSorting.js +7 -4
- package/hooks/useTableSelection.d.ts +151 -0
- package/hooks/useTableSelection.js +196 -0
- package/lib/es/SvgImage.d.ts +2 -0
- package/lib/es/SvgImage.js +7 -0
- package/lib/es/TableCol.d.ts +2 -0
- package/lib/es/TableCol.js +7 -0
- package/lib/es/TableHead.d.ts +2 -0
- package/lib/es/TableHead.js +7 -0
- package/lib/es/components/actionBarItem/ActionBarItemIcon.js +1 -1
- package/lib/es/components/actionBarItem/ActionBarOverlay.js +1 -1
- package/lib/es/components/applicationHeader/CollapsedNavItem.js +1 -0
- package/lib/es/components/assetTree/Tree.d.ts +8 -0
- package/lib/es/components/assetTree/Tree.js +4 -2
- package/lib/es/components/assetTree/TreeLeaf.js +1 -1
- package/lib/es/components/assetTree/TreeSearch.js +1 -1
- package/lib/es/components/assetTree/TreeSummary.js +1 -1
- package/lib/es/components/assetTree/TypeCounter.d.ts +2 -0
- package/lib/es/components/assetTree/TypeCounter.js +1 -1
- package/lib/es/components/autosuggest/AutoSuggest.js +2 -1
- package/lib/es/components/banner/Banner.d.ts +6 -0
- package/lib/es/components/banner/Banner.js +31 -6
- package/lib/es/components/button/ButtonToolbar.d.ts +1 -1
- package/lib/es/components/button/ButtonToolbar.js +1 -1
- package/lib/es/components/button/ToggleButton.js +0 -1
- package/lib/es/components/clearableInput/ClearableInput.d.ts +20 -7
- package/lib/es/components/clearableInput/ClearableInput.js +67 -7
- package/lib/es/components/dialog/Dialog.js +1 -1
- package/lib/es/components/dialog/FrameDialog.js +1 -1
- package/lib/es/components/dropdown/ButtonDropdown.d.ts +11 -3
- package/lib/es/components/dropdown/ButtonDropdown.js +79 -64
- package/lib/es/components/dropdown/DropdownToggleButton.d.ts +7 -4
- package/lib/es/components/dropdown/DropdownToggleButton.js +11 -3
- package/lib/es/components/formLabel/FormLabel.js +24 -4
- package/lib/es/components/listMenu/ListMenu.js +7 -3
- package/lib/es/components/map/components/Map.js +1 -1
- package/lib/es/components/map/components/features/basics/InfoBubble.js +1 -1
- package/lib/es/components/map/components/features/layers/overlayLayers/IncidentsLayer.js +1 -1
- package/lib/es/components/mapMarker/SingleMapMarker.js +1 -1
- package/lib/es/components/menuItems/MenuItem.js +1 -1
- package/lib/es/components/notification/Notification.js +1 -1
- package/lib/es/components/overlay/OverlayTrigger.js +1 -1
- package/lib/es/components/selects/BaseSelectDropdown.js +1 -1
- package/lib/es/components/selects/Multiselect.d.ts +8 -0
- package/lib/es/components/selects/Multiselect.js +4 -4
- package/lib/es/components/smoothScrollbars/SmoothScrollbars.js +1 -1
- package/lib/es/components/svgImage/SvgElement.d.ts +8 -0
- package/lib/es/components/svgImage/SvgElement.js +14 -0
- package/lib/es/components/svgImage/SvgImage.d.ts +30 -0
- package/lib/es/components/svgImage/SvgImage.js +25 -0
- package/lib/es/components/svgImage/svgConverter.d.ts +17 -0
- package/lib/es/components/svgImage/svgConverter.js +84 -0
- package/lib/es/components/svgImage/useSvgLoader.d.ts +9 -0
- package/lib/es/components/svgImage/useSvgLoader.js +48 -0
- package/lib/es/components/switch/Switch.d.ts +4 -0
- package/lib/es/components/switch/Switch.js +5 -6
- package/lib/es/components/table/TableCardsSorting.d.ts +0 -1
- package/lib/es/components/table/TableCol.d.ts +18 -0
- package/lib/es/components/table/TableCol.js +13 -0
- package/lib/es/components/table/TableHead.d.ts +33 -0
- package/lib/es/components/table/TableHead.js +14 -0
- package/lib/es/components/table/TableSettingsDialog.js +1 -1
- package/lib/es/components/tag/Tag.js +1 -1
- package/lib/es/components/timepicker/TimePicker.d.ts +1 -2
- package/lib/es/components/timepicker/TimePicker.js +35 -8
- package/lib/es/components/virtualList/VirtualList.js +1 -1
- package/lib/es/hooks/useLocationSuggestions.d.ts +27 -0
- package/lib/es/hooks/useLocationSuggestions.js +97 -0
- package/lib/es/hooks/useOnboarding.d.ts +17 -5
- package/lib/es/hooks/useOnboarding.js +7 -1
- package/lib/es/hooks/usePostMessage.js +0 -1
- package/lib/es/hooks/useSearch.d.ts +63 -0
- package/lib/es/hooks/useSearch.js +75 -0
- package/lib/es/hooks/useSorting.d.ts +6 -0
- package/lib/es/hooks/useSorting.js +7 -4
- package/lib/es/hooks/useTableSelection.d.ts +151 -0
- package/lib/es/hooks/useTableSelection.js +205 -0
- package/lib/es/themes/Volkswagen/components/applicationHeader/VolkswagenApplicationHeader.js +1 -1
- package/lib/es/useLocationSuggestions.d.ts +2 -0
- package/lib/es/useLocationSuggestions.js +7 -0
- package/lib/es/useSearch.d.ts +2 -0
- package/lib/es/useSearch.js +7 -0
- package/lib/es/useTableSelection.d.ts +2 -0
- package/lib/es/useTableSelection.js +7 -0
- package/lib/es/utils/storageUtils.d.ts +2 -2
- package/lib/es/utils/storageUtils.js +2 -0
- package/lib/es/utils/urlFeatureToggles.d.ts +12 -6
- package/lib/es/utils/urlFeatureToggles.js +14 -8
- package/lib/es/utils/useDropDirection.js +1 -0
- package/lib/es/version.json +1 -1
- package/package.json +36 -39
- package/themes/Volkswagen/components/applicationHeader/VolkswagenApplicationHeader.js +1 -1
- package/useLocationSuggestions.d.ts +2 -0
- package/useLocationSuggestions.js +2 -0
- package/useSearch.d.ts +2 -0
- package/useSearch.js +2 -0
- package/useTableSelection.d.ts +2 -0
- package/useTableSelection.js +2 -0
- package/utils/storageUtils.d.ts +2 -2
- package/utils/storageUtils.js +2 -0
- package/utils/urlFeatureToggles.d.ts +12 -6
- package/utils/urlFeatureToggles.js +10 -7
- package/utils/useDropDirection.js +1 -0
- package/version.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { convertAttributes, defaultColorMap } from './svgConverter';
|
|
4
|
+
import SvgElement from './SvgElement';
|
|
5
|
+
export const useSvgLoader = (name, baseUrl, colorMap = defaultColorMap) => {
|
|
6
|
+
const [svgElement, setSvgElement] = useState(null);
|
|
7
|
+
const [error, setError] = useState(false);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const fetchSvg = async () => {
|
|
10
|
+
try {
|
|
11
|
+
const url = `${baseUrl}/${name}.svg`;
|
|
12
|
+
const response = await fetch(url);
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
throw new Error('Failed to load SVG');
|
|
15
|
+
}
|
|
16
|
+
const svgText = await response.text();
|
|
17
|
+
if (svgText.startsWith('<html>')) {
|
|
18
|
+
// When fetching from RIO CDN, a default index page is returned when something cannot be found.
|
|
19
|
+
// Hence, we need to check for this to throw a proper error message.
|
|
20
|
+
throw new Error(`Could not load SVG with URL: ${url}`);
|
|
21
|
+
}
|
|
22
|
+
const parser = new DOMParser();
|
|
23
|
+
const doc = parser.parseFromString(svgText, 'image/svg+xml');
|
|
24
|
+
const svgNode = doc.querySelector('svg');
|
|
25
|
+
if (!svgNode) {
|
|
26
|
+
throw new Error('Invalid SVG format');
|
|
27
|
+
}
|
|
28
|
+
const attributes = convertAttributes(svgNode, colorMap);
|
|
29
|
+
const svgJsx = (_jsx("svg", { ...attributes, children: Array.from(svgNode.childNodes).map((node, idx) => node.nodeType === 1 ? (
|
|
30
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
|
|
31
|
+
_jsx(SvgElement, { node: node, colorMap: colorMap }, idx)) : null) }));
|
|
32
|
+
setSvgElement(svgJsx);
|
|
33
|
+
setError(false);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
console.error(`Error loading SVG "${name}":`, err);
|
|
37
|
+
setError(true);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
fetchSvg();
|
|
41
|
+
}, [name, baseUrl, colorMap]);
|
|
42
|
+
return { svgElement, error };
|
|
43
|
+
};
|
|
@@ -45,6 +45,10 @@ export type SwitchProps = {
|
|
|
45
45
|
* Possible values are `left` and `right`.
|
|
46
46
|
*/
|
|
47
47
|
labelPosition?: 'left' | 'right';
|
|
48
|
+
/**
|
|
49
|
+
* Additional class names added to the SVG element.
|
|
50
|
+
*/
|
|
51
|
+
className?: string;
|
|
48
52
|
};
|
|
49
53
|
declare const Switch: React.ForwardRefExoticComponent<PropsWithChildren<SwitchProps> & React.RefAttributes<HTMLDivElement>> & {
|
|
50
54
|
LABEL_POSITION_LEFT: "left";
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import noop from 'lodash/fp/noop';
|
|
6
6
|
import { getCurrentBackgroundColor } from '../../utils/currentColors';
|
|
7
7
|
const Switch = forwardRef((props, ref) => {
|
|
8
|
-
const { keyName, checked = false, enabledText, minWidth = 40, disabled = false, color = 'primary', disabledText, children, labelPosition = children ? 'right' : undefined, onChange = noop, ...remainingProps } = props;
|
|
8
|
+
const { keyName, checked = false, enabledText, minWidth = 40, disabled = false, color = 'primary', disabledText, children, className = '', labelPosition = children ? 'right' : undefined, onChange = noop, ...remainingProps } = props;
|
|
9
9
|
const handleChange = (event) => {
|
|
10
10
|
onChange(event.target.checked);
|
|
11
11
|
};
|
|
12
12
|
const hasMultipleText = enabledText && disabledText;
|
|
13
13
|
const hasSingleText = enabledText && !disabledText;
|
|
14
|
+
const switchClasses = classNames('uikit-switch', className);
|
|
14
15
|
const switchLabelClasses = classNames('switch-label', disabled && 'cursor-not-allowed', labelPosition && `label-position-${labelPosition}`);
|
|
15
|
-
const switchContentClasses = classNames('switch-content'
|
|
16
|
-
// !hasMultipleText && !hasSingleText && 'width-40'
|
|
17
|
-
);
|
|
16
|
+
const switchContentClasses = classNames('switch-content');
|
|
18
17
|
const switchBackgroundColor = getCurrentBackgroundColor(color);
|
|
19
|
-
return (_jsx("div", { ref: ref, ...remainingProps, className:
|
|
18
|
+
return (_jsx("div", { ref: ref, ...remainingProps, className: switchClasses, children: _jsxs("label", { className: switchLabelClasses, children: [_jsx("input", { onChange: handleChange, checked: checked, type: 'checkbox', id: keyName, className: 'switch-input', disabled: disabled }, keyName), _jsxs("div", { className: switchContentClasses, style: { color: switchBackgroundColor, minWidth }, children: [hasMultipleText ? (_jsx("div", { className: 'switch-text', "data-on": enabledText, "data-off": disabledText })) : (hasSingleText && _jsx("div", { className: 'switch-text', "data-on": enabledText, "data-off": enabledText })), _jsx("div", { className: 'switch-handle' })] }), children && children] }) }));
|
|
20
19
|
});
|
|
21
20
|
Switch.LABEL_POSITION_LEFT = 'left';
|
|
22
21
|
Switch.LABEL_POSITION_RIGHT = 'right';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ColumnDetails = {
|
|
2
|
+
[key: string]: number;
|
|
3
|
+
};
|
|
4
|
+
export type ColumnDetailsMap = {
|
|
5
|
+
[key: string]: ColumnDetails;
|
|
6
|
+
};
|
|
7
|
+
type TableColProps = {
|
|
8
|
+
/**
|
|
9
|
+
* The width of the column as part of the column details object used for the TableSettingsDialog.
|
|
10
|
+
*/
|
|
11
|
+
columnDetails?: ColumnDetails;
|
|
12
|
+
/**
|
|
13
|
+
* Additional classes added to the col tag element.
|
|
14
|
+
*/
|
|
15
|
+
className?: string;
|
|
16
|
+
};
|
|
17
|
+
declare const TableCol: ({ columnDetails }: TableColProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export default TableCol;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const TableCol = ({ columnDetails }) => {
|
|
3
|
+
const style = columnDetails?.width
|
|
4
|
+
? {
|
|
5
|
+
minWidth: columnDetails.width,
|
|
6
|
+
width: columnDetails.width,
|
|
7
|
+
}
|
|
8
|
+
: {};
|
|
9
|
+
return _jsx("col", { style: style });
|
|
10
|
+
};
|
|
11
|
+
export default TableCol;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { PropsWithChildren } from 'react';
|
|
2
|
+
type TableHeadProps = {
|
|
3
|
+
/**
|
|
4
|
+
* The unique name of the column used as identifier
|
|
5
|
+
*/
|
|
6
|
+
column?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The label that shall be rendered in the table head next to the sorting icons.
|
|
9
|
+
*/
|
|
10
|
+
label?: string | React.ReactElement;
|
|
11
|
+
/**
|
|
12
|
+
* The string title of a column used as native title attribute on the th tag.
|
|
13
|
+
*/
|
|
14
|
+
title?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The sorting key stored as data attribute for later usage for click events.
|
|
17
|
+
*/
|
|
18
|
+
sortBy?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The column sorting direction.
|
|
21
|
+
*/
|
|
22
|
+
sortDir?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The click handler for the th tag.
|
|
25
|
+
*/
|
|
26
|
+
onClick?: (event: React.MouseEvent<HTMLTableCellElement>) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Additional class names assigned to the wrapper element.
|
|
29
|
+
*/
|
|
30
|
+
className?: string;
|
|
31
|
+
};
|
|
32
|
+
declare const TableHead: (props: PropsWithChildren<TableHeadProps>) => import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export default TableHead;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import SortArrows from './SortArrows';
|
|
4
|
+
const TableHead = (props) => {
|
|
5
|
+
const { column, title, label, sortBy, sortDir, onClick = () => { }, className = '', children } = props;
|
|
6
|
+
const tableHeadClassNames = classNames('user-select-none', 'sort-column', className);
|
|
7
|
+
const labelString = typeof label === 'string' ? label : '';
|
|
8
|
+
const thTitle = title ?? labelString;
|
|
9
|
+
return (_jsxs("th", { className: tableHeadClassNames, onClick: onClick, "data-field": column, "data-sortby": column, title: thTitle, children: [label && (_jsxs("span", { children: [column !== undefined && sortBy === column ? _jsx(SortArrows, { direction: sortDir }) : _jsx(SortArrows, {}), _jsx("span", { children: label })] })), children] }));
|
|
10
|
+
};
|
|
11
|
+
export default TableHead;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { useState, useEffect, useRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import isEqual from 'lodash/fp/isEqual';
|
package/components/tag/Tag.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
const Tag = forwardRef((props, ref) => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { type Props as InputMaskProps } from 'react-input-mask';
|
|
3
2
|
export type TimePickerProps = {
|
|
4
3
|
/**
|
|
5
4
|
* Value of the time as string. Note, when value is given the component is treated as controlled.
|
|
@@ -40,7 +39,7 @@ export type TimePickerProps = {
|
|
|
40
39
|
/**
|
|
41
40
|
* Additional properties to be set on the input element.
|
|
42
41
|
*/
|
|
43
|
-
inputProps?: Omit<
|
|
42
|
+
inputProps?: Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'>;
|
|
44
43
|
/**
|
|
45
44
|
* Additional classes to be set on the wrapper element.
|
|
46
45
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import
|
|
3
|
+
import { IMask, IMaskInput } from 'react-imask';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import isNil from 'lodash/fp/isNil';
|
|
6
6
|
import isEmpty from 'lodash/fp/isEmpty';
|
|
@@ -8,7 +8,7 @@ import moment from 'moment';
|
|
|
8
8
|
import noop from 'lodash/fp/noop';
|
|
9
9
|
import invariant from 'tiny-invariant';
|
|
10
10
|
const MINUTES_OFFSET = 15;
|
|
11
|
-
const mask =
|
|
11
|
+
const mask = '00:00';
|
|
12
12
|
const fullRegexp = /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/;
|
|
13
13
|
const getPadded = (value) => (value >= 10 ? `${value}` : `0${value}`);
|
|
14
14
|
const formatTimeString = (hours, minutes) => `${getPadded(hours)}:${getPadded(minutes)}`;
|
|
@@ -39,11 +39,23 @@ const TimePicker = (props) => {
|
|
|
39
39
|
onChange(value);
|
|
40
40
|
}
|
|
41
41
|
}, [value]);
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
42
|
+
const handleFocus = (event) => {
|
|
43
|
+
const input = event.target;
|
|
44
|
+
// Check if value is empty or partially filled
|
|
45
|
+
if (!input.value || input.value.startsWith('-')) {
|
|
46
|
+
// Move cursor to the first empty position (usually 0)
|
|
47
|
+
// Timeout needed to wait for IMask internal focus handling
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
input.setSelectionRange(0, 0);
|
|
50
|
+
}, 0);
|
|
51
|
+
}
|
|
52
|
+
// If you want to preserve custom onFocus from props
|
|
53
|
+
inputProps.onFocus?.(event);
|
|
54
|
+
};
|
|
55
|
+
const handleAcceptTime = (val, maskRef) => {
|
|
56
|
+
setTimeValue(val);
|
|
57
|
+
if (maskRef.masked.isComplete) {
|
|
58
|
+
onChange(val);
|
|
47
59
|
}
|
|
48
60
|
};
|
|
49
61
|
const isValid = isTimeValid(timeValue);
|
|
@@ -67,6 +79,21 @@ const TimePicker = (props) => {
|
|
|
67
79
|
};
|
|
68
80
|
const { className: inputClassName, ...otherInputProps } = inputProps;
|
|
69
81
|
const hasFeedback = errorMessage || warningMessage;
|
|
70
|
-
return (_jsxs("div", { ...remainingProps, className: classNames('TimePicker', 'input-group', className), children: [showIcon && (_jsx("span", { className: 'input-group-addon', children: _jsx("span", { className: 'rioglyph rioglyph-time-alt' }) })), _jsxs("div", { className: 'form-control-feedback-wrapper', children: [_jsx(
|
|
82
|
+
return (_jsxs("div", { ...remainingProps, className: classNames('TimePicker', 'input-group', className), children: [showIcon && (_jsx("span", { className: 'input-group-addon', children: _jsx("span", { className: 'rioglyph rioglyph-time-alt' }) })), _jsxs("div", { className: 'form-control-feedback-wrapper', children: [_jsx(IMaskInput, { ...otherInputProps, className: classNames('TimePickerInput', 'form-control', inputClassName),
|
|
83
|
+
// mask={mask}
|
|
84
|
+
mask: 'HH:MM', blocks: {
|
|
85
|
+
HH: {
|
|
86
|
+
mask: IMask.MaskedRange,
|
|
87
|
+
from: 0,
|
|
88
|
+
to: 23,
|
|
89
|
+
maxLength: 2,
|
|
90
|
+
},
|
|
91
|
+
MM: {
|
|
92
|
+
mask: IMask.MaskedRange,
|
|
93
|
+
from: 0,
|
|
94
|
+
to: 59,
|
|
95
|
+
maxLength: 2,
|
|
96
|
+
},
|
|
97
|
+
}, value: timeValue, onAccept: handleAcceptTime, onFocus: handleFocus, lazy: !alwaysShowMask, placeholderChar: '-', overwrite: true }), hasFeedback && (_jsxs(_Fragment, { children: [errorMessage && _jsx("span", { className: 'form-control-feedback rioglyph rioglyph-error-sign' }), warningMessage && _jsx("span", { className: 'form-control-feedback rioglyph rioglyph-warning-sign' }), _jsx("span", { className: `help-block white-space-${messageWhiteSpace}`, children: _jsx("span", { children: errorMessage || warningMessage }) })] }))] }), isValid && (_jsxs("div", { className: 'TimePickerIncreaseButton input-group-addon', children: [_jsx("div", { className: 'text-color-gray hover-text-color-dark display-grid place-items-center cursor-pointer', onClick: handleDecrease, children: _jsx("div", { className: 'rioglyph rioglyph-chevron-left scale-90' }) }), _jsx("div", { className: 'text-color-gray hover-text-color-dark margin-left-5 display-grid place-items-center cursor-pointer', onClick: handleIncrease, children: _jsx("div", { className: 'rioglyph rioglyph-chevron-right scale-90' }) })] }))] }));
|
|
71
98
|
};
|
|
72
99
|
export default TimePicker;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
//
|
|
2
|
+
// biome-ignore lint/style/useImportType: required for JSX runtime compatibility with older toolchains
|
|
3
3
|
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
4
4
|
import VirtualListItemWrapper from './VirtualListItemWrapper';
|
|
5
5
|
import useWindowResize from '../../hooks/useWindowResize';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type LocationSuggestion = {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
};
|
|
5
|
+
export type LocationFetchOptions = Record<string, unknown> & {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
fetchUrl?: string;
|
|
8
|
+
limit?: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Custom React hook for fetching location suggestions using HERE Maps Autocomplete API.
|
|
12
|
+
*
|
|
13
|
+
* @param query - The user input string to search for location suggestions.
|
|
14
|
+
* @param options - Optional configuration:
|
|
15
|
+
* - apiKey: Your HERE Maps API key (default is 'YOUR_API_KEY').
|
|
16
|
+
* - fetchUrl: Optional override for the autocomplete endpoint URL.
|
|
17
|
+
* @returns An object containing:
|
|
18
|
+
* - suggestions: Array of location suggestions with `id` and `label`.
|
|
19
|
+
* - loading: Boolean indicating whether the fetch is in progress.
|
|
20
|
+
* - error: Any error that occurred during fetching.
|
|
21
|
+
*/
|
|
22
|
+
declare const useLocationSuggestions: (query: string, options?: LocationFetchOptions) => {
|
|
23
|
+
suggestions: LocationSuggestion[];
|
|
24
|
+
loading: boolean;
|
|
25
|
+
error: Error | null;
|
|
26
|
+
};
|
|
27
|
+
export default useLocationSuggestions;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import debounce from 'lodash/fp/debounce';
|
|
3
|
+
const DEFAULT_URL = 'https://autocomplete.search.hereapi.com/v1/autocomplete';
|
|
4
|
+
const fetchLocationSuggestions = async (query, signal, options = {}) => {
|
|
5
|
+
const { apiKey, fetchUrl = DEFAULT_URL, limit = 5, ...restOptions } = options;
|
|
6
|
+
if (!query || !apiKey) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
const params = new URLSearchParams({
|
|
10
|
+
q: query,
|
|
11
|
+
apiKey,
|
|
12
|
+
limit: String(limit),
|
|
13
|
+
// Add any additional options dynamically
|
|
14
|
+
...restOptions,
|
|
15
|
+
});
|
|
16
|
+
const response = await fetch(`${fetchUrl}?${params.toString()}`, { signal });
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
// Throw an error for bad responses (4xx, 5xx)
|
|
19
|
+
// This allows the hook's catch block to handle API errors
|
|
20
|
+
throw new Error(`API request failed with status ${response.status}`);
|
|
21
|
+
}
|
|
22
|
+
const data = await response.json();
|
|
23
|
+
// Ensure data.items exists and is an array before mapping
|
|
24
|
+
return Array.isArray(data?.items)
|
|
25
|
+
? data.items.map((item) => ({
|
|
26
|
+
id: item.id,
|
|
27
|
+
label: item.title,
|
|
28
|
+
}))
|
|
29
|
+
: [];
|
|
30
|
+
};
|
|
31
|
+
const FETCH_DEBOUNCE_IN_MS = 300;
|
|
32
|
+
/**
|
|
33
|
+
* Custom React hook for fetching location suggestions using HERE Maps Autocomplete API.
|
|
34
|
+
*
|
|
35
|
+
* @param query - The user input string to search for location suggestions.
|
|
36
|
+
* @param options - Optional configuration:
|
|
37
|
+
* - apiKey: Your HERE Maps API key (default is 'YOUR_API_KEY').
|
|
38
|
+
* - fetchUrl: Optional override for the autocomplete endpoint URL.
|
|
39
|
+
* @returns An object containing:
|
|
40
|
+
* - suggestions: Array of location suggestions with `id` and `label`.
|
|
41
|
+
* - loading: Boolean indicating whether the fetch is in progress.
|
|
42
|
+
* - error: Any error that occurred during fetching.
|
|
43
|
+
*/
|
|
44
|
+
const useLocationSuggestions = (query, options = {}) => {
|
|
45
|
+
const [suggestions, setSuggestions] = useState([]);
|
|
46
|
+
const [loading, setLoading] = useState(false);
|
|
47
|
+
const [error, setError] = useState(null);
|
|
48
|
+
const abortRef = useRef(null);
|
|
49
|
+
// React re-renders the component every time state or props change. If we define the debounce() call
|
|
50
|
+
// directly inside the component without useRef, we'll create a new debounced function on every render,
|
|
51
|
+
// which defeats the purpose of debouncing.
|
|
52
|
+
// By wrapping it in useRef, we ensure the debounced function is created only once and persists between renders
|
|
53
|
+
const debouncedFetch = useRef(debounce(FETCH_DEBOUNCE_IN_MS, async (currentQuery, currentOptions) => {
|
|
54
|
+
// Abort any ongoing request from previous calls
|
|
55
|
+
abortRef.current?.abort();
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
abortRef.current = controller;
|
|
58
|
+
// Reset error before a new fetch attempt
|
|
59
|
+
setError(null);
|
|
60
|
+
try {
|
|
61
|
+
const results = await fetchLocationSuggestions(currentQuery, controller.signal, currentOptions);
|
|
62
|
+
setSuggestions(results);
|
|
63
|
+
}
|
|
64
|
+
catch (fetchError) {
|
|
65
|
+
if (fetchError.name !== 'AbortError') {
|
|
66
|
+
setError(fetchError);
|
|
67
|
+
}
|
|
68
|
+
setSuggestions([]);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
setLoading(false);
|
|
72
|
+
}
|
|
73
|
+
})).current;
|
|
74
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!query || !options.apiKey) {
|
|
77
|
+
setSuggestions([]);
|
|
78
|
+
setLoading(false);
|
|
79
|
+
// Abort if there was an ongoing request
|
|
80
|
+
abortRef.current?.abort();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
setLoading(true);
|
|
84
|
+
debouncedFetch(query, options);
|
|
85
|
+
}, [query, debouncedFetch, options.apiKey, options.fetchUrl]); // `debouncedFetch` is stable due to useRef
|
|
86
|
+
// Cleanup on unmount
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
return () => {
|
|
89
|
+
abortRef.current?.abort();
|
|
90
|
+
};
|
|
91
|
+
}, []);
|
|
92
|
+
return { suggestions, loading, error };
|
|
93
|
+
};
|
|
94
|
+
export default useLocationSuggestions;
|
package/hooks/useOnboarding.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type PopoverDOM as DriverPopoverDOM, type State as DriverState, type AllowedButtons } from 'driver.js';
|
|
1
|
+
import { type PopoverDOM as DriverPopoverDOM, type State as DriverState, type AllowedButtons, type DriveStep } from 'driver.js';
|
|
2
2
|
import 'driver.js/dist/driver.css';
|
|
3
3
|
export type PopoverDOM = DriverPopoverDOM;
|
|
4
4
|
export type OnboardingState = DriverState;
|
|
5
|
-
export type OnboardingStep = {
|
|
5
|
+
export type OnboardingStep = DriveStep & {
|
|
6
6
|
element?: string | Element;
|
|
7
7
|
onHighlightStarted?: (element: Element | undefined, step: OnboardingStep, opts: any) => void;
|
|
8
8
|
onHighlighted?: (element: Element | undefined, step: OnboardingStep, opts: any) => void;
|
|
@@ -14,6 +14,7 @@ export type OnboardingStep = {
|
|
|
14
14
|
align?: 'start' | 'center' | 'end';
|
|
15
15
|
showButtons?: ('next' | 'previous' | 'close')[];
|
|
16
16
|
disableButtons?: ('next' | 'previous' | 'close')[];
|
|
17
|
+
disableActiveInteraction?: boolean;
|
|
17
18
|
popoverClass?: string;
|
|
18
19
|
doneBtnText?: string;
|
|
19
20
|
nextBtnText?: string;
|
|
@@ -78,6 +79,13 @@ type OnboardingOptions = {
|
|
|
78
79
|
* Array of buttons to disable. This is useful when you want to show some of the buttons, but disable some of them.
|
|
79
80
|
*/
|
|
80
81
|
disableButtons?: AllowedButtons[];
|
|
82
|
+
/**
|
|
83
|
+
* Whether to disable interaction with the highlighted element.
|
|
84
|
+
* Can be configured at the step level as well.
|
|
85
|
+
*
|
|
86
|
+
* @default false
|
|
87
|
+
*/
|
|
88
|
+
disableActiveInteraction?: boolean;
|
|
81
89
|
/**
|
|
82
90
|
* Option to disable the backdrop. Note, the backdrop element is still there but with 100% opacity
|
|
83
91
|
* and the close on the backdrop is disabled.
|
|
@@ -97,18 +105,22 @@ type OnboardingOptions = {
|
|
|
97
105
|
* @returns
|
|
98
106
|
*/
|
|
99
107
|
onPopoverRender?: (popover: PopoverDOM, state: OnboardingState) => void;
|
|
108
|
+
/**
|
|
109
|
+
* Callback triggered when the onboarding tour is destroyed
|
|
110
|
+
*/
|
|
111
|
+
onDestroyed?: () => void;
|
|
100
112
|
};
|
|
101
113
|
export declare const useOnboardingTour: (params: OnboardingOptions) => {
|
|
102
114
|
run: () => void;
|
|
103
115
|
destroy: () => void;
|
|
104
|
-
onboardingState: () =>
|
|
116
|
+
onboardingState: () => any;
|
|
105
117
|
refresh: () => void;
|
|
106
118
|
isActive: () => boolean;
|
|
107
119
|
moveNext: () => void;
|
|
108
120
|
movePrevious: () => void;
|
|
109
121
|
moveTo: (stepNumber: number) => void;
|
|
110
|
-
hasNextStep: () =>
|
|
111
|
-
hasPreviousStep: () =>
|
|
122
|
+
hasNextStep: () => boolean;
|
|
123
|
+
hasPreviousStep: () => boolean;
|
|
112
124
|
isFirstStep: () => boolean;
|
|
113
125
|
isLastStep: () => boolean;
|
|
114
126
|
getActiveIndex: () => number | undefined;
|
package/hooks/useOnboarding.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { driver, } from 'driver.js';
|
|
2
2
|
import 'driver.js/dist/driver.css';
|
|
3
3
|
export const useOnboardingTour = (params) => {
|
|
4
|
-
|
|
4
|
+
console.log({ params });
|
|
5
|
+
const { steps, prevBtnText = 'Previous', nextBtnText = 'Next', doneBtnText = 'Done', showProgress = true, allowClose = false, stagePadding = 10, stageRadius = 5, allowKeyboardControl = true, showButtons, disableButtons, popoverClass, noBackdrop = false, onPopoverRender = () => { }, onDestroyed = () => { }, ...driverProps } = params;
|
|
5
6
|
const handlePopoverRender = (popover, options) => {
|
|
6
7
|
onPopoverRender(popover, options.state);
|
|
7
8
|
};
|
|
9
|
+
const handleDestroyed = () => {
|
|
10
|
+
onDestroyed();
|
|
11
|
+
};
|
|
8
12
|
const isSingleStep = !steps || steps.length === 1;
|
|
9
13
|
// This configuration is applied to all steps.
|
|
10
14
|
// Driver.js allows also for individual customization for single steps too.
|
|
@@ -25,6 +29,8 @@ export const useOnboardingTour = (params) => {
|
|
|
25
29
|
allowKeyboardControl,
|
|
26
30
|
popoverClass,
|
|
27
31
|
onPopoverRender: handlePopoverRender,
|
|
32
|
+
onDestroyed: handleDestroyed,
|
|
33
|
+
...driverProps,
|
|
28
34
|
});
|
|
29
35
|
return {
|
|
30
36
|
// Use for onboarding tours. Pass in all steps as "steps" parameter for initial configuration.
|
package/hooks/usePostMessage.js
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring the `useSearch` hook.
|
|
3
|
+
*/
|
|
4
|
+
type UseSearchOptions<T> = {
|
|
5
|
+
/**
|
|
6
|
+
* List of object fields to search within. Dot notation (e.g. `'address.city'`) is supported for nested properties.
|
|
7
|
+
* If omitted, all top-level string and number fields will be used.
|
|
8
|
+
*/
|
|
9
|
+
fields?: (keyof T | string)[];
|
|
10
|
+
/**
|
|
11
|
+
* Optional custom filtering function.
|
|
12
|
+
* If provided, this takes precedence over field-based filtering.
|
|
13
|
+
*
|
|
14
|
+
* @param item - The current item in the list.
|
|
15
|
+
* @param query - The current search query string.
|
|
16
|
+
* @returns `true` if the item should be included in the filtered list.
|
|
17
|
+
*/
|
|
18
|
+
customFilter?: (item: T, query: string) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Number of milliseconds to debounce the search input.
|
|
21
|
+
* If omitted, debounce is disabled.
|
|
22
|
+
*/
|
|
23
|
+
debounceMs?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to perform a case-sensitive match.
|
|
26
|
+
* Default is `false` (case-insensitive).
|
|
27
|
+
*
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
caseSensitive?: boolean;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* A hook to filter a list of objects by a search value.
|
|
34
|
+
* Supports field-based filtering, custom filtering logic, debounce, and case sensitivity.
|
|
35
|
+
*
|
|
36
|
+
* @template T - The type of items in the list (must be an object).
|
|
37
|
+
*
|
|
38
|
+
* @param list - The array of objects to search through.
|
|
39
|
+
* @param options - Configuration options for the search behavior.
|
|
40
|
+
* @param options.fields - Fields to search through. If omitted, all top-level string/number fields are used.
|
|
41
|
+
* @param options.customFilter - Optional custom filter function overriding field-based filtering.
|
|
42
|
+
* @param options.debounceMs - Debounce time in milliseconds.
|
|
43
|
+
* @param options.caseSensitive - Whether the search should be case-sensitive.
|
|
44
|
+
*
|
|
45
|
+
* @returns An object containing:
|
|
46
|
+
* - `searchValue`: The current search input string.
|
|
47
|
+
* - `setSearchValue`: A setter function to update the search query.
|
|
48
|
+
* - `filteredList`: The list of items matching the current search query.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const { searchValue, setSearchValue, filteredList } = useSearch(users, {
|
|
53
|
+
* fields: ['name', 'email'],
|
|
54
|
+
* debounceMs: 300,
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare const useSearch: <T extends object>(list: T[], options?: UseSearchOptions<T>) => {
|
|
59
|
+
searchValue: string;
|
|
60
|
+
setSearchValue: import("react").Dispatch<import("react").SetStateAction<string>> | import("lodash").DebouncedFunc<(q: string) => void>;
|
|
61
|
+
filteredList: T[];
|
|
62
|
+
};
|
|
63
|
+
export default useSearch;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useMemo, useState, useCallback } from 'react';
|
|
2
|
+
import { debounce } from 'lodash/fp';
|
|
3
|
+
/**
|
|
4
|
+
* Gets the value of a nested field from an object using dot notation.
|
|
5
|
+
*
|
|
6
|
+
* @param obj - The object to traverse.
|
|
7
|
+
* @param path - The dot-notated path string.
|
|
8
|
+
* @returns The value at the specified path, or undefined.
|
|
9
|
+
*/
|
|
10
|
+
const getNestedValue = (obj, path) => path.split('.').reduce((val, key) => (val ? val[key] : undefined), obj);
|
|
11
|
+
const inferSearchableFields = (item) => Object.keys(item).filter(key => {
|
|
12
|
+
const value = item[key];
|
|
13
|
+
return typeof value === 'string' || typeof value === 'number';
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* A hook to filter a list of objects by a search value.
|
|
17
|
+
* Supports field-based filtering, custom filtering logic, debounce, and case sensitivity.
|
|
18
|
+
*
|
|
19
|
+
* @template T - The type of items in the list (must be an object).
|
|
20
|
+
*
|
|
21
|
+
* @param list - The array of objects to search through.
|
|
22
|
+
* @param options - Configuration options for the search behavior.
|
|
23
|
+
* @param options.fields - Fields to search through. If omitted, all top-level string/number fields are used.
|
|
24
|
+
* @param options.customFilter - Optional custom filter function overriding field-based filtering.
|
|
25
|
+
* @param options.debounceMs - Debounce time in milliseconds.
|
|
26
|
+
* @param options.caseSensitive - Whether the search should be case-sensitive.
|
|
27
|
+
*
|
|
28
|
+
* @returns An object containing:
|
|
29
|
+
* - `searchValue`: The current search input string.
|
|
30
|
+
* - `setSearchValue`: A setter function to update the search query.
|
|
31
|
+
* - `filteredList`: The list of items matching the current search query.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const { searchValue, setSearchValue, filteredList } = useSearch(users, {
|
|
36
|
+
* fields: ['name', 'email'],
|
|
37
|
+
* debounceMs: 300,
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
const useSearch = (list, options = {}) => {
|
|
42
|
+
const [searchValue, _setSearchValue] = useState('');
|
|
43
|
+
// Debounced setter
|
|
44
|
+
const setSearchValue = useCallback(options.debounceMs ? debounce(options.debounceMs, (q) => _setSearchValue(q)) : _setSearchValue, [options.debounceMs]);
|
|
45
|
+
const filteredList = useMemo(() => {
|
|
46
|
+
if (!searchValue) {
|
|
47
|
+
return list;
|
|
48
|
+
}
|
|
49
|
+
if (list.length === 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const isCaseSensitive = options.caseSensitive ?? false;
|
|
53
|
+
const query = isCaseSensitive ? searchValue : searchValue.toLowerCase();
|
|
54
|
+
// Custom filter takes precedence
|
|
55
|
+
if (options.customFilter) {
|
|
56
|
+
return list.filter(item => options.customFilter?.(item, searchValue));
|
|
57
|
+
}
|
|
58
|
+
const fields = options.fields ?? inferSearchableFields(list[0]);
|
|
59
|
+
return list.filter(item => fields.some(field => {
|
|
60
|
+
const value = getNestedValue(item, field.toString());
|
|
61
|
+
if (typeof value === 'string') {
|
|
62
|
+
const target = isCaseSensitive ? value : value.toLowerCase();
|
|
63
|
+
return target.includes(query);
|
|
64
|
+
}
|
|
65
|
+
if (typeof value === 'number') {
|
|
66
|
+
return value.toString().includes(query);
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}));
|
|
70
|
+
}, [list, options, searchValue]);
|
|
71
|
+
return { searchValue, setSearchValue, filteredList };
|
|
72
|
+
};
|
|
73
|
+
export default useSearch;
|
package/hooks/useSorting.d.ts
CHANGED
|
@@ -19,6 +19,12 @@ type UseSortingResult<T> = {
|
|
|
19
19
|
* @returns
|
|
20
20
|
*/
|
|
21
21
|
setSortKey: (newKey: SortKey<T>) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Function to change the sorting order afterwards
|
|
24
|
+
* @param newKey the new sorting key(s)
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
27
|
+
setSortDirection: (newSortDirection: SortDirectionType) => void;
|
|
22
28
|
/**
|
|
23
29
|
* Function to toggle the sorting between ascending and descending order
|
|
24
30
|
* @returns
|