@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.
Files changed (176) hide show
  1. package/README.md +4 -0
  2. package/SvgImage.d.ts +2 -0
  3. package/SvgImage.js +2 -0
  4. package/TableCol.d.ts +2 -0
  5. package/TableCol.js +2 -0
  6. package/TableHead.d.ts +2 -0
  7. package/TableHead.js +2 -0
  8. package/components/actionBarItem/ActionBarItemIcon.js +1 -1
  9. package/components/actionBarItem/ActionBarOverlay.js +1 -1
  10. package/components/applicationHeader/CollapsedNavItem.js +1 -0
  11. package/components/assetTree/Tree.d.ts +8 -0
  12. package/components/assetTree/Tree.js +4 -2
  13. package/components/assetTree/TreeLeaf.js +1 -1
  14. package/components/assetTree/TreeSearch.js +1 -1
  15. package/components/assetTree/TreeSummary.js +1 -1
  16. package/components/assetTree/TypeCounter.d.ts +2 -0
  17. package/components/assetTree/TypeCounter.js +1 -1
  18. package/components/autosuggest/AutoSuggest.js +2 -1
  19. package/components/banner/Banner.d.ts +6 -0
  20. package/components/banner/Banner.js +33 -8
  21. package/components/button/ButtonToolbar.d.ts +1 -1
  22. package/components/button/ButtonToolbar.js +1 -1
  23. package/components/button/ToggleButton.js +0 -1
  24. package/components/clearableInput/ClearableInput.d.ts +20 -7
  25. package/components/clearableInput/ClearableInput.js +68 -8
  26. package/components/dialog/Dialog.js +1 -1
  27. package/components/dialog/FrameDialog.js +1 -1
  28. package/components/dropdown/ButtonDropdown.d.ts +11 -3
  29. package/components/dropdown/ButtonDropdown.js +79 -64
  30. package/components/dropdown/DropdownToggleButton.d.ts +7 -4
  31. package/components/dropdown/DropdownToggleButton.js +11 -3
  32. package/components/formLabel/FormLabel.js +24 -4
  33. package/components/listMenu/ListMenu.js +8 -4
  34. package/components/map/components/Map.js +1 -1
  35. package/components/map/components/features/basics/InfoBubble.js +1 -1
  36. package/components/map/components/features/layers/overlayLayers/IncidentsLayer.js +1 -1
  37. package/components/mapMarker/SingleMapMarker.js +1 -1
  38. package/components/menuItems/MenuItem.js +1 -1
  39. package/components/notification/Notification.js +1 -1
  40. package/components/overlay/OverlayTrigger.js +1 -1
  41. package/components/selects/BaseSelectDropdown.js +1 -1
  42. package/components/selects/Multiselect.d.ts +8 -0
  43. package/components/selects/Multiselect.js +4 -4
  44. package/components/smoothScrollbars/SmoothScrollbars.js +1 -1
  45. package/components/svgImage/SvgElement.d.ts +8 -0
  46. package/components/svgImage/SvgElement.js +11 -0
  47. package/components/svgImage/SvgImage.d.ts +30 -0
  48. package/components/svgImage/SvgImage.js +20 -0
  49. package/components/svgImage/svgConverter.d.ts +17 -0
  50. package/components/svgImage/svgConverter.js +78 -0
  51. package/components/svgImage/useSvgLoader.d.ts +9 -0
  52. package/components/svgImage/useSvgLoader.js +43 -0
  53. package/components/switch/Switch.d.ts +4 -0
  54. package/components/switch/Switch.js +5 -6
  55. package/components/table/TableCardsSorting.d.ts +0 -1
  56. package/components/table/TableCol.d.ts +18 -0
  57. package/components/table/TableCol.js +11 -0
  58. package/components/table/TableHead.d.ts +33 -0
  59. package/components/table/TableHead.js +11 -0
  60. package/components/table/TableSettingsDialog.js +1 -1
  61. package/components/tag/Tag.js +1 -1
  62. package/components/timepicker/TimePicker.d.ts +1 -2
  63. package/components/timepicker/TimePicker.js +35 -8
  64. package/components/virtualList/VirtualList.js +1 -1
  65. package/hooks/useLocationSuggestions.d.ts +27 -0
  66. package/hooks/useLocationSuggestions.js +94 -0
  67. package/hooks/useOnboarding.d.ts +17 -5
  68. package/hooks/useOnboarding.js +7 -1
  69. package/hooks/usePostMessage.js +0 -1
  70. package/hooks/useSearch.d.ts +63 -0
  71. package/hooks/useSearch.js +73 -0
  72. package/hooks/useSorting.d.ts +6 -0
  73. package/hooks/useSorting.js +7 -4
  74. package/hooks/useTableSelection.d.ts +151 -0
  75. package/hooks/useTableSelection.js +196 -0
  76. package/lib/es/SvgImage.d.ts +2 -0
  77. package/lib/es/SvgImage.js +7 -0
  78. package/lib/es/TableCol.d.ts +2 -0
  79. package/lib/es/TableCol.js +7 -0
  80. package/lib/es/TableHead.d.ts +2 -0
  81. package/lib/es/TableHead.js +7 -0
  82. package/lib/es/components/actionBarItem/ActionBarItemIcon.js +1 -1
  83. package/lib/es/components/actionBarItem/ActionBarOverlay.js +1 -1
  84. package/lib/es/components/applicationHeader/CollapsedNavItem.js +1 -0
  85. package/lib/es/components/assetTree/Tree.d.ts +8 -0
  86. package/lib/es/components/assetTree/Tree.js +4 -2
  87. package/lib/es/components/assetTree/TreeLeaf.js +1 -1
  88. package/lib/es/components/assetTree/TreeSearch.js +1 -1
  89. package/lib/es/components/assetTree/TreeSummary.js +1 -1
  90. package/lib/es/components/assetTree/TypeCounter.d.ts +2 -0
  91. package/lib/es/components/assetTree/TypeCounter.js +1 -1
  92. package/lib/es/components/autosuggest/AutoSuggest.js +2 -1
  93. package/lib/es/components/banner/Banner.d.ts +6 -0
  94. package/lib/es/components/banner/Banner.js +31 -6
  95. package/lib/es/components/button/ButtonToolbar.d.ts +1 -1
  96. package/lib/es/components/button/ButtonToolbar.js +1 -1
  97. package/lib/es/components/button/ToggleButton.js +0 -1
  98. package/lib/es/components/clearableInput/ClearableInput.d.ts +20 -7
  99. package/lib/es/components/clearableInput/ClearableInput.js +67 -7
  100. package/lib/es/components/dialog/Dialog.js +1 -1
  101. package/lib/es/components/dialog/FrameDialog.js +1 -1
  102. package/lib/es/components/dropdown/ButtonDropdown.d.ts +11 -3
  103. package/lib/es/components/dropdown/ButtonDropdown.js +79 -64
  104. package/lib/es/components/dropdown/DropdownToggleButton.d.ts +7 -4
  105. package/lib/es/components/dropdown/DropdownToggleButton.js +11 -3
  106. package/lib/es/components/formLabel/FormLabel.js +24 -4
  107. package/lib/es/components/listMenu/ListMenu.js +7 -3
  108. package/lib/es/components/map/components/Map.js +1 -1
  109. package/lib/es/components/map/components/features/basics/InfoBubble.js +1 -1
  110. package/lib/es/components/map/components/features/layers/overlayLayers/IncidentsLayer.js +1 -1
  111. package/lib/es/components/mapMarker/SingleMapMarker.js +1 -1
  112. package/lib/es/components/menuItems/MenuItem.js +1 -1
  113. package/lib/es/components/notification/Notification.js +1 -1
  114. package/lib/es/components/overlay/OverlayTrigger.js +1 -1
  115. package/lib/es/components/selects/BaseSelectDropdown.js +1 -1
  116. package/lib/es/components/selects/Multiselect.d.ts +8 -0
  117. package/lib/es/components/selects/Multiselect.js +4 -4
  118. package/lib/es/components/smoothScrollbars/SmoothScrollbars.js +1 -1
  119. package/lib/es/components/svgImage/SvgElement.d.ts +8 -0
  120. package/lib/es/components/svgImage/SvgElement.js +14 -0
  121. package/lib/es/components/svgImage/SvgImage.d.ts +30 -0
  122. package/lib/es/components/svgImage/SvgImage.js +25 -0
  123. package/lib/es/components/svgImage/svgConverter.d.ts +17 -0
  124. package/lib/es/components/svgImage/svgConverter.js +84 -0
  125. package/lib/es/components/svgImage/useSvgLoader.d.ts +9 -0
  126. package/lib/es/components/svgImage/useSvgLoader.js +48 -0
  127. package/lib/es/components/switch/Switch.d.ts +4 -0
  128. package/lib/es/components/switch/Switch.js +5 -6
  129. package/lib/es/components/table/TableCardsSorting.d.ts +0 -1
  130. package/lib/es/components/table/TableCol.d.ts +18 -0
  131. package/lib/es/components/table/TableCol.js +13 -0
  132. package/lib/es/components/table/TableHead.d.ts +33 -0
  133. package/lib/es/components/table/TableHead.js +14 -0
  134. package/lib/es/components/table/TableSettingsDialog.js +1 -1
  135. package/lib/es/components/tag/Tag.js +1 -1
  136. package/lib/es/components/timepicker/TimePicker.d.ts +1 -2
  137. package/lib/es/components/timepicker/TimePicker.js +35 -8
  138. package/lib/es/components/virtualList/VirtualList.js +1 -1
  139. package/lib/es/hooks/useLocationSuggestions.d.ts +27 -0
  140. package/lib/es/hooks/useLocationSuggestions.js +97 -0
  141. package/lib/es/hooks/useOnboarding.d.ts +17 -5
  142. package/lib/es/hooks/useOnboarding.js +7 -1
  143. package/lib/es/hooks/usePostMessage.js +0 -1
  144. package/lib/es/hooks/useSearch.d.ts +63 -0
  145. package/lib/es/hooks/useSearch.js +75 -0
  146. package/lib/es/hooks/useSorting.d.ts +6 -0
  147. package/lib/es/hooks/useSorting.js +7 -4
  148. package/lib/es/hooks/useTableSelection.d.ts +151 -0
  149. package/lib/es/hooks/useTableSelection.js +205 -0
  150. package/lib/es/themes/Volkswagen/components/applicationHeader/VolkswagenApplicationHeader.js +1 -1
  151. package/lib/es/useLocationSuggestions.d.ts +2 -0
  152. package/lib/es/useLocationSuggestions.js +7 -0
  153. package/lib/es/useSearch.d.ts +2 -0
  154. package/lib/es/useSearch.js +7 -0
  155. package/lib/es/useTableSelection.d.ts +2 -0
  156. package/lib/es/useTableSelection.js +7 -0
  157. package/lib/es/utils/storageUtils.d.ts +2 -2
  158. package/lib/es/utils/storageUtils.js +2 -0
  159. package/lib/es/utils/urlFeatureToggles.d.ts +12 -6
  160. package/lib/es/utils/urlFeatureToggles.js +14 -8
  161. package/lib/es/utils/useDropDirection.js +1 -0
  162. package/lib/es/version.json +1 -1
  163. package/package.json +36 -39
  164. package/themes/Volkswagen/components/applicationHeader/VolkswagenApplicationHeader.js +1 -1
  165. package/useLocationSuggestions.d.ts +2 -0
  166. package/useLocationSuggestions.js +2 -0
  167. package/useSearch.d.ts +2 -0
  168. package/useSearch.js +2 -0
  169. package/useTableSelection.d.ts +2 -0
  170. package/useTableSelection.js +2 -0
  171. package/utils/storageUtils.d.ts +2 -2
  172. package/utils/storageUtils.js +2 -0
  173. package/utils/urlFeatureToggles.d.ts +12 -6
  174. package/utils/urlFeatureToggles.js +10 -7
  175. package/utils/useDropDirection.js +1 -0
  176. 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
- // @ts-ignore-next-line importsNotUsedAsValues
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: 'uikit-switch', 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] }) }));
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';
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  type TableCardsSortingOption = {
3
2
  /**
4
3
  * ID to use for the select option.
@@ -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
- // @ts-ignore-next-line importsNotUsedAsValues
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';
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- // @ts-ignore-next-line importsNotUsedAsValues
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<InputMaskProps, 'mask' | 'maskPlaceholder' | 'value' | 'onChange' | 'alwaysShowMask'>;
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 InputMask from 'react-input-mask';
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 = [/[0-2]/, /[0-9]/, ':', /[0-5]/, /[0-9]/];
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 handleChangeTime = (event) => {
43
- const currentValue = event.target.value;
44
- setTimeValue(currentValue);
45
- if (fullRegexp.test(currentValue)) {
46
- onChange(currentValue);
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(InputMask, { ...otherInputProps, className: classNames('TimePickerInput', 'form-control', inputClassName), mask: mask, maskPlaceholder: '-', value: timeValue, onChange: handleChangeTime, alwaysShowMask: alwaysShowMask }), 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' }) })] }))] }));
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
- // @ts-ignore-next-line importsNotUsedAsValues
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;
@@ -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: () => DriverState;
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: () => false | import("driver.js").DriveStep;
111
- hasPreviousStep: () => false | import("driver.js").DriveStep;
122
+ hasNextStep: () => boolean;
123
+ hasPreviousStep: () => boolean;
112
124
  isFirstStep: () => boolean;
113
125
  isLastStep: () => boolean;
114
126
  getActiveIndex: () => number | undefined;
@@ -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
- const { steps, prevBtnText = 'Previous', nextBtnText = 'Next', doneBtnText = 'Done', showProgress = true, allowClose = false, stagePadding = 10, stageRadius = 5, allowKeyboardControl = true, showButtons, disableButtons, popoverClass, noBackdrop = false, onPopoverRender = () => { }, } = params;
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.
@@ -33,7 +33,6 @@ const usePostMessage = (messagePrefix, onReceiveMessage) => {
33
33
  if (!actionType) {
34
34
  return;
35
35
  }
36
- console.log(event);
37
36
  if (actionType.startsWith(messagePrefix)) {
38
37
  callback(event.data);
39
38
  }
@@ -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;
@@ -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