@ultraviolet/ui 1.55.3 → 1.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +4 -3
  2. package/dist/components/Alert/index.cjs +1 -2
  3. package/dist/components/Alert/index.js +1 -2
  4. package/dist/components/Avatar/index.cjs +4 -5
  5. package/dist/components/Avatar/index.js +4 -5
  6. package/dist/components/Banner/index.cjs +1 -2
  7. package/dist/components/Banner/index.js +1 -2
  8. package/dist/components/Bullet/index.d.ts +1 -1
  9. package/dist/components/Button/index.d.ts +14 -14
  10. package/dist/components/Checkbox/index.cjs +1 -2
  11. package/dist/components/Checkbox/index.js +1 -2
  12. package/dist/components/Dialog/Context.d.ts +0 -1
  13. package/dist/components/Dialog/index.d.ts +46 -46
  14. package/dist/components/Dialog/subComponents/Text.d.ts +0 -1
  15. package/dist/components/Expandable/index.d.ts +2 -2
  16. package/dist/components/GlobalAlert/GlobalAlertLink.d.ts +1 -1
  17. package/dist/components/GlobalAlert/index.cjs +1 -2
  18. package/dist/components/GlobalAlert/index.d.ts +1 -17
  19. package/dist/components/GlobalAlert/index.js +1 -2
  20. package/dist/components/LineChart/helpers.cjs +5 -10
  21. package/dist/components/LineChart/helpers.js +5 -10
  22. package/dist/components/Link/index.cjs +2 -4
  23. package/dist/components/Link/index.js +2 -4
  24. package/dist/components/List/Cell.cjs +1 -1
  25. package/dist/components/List/Cell.d.ts +2 -0
  26. package/dist/components/List/Cell.js +1 -1
  27. package/dist/components/List/Row.cjs +4 -4
  28. package/dist/components/List/Row.d.ts +2 -2
  29. package/dist/components/List/Row.js +4 -4
  30. package/dist/components/List/constants.cjs +1 -1
  31. package/dist/components/List/constants.d.ts +1 -1
  32. package/dist/components/List/constants.js +1 -1
  33. package/dist/components/List/index.d.ts +9 -9
  34. package/dist/components/Menu/index.d.ts +4 -4
  35. package/dist/components/MenuV2/index.d.ts +41 -36
  36. package/dist/components/Modal/Dialog.d.ts +0 -1
  37. package/dist/components/Modal/Disclosure.d.ts +0 -1
  38. package/dist/components/NumberInput/index.cjs +6 -12
  39. package/dist/components/NumberInput/index.js +6 -12
  40. package/dist/components/NumberInputV2/index.cjs +23 -17
  41. package/dist/components/NumberInputV2/index.d.ts +23 -12
  42. package/dist/components/NumberInputV2/index.js +23 -17
  43. package/dist/components/Popover/index.d.ts +35 -30
  44. package/dist/components/Popup/index.cjs +4 -8
  45. package/dist/components/Popup/index.js +4 -8
  46. package/dist/components/Row/index.d.ts +2 -2
  47. package/dist/components/SearchInput/index.cjs +100 -0
  48. package/dist/components/SearchInput/index.d.ts +36 -0
  49. package/dist/components/SearchInput/index.js +98 -0
  50. package/dist/components/SearchInput/types.d.ts +17 -0
  51. package/dist/components/SelectInput/index.cjs +4 -8
  52. package/dist/components/SelectInput/index.js +4 -8
  53. package/dist/components/SelectInputV2/SelectBar.cjs +8 -6
  54. package/dist/components/SelectInputV2/SelectBar.d.ts +3 -1
  55. package/dist/components/SelectInputV2/SelectBar.js +8 -6
  56. package/dist/components/SelectInputV2/index.cjs +6 -5
  57. package/dist/components/SelectInputV2/index.d.ts +1 -1
  58. package/dist/components/SelectInputV2/index.js +6 -5
  59. package/dist/components/SelectableCard/index.cjs +4 -4
  60. package/dist/components/SelectableCard/index.d.ts +1 -2
  61. package/dist/components/SelectableCard/index.js +4 -4
  62. package/dist/components/SelectableCardGroup/index.cjs +2 -2
  63. package/dist/components/SelectableCardGroup/index.d.ts +1 -1
  64. package/dist/components/SelectableCardGroup/index.js +2 -2
  65. package/dist/components/Skeleton/IconSkeleton.d.ts +2 -3
  66. package/dist/components/Skeleton/Line.d.ts +2 -3
  67. package/dist/components/Skeleton/Square.d.ts +2 -3
  68. package/dist/components/Skeleton/index.d.ts +13 -14
  69. package/dist/components/Stack/index.d.ts +2 -2
  70. package/dist/components/Status/index.d.ts +1 -1
  71. package/dist/components/Stepper/Step.cjs +38 -20
  72. package/dist/components/Stepper/Step.js +38 -20
  73. package/dist/components/Stepper/index.cjs +9 -11
  74. package/dist/components/Stepper/index.d.ts +5 -8
  75. package/dist/components/Stepper/index.js +9 -11
  76. package/dist/components/SwitchButton/FocusOverlay.cjs +1 -2
  77. package/dist/components/SwitchButton/FocusOverlay.js +1 -2
  78. package/dist/components/SwitchButton/index.cjs +1 -2
  79. package/dist/components/SwitchButton/index.js +1 -2
  80. package/dist/components/Table/index.d.ts +8 -8
  81. package/dist/components/Tabs/Tab.cjs +1 -2
  82. package/dist/components/Tabs/Tab.d.ts +2 -2
  83. package/dist/components/Tabs/Tab.js +1 -2
  84. package/dist/components/Tabs/TabMenu.d.ts +2 -2
  85. package/dist/components/Tabs/TabMenuItem.d.ts +5 -5
  86. package/dist/components/Tabs/TabsContext.d.ts +0 -1
  87. package/dist/components/Tabs/index.cjs +1 -2
  88. package/dist/components/Tabs/index.d.ts +16 -16
  89. package/dist/components/Tabs/index.js +1 -2
  90. package/dist/components/TagInput/index.cjs +15 -11
  91. package/dist/components/TagInput/index.js +15 -11
  92. package/dist/components/Text/index.d.ts +1 -1
  93. package/dist/components/TextInput/index.d.ts +1 -1
  94. package/dist/components/TextInputV2/index.cjs +9 -9
  95. package/dist/components/TextInputV2/index.d.ts +17 -15
  96. package/dist/components/TextInputV2/index.js +9 -9
  97. package/dist/components/Toggle/index.cjs +2 -4
  98. package/dist/components/Toggle/index.d.ts +11 -11
  99. package/dist/components/Toggle/index.js +2 -4
  100. package/dist/components/VerificationCode/index.cjs +3 -3
  101. package/dist/components/VerificationCode/index.js +3 -3
  102. package/dist/components/index.d.ts +9 -8
  103. package/dist/helpers/recursivelyGetChildrenString.cjs +3 -6
  104. package/dist/helpers/recursivelyGetChildrenString.js +3 -6
  105. package/dist/index.cjs +119 -117
  106. package/dist/index.js +10 -8
  107. package/dist/mocks/list.d.ts +1 -1
  108. package/dist/theme/index.d.ts +31 -799
  109. package/dist/utils/responsive/Breakpoint.d.ts +5 -5
  110. package/dist/utils/responsive/utilities.cjs +2 -4
  111. package/dist/utils/responsive/utilities.js +2 -4
  112. package/package.json +5 -5
@@ -1,5 +1,10 @@
1
1
  import type { ReactNode, Ref } from 'react';
2
2
  type SentimentType = 'neutral' | 'primary';
3
+ declare const SIZES_WIDTH: {
4
+ small: number;
5
+ medium: number;
6
+ large: number;
7
+ };
3
8
  /**
4
9
  * Popover component is used to display additional information or actions on top of the main content of the page.
5
10
  * It is usually triggered by clicking on a button. It includes a title, a close button and a content area.
@@ -8,48 +13,48 @@ export declare const Popover: import("react").ForwardRefExoticComponent<{
8
13
  children: ReactNode;
9
14
  content: ReactNode;
10
15
  title: string;
11
- sentiment?: SentimentType | undefined;
12
- visible?: boolean | undefined;
13
- size?: "large" | "medium" | "small" | undefined;
14
- onClose?: (() => void) | undefined;
15
- className?: string | undefined;
16
- 'data-testid'?: string | undefined;
17
- maxWidth?: string | undefined;
18
- maxHeight?: string | undefined;
16
+ sentiment?: SentimentType;
17
+ visible?: boolean;
18
+ size?: keyof typeof SIZES_WIDTH;
19
+ onClose?: () => void;
20
+ className?: string;
21
+ 'data-testid'?: string;
22
+ maxWidth?: string;
23
+ maxHeight?: string;
19
24
  /**
20
25
  * By default, the portal target is children container or document.body if children is a function. You can override this
21
26
  * behavior by setting a portalTarget prop.
22
27
  */
23
- portalTarget?: HTMLElement | undefined;
28
+ portalTarget?: HTMLElement;
24
29
  } & Pick<{
25
- id?: string | undefined;
30
+ id?: string;
26
31
  children: ReactNode | ((renderProps: {
27
- className?: string | undefined;
32
+ className?: string;
28
33
  onBlur: () => void;
29
34
  onFocus: () => void;
30
35
  onPointerEnter: () => void;
31
36
  onPointerLeave: () => void;
32
37
  ref: import("react").RefObject<HTMLDivElement>;
33
38
  }) => ReactNode);
34
- maxWidth?: string | number | undefined;
35
- placement?: import("../Popup/helpers").PopupPlacement | undefined;
39
+ maxWidth?: number | string;
40
+ placement?: import("../Popup/helpers").PopupPlacement;
36
41
  text?: ReactNode;
37
- className?: string | undefined;
38
- containerFullWidth?: boolean | undefined;
39
- visible?: boolean | undefined;
40
- innerRef?: Ref<HTMLDivElement | null> | undefined;
41
- role?: string | undefined;
42
- 'data-testid'?: string | undefined;
43
- hasArrow?: boolean | undefined;
44
- onClose?: (() => void) | undefined;
45
- tabIndex?: number | undefined;
46
- onKeyDown?: import("react").KeyboardEventHandler | undefined;
47
- 'aria-haspopup'?: boolean | "menu" | "dialog" | "grid" | "listbox" | "tree" | "false" | "true" | undefined;
48
- hideOnClickOutside?: boolean | undefined;
49
- debounceDelay?: number | undefined;
50
- maxHeight?: string | number | undefined;
51
- disableAnimation?: boolean | undefined;
52
- portalTarget?: HTMLElement | undefined;
53
- dynamicDomRendering?: boolean | undefined;
42
+ className?: string;
43
+ containerFullWidth?: boolean;
44
+ visible?: boolean;
45
+ innerRef?: Ref<HTMLDivElement | null>;
46
+ role?: string;
47
+ 'data-testid'?: string;
48
+ hasArrow?: boolean;
49
+ onClose?: () => void;
50
+ tabIndex?: number;
51
+ onKeyDown?: import("react").KeyboardEventHandler;
52
+ 'aria-haspopup'?: import("react").HTMLAttributes<HTMLDivElement>["aria-haspopup"];
53
+ hideOnClickOutside?: boolean;
54
+ debounceDelay?: number;
55
+ maxHeight?: string | number;
56
+ disableAnimation?: boolean;
57
+ portalTarget?: HTMLElement;
58
+ dynamicDomRendering?: boolean;
54
59
  } & import("react").RefAttributes<HTMLDivElement>, "placement" | "dynamicDomRendering"> & import("react").RefAttributes<HTMLDivElement>>;
55
60
  export {};
@@ -98,13 +98,10 @@ const Popup = React.forwardRef(({
98
98
  React.useImperativeHandle(ref, () => innerPopupRef.current);
99
99
  const timer = React.useRef();
100
100
  const popupPortalTarget = React.useMemo(() => {
101
- if (portalTarget)
102
- return portalTarget;
101
+ if (portalTarget) return portalTarget;
103
102
  if (role === "dialog") {
104
- if (childrenRef.current)
105
- return childrenRef.current;
106
- if (typeof window !== "undefined")
107
- return document.body;
103
+ if (childrenRef.current) return childrenRef.current;
104
+ if (typeof window !== "undefined") return document.body;
108
105
  return null;
109
106
  }
110
107
  if (typeof window !== "undefined") {
@@ -286,8 +283,7 @@ const Popup = React.forwardRef(({
286
283
  return false;
287
284
  }, [dynamicDomRendering, visibleInDom]);
288
285
  if (!text) {
289
- if (typeof children === "function")
290
- return null;
286
+ if (typeof children === "function") return null;
291
287
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
292
288
  }
293
289
  const stopClickPropagation = (event) => {
@@ -94,13 +94,10 @@ const Popup = forwardRef(({
94
94
  useImperativeHandle(ref, () => innerPopupRef.current);
95
95
  const timer = useRef();
96
96
  const popupPortalTarget = useMemo(() => {
97
- if (portalTarget)
98
- return portalTarget;
97
+ if (portalTarget) return portalTarget;
99
98
  if (role === "dialog") {
100
- if (childrenRef.current)
101
- return childrenRef.current;
102
- if (typeof window !== "undefined")
103
- return document.body;
99
+ if (childrenRef.current) return childrenRef.current;
100
+ if (typeof window !== "undefined") return document.body;
104
101
  return null;
105
102
  }
106
103
  if (typeof window !== "undefined") {
@@ -282,8 +279,7 @@ const Popup = forwardRef(({
282
279
  return false;
283
280
  }, [dynamicDomRendering, visibleInDom]);
284
281
  if (!text) {
285
- if (typeof children === "function")
286
- return null;
282
+ if (typeof children === "function") return null;
287
283
  return /* @__PURE__ */ jsx(Fragment, { children });
288
284
  }
289
285
  const stopClickPropagation = (event) => {
@@ -2,8 +2,8 @@ import type { CSSProperties, ReactNode } from 'react';
2
2
  import type { UltravioletUITheme } from '../../theme';
3
3
  type StyledRowProps = Pick<RowProps, 'gap' | 'templateColumns' | 'alignItems' | 'justifyContent'>;
4
4
  export declare const StyledRow: import("@emotion/styled").StyledComponent<{
5
- theme?: import("@emotion/react").Theme | undefined;
6
- as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
5
+ theme?: import("@emotion/react").Theme;
6
+ as?: import("react").ElementType;
7
7
  } & StyledRowProps, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
8
8
  type RowProps = {
9
9
  className?: string;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("@emotion/react/jsx-runtime");
4
+ const _styled = require("@emotion/styled/base");
5
+ const icons = require("@ultraviolet/icons");
6
+ const React = require("react");
7
+ const index = require("../Popup/index.cjs");
8
+ const index$1 = require("../TextInputV2/index.cjs");
9
+ const _interopDefaultCompat = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
10
+ const _styled__default = /* @__PURE__ */ _interopDefaultCompat(_styled);
11
+ const StyledPopup = /* @__PURE__ */ _styled__default.default(index.Popup, process.env.NODE_ENV === "production" ? {
12
+ target: "eefux4u0"
13
+ } : {
14
+ target: "eefux4u0",
15
+ label: "StyledPopup"
16
+ })("width:100%;text-align:initial;min-width:610px;padding:", ({
17
+ theme
18
+ }) => `${theme.space["2"]} ${theme.space["1"]}`, ";background:", ({
19
+ theme
20
+ }) => theme.colors.neutral.background, ";box-shadow:", ({
21
+ theme
22
+ }) => theme.shadows.modal, ";" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL3VsdHJhdmlvbGV0L3VsdHJhdmlvbGV0L3BhY2thZ2VzL3VpL3NyYy9jb21wb25lbnRzL1NlYXJjaElucHV0L2luZGV4LnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFRaUMiLCJmaWxlIjoiL2hvbWUvcnVubmVyL3dvcmsvdWx0cmF2aW9sZXQvdWx0cmF2aW9sZXQvcGFja2FnZXMvdWkvc3JjL2NvbXBvbmVudHMvU2VhcmNoSW5wdXQvaW5kZXgudHN4Iiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnXG5pbXBvcnQgeyBJY29uIH0gZnJvbSAnQHVsdHJhdmlvbGV0L2ljb25zJ1xuaW1wb3J0IHR5cGUgeyBSZWYgfSBmcm9tICdyZWFjdCdcbmltcG9ydCB7IGZvcndhcmRSZWYsIHVzZUVmZmVjdCwgdXNlUmVkdWNlciwgdXNlUmVmLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgUG9wdXAgfSBmcm9tICcuLi9Qb3B1cCdcbmltcG9ydCB7IFRleHRJbnB1dFYyIH0gZnJvbSAnLi4vVGV4dElucHV0VjInXG5pbXBvcnQgdHlwZSB7IFNlYXJjaElucHV0UHJvcHMgfSBmcm9tICcuL3R5cGVzJ1xuXG5jb25zdCBTdHlsZWRQb3B1cCA9IHN0eWxlZChQb3B1cClgXG4gIHdpZHRoOiAxMDAlO1xuICB0ZXh0LWFsaWduOiBpbml0aWFsO1xuICBtaW4td2lkdGg6IDYxMHB4O1xuICBwYWRkaW5nOiAkeyh7IHRoZW1lIH0pID0+IGAke3RoZW1lLnNwYWNlWycyJ119ICR7dGhlbWUuc3BhY2VbJzEnXX1gfTtcbiAgYmFja2dyb3VuZDogJHsoeyB0aGVtZSB9KSA9PiB0aGVtZS5jb2xvcnMubmV1dHJhbC5iYWNrZ3JvdW5kfTtcbiAgYm94LXNoYWRvdzogJHsoeyB0aGVtZSB9KSA9PiB0aGVtZS5zaGFkb3dzLm1vZGFsfTtcbmBcblxuLyoqXG4gKiBTZWFyY2hJbnB1dCBpcyBhIGNvbXBvbmVudCB0aGF0IGFsbG93cyB1c2VycyB0byBzZWFyY2ggZm9yIGl0ZW1zLiBJdCBpcyBhIGNvbWJpbmF0aW9uIG9mIGEgVGV4dElucHV0VjIgYW5kIGEgUG9wdXAuIFRoZSBQb3B1cCBpcyB1c2VkIHRvIGRpc3BsYXkgc2VhcmNoIHJlc3VsdHMuXG4gKiBDaGlsZHJlbiBvZiB0aGUgU2VhcmNoSW5wdXQgY29tcG9uZW50IGNhbiBiZSBhIGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgYW4gb2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICogLSBgc2VhcmNoVGVybXNgOiB0aGUgY3VycmVudCBzZWFyY2ggdGVybXNcbiAqIC0gYGlzT3BlbmA6IGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIHRoZSBwb3B1cCBpcyBvcGVuXG4gKiAtIGB0b2dnbGVJc09wZW5gOiBhIGZ1bmN0aW9uIHRvIHRvZ2dsZSB0aGUgcG9wdXBcbiAqL1xuZXhwb3J0IGNvbnN0IFNlYXJjaElucHV0ID0gZm9yd2FyZFJlZihcbiAgKFxuICAgIHtcbiAgICAgIHBsYWNlaG9sZGVyLFxuICAgICAgbGFiZWwsXG4gICAgICBsb2FkaW5nLFxuICAgICAgc2l6ZSxcbiAgICAgIHN1ZmZpeCxcbiAgICAgIHBvcHVwUGxhY2VtZW50LFxuICAgICAgdGhyZXNob2xkID0gMCxcbiAgICAgIGNoaWxkcmVuLFxuICAgICAgb25TZWFyY2gsXG4gICAgICBvbkNsb3NlLFxuICAgICAgJ2RhdGEtdGVzdGlkJzogZGF0YVRlc3RJZCxcbiAgICB9OiBTZWFyY2hJbnB1dFByb3BzLFxuICAgIHJlZjogUmVmPEhUTUxJbnB1dEVsZW1lbnQ+LFxuICApID0+IHtcbiAgICBjb25zdCBmb2N1c2VkTGlua0luZGV4ID0gdXNlUmVmKDApXG4gICAgY29uc3QgcG9wdXBSZWYgPSB1c2VSZWY8SFRNTERpdkVsZW1lbnQ+KG51bGwpXG4gICAgY29uc3QgW2NvbnRhaW5lcldpZHRoLCBzZXRDb250YWluZXJXaWR0aF0gPSB1c2VTdGF0ZSgwKVxuICAgIGNvbnN0IFtzZWFyY2hUZXJtcywgc2V0U2VhcmNoVGVybXNdID0gdXNlU3RhdGUoJycpXG4gICAgY29uc3QgW2lzT3BlbiwgdG9nZ2xlSXNPcGVuXSA9IHVzZVJlZHVjZXIoc3RhdGUgPT4gIXN0YXRlLCBmYWxzZSlcblxuICAgIGNvbnN0IGNvbnRlbnQgPVxuICAgICAgdHlwZW9mIGNoaWxkcmVuID09PSAnZnVuY3Rpb24nXG4gICAgICAgID8gY2hpbGRyZW4oeyBzZWFyY2hUZXJtcywgaXNPcGVuLCB0b2dnbGVJc09wZW4gfSlcbiAgICAgICAgOiBjaGlsZHJlblxuXG4gICAgY29uc3QgcmVzaXplU2VhcmNoQmFyID0gKCkgPT4ge1xuICAgICAgaWYgKHBvcHVwUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgc2V0Q29udGFpbmVyV2lkdGgocG9wdXBSZWYuY3VycmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aClcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBoYW5kbGVOYXZpZ2F0aW9uID0gKGV2ZW50OiBLZXlib2FyZEV2ZW50KSA9PiB7XG4gICAgICBjb25zdCBsaW5rcyA9IFsuLi4ocG9wdXBSZWYuY3VycmVudD8ucXVlcnlTZWxlY3RvckFsbCgnYScpID8/IFtdKV1cblxuICAgICAgaWYgKFxuICAgICAgICBsaW5rcy5sZW5ndGggPiAwICYmXG4gICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA+PSAwICYmXG4gICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA8PSBsaW5rcy5sZW5ndGhcbiAgICAgICkge1xuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSAnQXJyb3dVcCcpIHtcbiAgICAgICAgICBpZiAoZm9jdXNlZExpbmtJbmRleC5jdXJyZW50IC0gMSA8IDApIHtcbiAgICAgICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA9IGxpbmtzLmxlbmd0aCAtIDFcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9jdXNlZExpbmtJbmRleC5jdXJyZW50IC09IDFcbiAgICAgICAgICB9XG4gICAgICAgICAgbGlua3NbZm9jdXNlZExpbmtJbmRleC5jdXJyZW50XT8uZm9jdXMoKVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gJ0Fycm93RG93bicpIHtcbiAgICAgICAgICBpZiAoZm9jdXNlZExpbmtJbmRleC5jdXJyZW50ICsgMSA+PSBsaW5rcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA9IDBcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9jdXNlZExpbmtJbmRleC5jdXJyZW50ICs9IDFcbiAgICAgICAgICB9XG4gICAgICAgICAgbGlua3NbZm9jdXNlZExpbmtJbmRleC5jdXJyZW50XT8uZm9jdXMoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2tleXVwJywgaGFuZGxlTmF2aWdhdGlvbilcblxuICAgICAgcmV0dXJuICgpID0+IGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleXVwJywgaGFuZGxlTmF2aWdhdGlvbilcbiAgICB9LCBbXSlcblxuICAgIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICByZXNpemVTZWFyY2hCYXIoKVxuXG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgcmVzaXplU2VhcmNoQmFyKVxuXG4gICAgICByZXR1cm4gKCkgPT4gd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHJlc2l6ZVNlYXJjaEJhcilcbiAgICB9LCBbXSlcblxuICAgIGNvbnN0IG9uU2VhcmNoQ2FsbGJhY2sgPSAodmFsdWU6IHN0cmluZykgPT4ge1xuICAgICAgc2V0U2VhcmNoVGVybXModmFsdWUpXG5cbiAgICAgIHRyeSB7XG4gICAgICAgIG9uU2VhcmNoKHZhbHVlKVxuICAgICAgICBpZiAodmFsdWUubGVuZ3RoID49IHRocmVzaG9sZCAmJiAhaXNPcGVuKSB7XG4gICAgICAgICAgdG9nZ2xlSXNPcGVuKClcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHRvZ2dsZUlzT3BlbigpXG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3Qgb25DbG9zZUNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgb25DbG9zZT8uKClcbiAgICAgIGlmIChpc09wZW4pIHtcbiAgICAgICAgdG9nZ2xlSXNPcGVuKClcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdj5cbiAgICAgICAgPFN0eWxlZFBvcHVwXG4gICAgICAgICAgZGF0YS10ZXN0aWQ9e2Bwb3B1cC0ke2RhdGFUZXN0SWR9YH1cbiAgICAgICAgICByb2xlPVwiZGlhbG9nXCJcbiAgICAgICAgICB2aXNpYmxlPXtpc09wZW59XG4gICAgICAgICAgb25DbG9zZT17b25DbG9zZUNhbGxiYWNrfVxuICAgICAgICAgIHBsYWNlbWVudD17cG9wdXBQbGFjZW1lbnR9XG4gICAgICAgICAgbWF4V2lkdGg9e2NvbnRhaW5lcldpZHRofVxuICAgICAgICAgIGhpZGVPbkNsaWNrT3V0c2lkZVxuICAgICAgICAgIGhhc0Fycm93PXtmYWxzZX1cbiAgICAgICAgICBpbm5lclJlZj17cG9wdXBSZWZ9XG4gICAgICAgICAgdGV4dD17Y29udGVudH1cbiAgICAgICAgICBtYXhIZWlnaHQ9ezQxMH1cbiAgICAgICAgICBkZWJvdW5jZURlbGF5PXswfVxuICAgICAgICA+XG4gICAgICAgICAgPFRleHRJbnB1dFYyXG4gICAgICAgICAgICByZWY9e3JlZn1cbiAgICAgICAgICAgIHByZWZpeD17PEljb24gbmFtZT1cInNlYXJjaFwiIC8+fVxuICAgICAgICAgICAgc3VmZml4PXtzdWZmaXh9XG4gICAgICAgICAgICBkYXRhLXRlc3RpZD17ZGF0YVRlc3RJZH1cbiAgICAgICAgICAgIHZhbHVlPXtzZWFyY2hUZXJtc31cbiAgICAgICAgICAgIHNpemU9e3NpemV9XG4gICAgICAgICAgICBsYWJlbD17bGFiZWx9XG4gICAgICAgICAgICBwbGFjZWhvbGRlcj17cGxhY2Vob2xkZXJ9XG4gICAgICAgICAgICBsb2FkaW5nPXtsb2FkaW5nfVxuICAgICAgICAgICAgb25DaGFuZ2U9e29uU2VhcmNoQ2FsbGJhY2t9XG4gICAgICAgICAgICBjbGVhcmFibGVcbiAgICAgICAgICAvPlxuICAgICAgICA8L1N0eWxlZFBvcHVwPlxuICAgICAgPC9kaXY+XG4gICAgKVxuICB9LFxuKVxuIl19 */"));
23
+ const SearchInput = React.forwardRef(({
24
+ placeholder,
25
+ label,
26
+ loading,
27
+ size,
28
+ suffix,
29
+ popupPlacement,
30
+ threshold = 0,
31
+ children,
32
+ onSearch,
33
+ onClose,
34
+ "data-testid": dataTestId
35
+ }, ref) => {
36
+ const focusedLinkIndex = React.useRef(0);
37
+ const popupRef = React.useRef(null);
38
+ const [containerWidth, setContainerWidth] = React.useState(0);
39
+ const [searchTerms, setSearchTerms] = React.useState("");
40
+ const [isOpen, toggleIsOpen] = React.useReducer((state) => !state, false);
41
+ const content = typeof children === "function" ? children({
42
+ searchTerms,
43
+ isOpen,
44
+ toggleIsOpen
45
+ }) : children;
46
+ const resizeSearchBar = () => {
47
+ if (popupRef.current) {
48
+ setContainerWidth(popupRef.current.getBoundingClientRect().width);
49
+ }
50
+ };
51
+ const handleNavigation = (event) => {
52
+ const links = [...popupRef.current?.querySelectorAll("a") ?? []];
53
+ if (links.length > 0 && focusedLinkIndex.current >= 0 && focusedLinkIndex.current <= links.length) {
54
+ if (event.key === "ArrowUp") {
55
+ if (focusedLinkIndex.current - 1 < 0) {
56
+ focusedLinkIndex.current = links.length - 1;
57
+ } else {
58
+ focusedLinkIndex.current -= 1;
59
+ }
60
+ links[focusedLinkIndex.current]?.focus();
61
+ }
62
+ if (event.key === "ArrowDown") {
63
+ if (focusedLinkIndex.current + 1 >= links.length) {
64
+ focusedLinkIndex.current = 0;
65
+ } else {
66
+ focusedLinkIndex.current += 1;
67
+ }
68
+ links[focusedLinkIndex.current]?.focus();
69
+ }
70
+ }
71
+ };
72
+ React.useEffect(() => {
73
+ document.addEventListener("keyup", handleNavigation);
74
+ return () => document.removeEventListener("keyup", handleNavigation);
75
+ }, []);
76
+ React.useEffect(() => {
77
+ resizeSearchBar();
78
+ window.addEventListener("resize", resizeSearchBar);
79
+ return () => window.removeEventListener("resize", resizeSearchBar);
80
+ }, []);
81
+ const onSearchCallback = (value) => {
82
+ setSearchTerms(value);
83
+ try {
84
+ onSearch(value);
85
+ if (value.length >= threshold && !isOpen) {
86
+ toggleIsOpen();
87
+ }
88
+ } catch {
89
+ toggleIsOpen();
90
+ }
91
+ };
92
+ const onCloseCallback = () => {
93
+ onClose?.();
94
+ if (isOpen) {
95
+ toggleIsOpen();
96
+ }
97
+ };
98
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(StyledPopup, { "data-testid": `popup-${dataTestId}`, role: "dialog", visible: isOpen, onClose: onCloseCallback, placement: popupPlacement, maxWidth: containerWidth, hideOnClickOutside: true, hasArrow: false, innerRef: popupRef, text: content, maxHeight: 410, debounceDelay: 0, children: /* @__PURE__ */ jsxRuntime.jsx(index$1.TextInputV2, { ref, prefix: /* @__PURE__ */ jsxRuntime.jsx(icons.Icon, { name: "search" }), suffix, "data-testid": dataTestId, value: searchTerms, size, label, placeholder, loading, onChange: onSearchCallback, clearable: true }) }) });
99
+ });
100
+ exports.SearchInput = SearchInput;
@@ -0,0 +1,36 @@
1
+ import { Popup } from '../Popup';
2
+ /**
3
+ * SearchInput is a component that allows users to search for items. It is a combination of a TextInputV2 and a Popup. The Popup is used to display search results.
4
+ * Children of the SearchInput component can be a function that receives an object with the following properties:
5
+ * - `searchTerms`: the current search terms
6
+ * - `isOpen`: a boolean indicating if the popup is open
7
+ * - `toggleIsOpen`: a function to toggle the popup
8
+ */
9
+ export declare const SearchInput: import("react").ForwardRefExoticComponent<{
10
+ popupPlacement?: import("react").ComponentProps<typeof Popup>["placement"];
11
+ threshold?: number;
12
+ children: import("./types").SearchBarChildrenFunctionProps | import("react").ReactNode;
13
+ onSearch: (value: string) => void;
14
+ onClose?: () => void;
15
+ "data-testid"?: string;
16
+ } & Pick<{
17
+ className?: string;
18
+ clearable?: boolean;
19
+ 'data-testid'?: string;
20
+ error?: string;
21
+ helper?: import("react").ReactNode;
22
+ label?: string;
23
+ labelDescription?: import("react").ReactNode;
24
+ loading?: boolean;
25
+ minLength?: number;
26
+ maxLength?: number;
27
+ onRandomize?: () => void;
28
+ onChange?: (newValue: string) => void;
29
+ prefix?: import("react").ReactNode;
30
+ size?: "large" | "medium" | "small";
31
+ success?: string | boolean;
32
+ suffix?: import("react").ReactNode;
33
+ tooltip?: string;
34
+ type?: "text" | "password" | "url" | "email";
35
+ value?: string;
36
+ } & Pick<import("react").InputHTMLAttributes<HTMLInputElement>, "autoFocus" | "id" | "tabIndex" | "aria-label" | "aria-labelledby" | "onFocus" | "onBlur" | "onKeyDown" | "name" | "disabled" | "autoComplete" | "placeholder" | "readOnly" | "required"> & import("react").RefAttributes<HTMLInputElement>, "label" | "size" | "loading" | "placeholder" | "suffix"> & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,98 @@
1
+ import { jsx } from "@emotion/react/jsx-runtime";
2
+ import _styled from "@emotion/styled/base";
3
+ import { Icon } from "@ultraviolet/icons";
4
+ import { forwardRef, useRef, useState, useReducer, useEffect } from "react";
5
+ import { Popup } from "../Popup/index.js";
6
+ import { TextInputV2 } from "../TextInputV2/index.js";
7
+ const StyledPopup = /* @__PURE__ */ _styled(Popup, process.env.NODE_ENV === "production" ? {
8
+ target: "eefux4u0"
9
+ } : {
10
+ target: "eefux4u0",
11
+ label: "StyledPopup"
12
+ })("width:100%;text-align:initial;min-width:610px;padding:", ({
13
+ theme
14
+ }) => `${theme.space["2"]} ${theme.space["1"]}`, ";background:", ({
15
+ theme
16
+ }) => theme.colors.neutral.background, ";box-shadow:", ({
17
+ theme
18
+ }) => theme.shadows.modal, ";" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL3VsdHJhdmlvbGV0L3VsdHJhdmlvbGV0L3BhY2thZ2VzL3VpL3NyYy9jb21wb25lbnRzL1NlYXJjaElucHV0L2luZGV4LnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFRaUMiLCJmaWxlIjoiL2hvbWUvcnVubmVyL3dvcmsvdWx0cmF2aW9sZXQvdWx0cmF2aW9sZXQvcGFja2FnZXMvdWkvc3JjL2NvbXBvbmVudHMvU2VhcmNoSW5wdXQvaW5kZXgudHN4Iiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnXG5pbXBvcnQgeyBJY29uIH0gZnJvbSAnQHVsdHJhdmlvbGV0L2ljb25zJ1xuaW1wb3J0IHR5cGUgeyBSZWYgfSBmcm9tICdyZWFjdCdcbmltcG9ydCB7IGZvcndhcmRSZWYsIHVzZUVmZmVjdCwgdXNlUmVkdWNlciwgdXNlUmVmLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgUG9wdXAgfSBmcm9tICcuLi9Qb3B1cCdcbmltcG9ydCB7IFRleHRJbnB1dFYyIH0gZnJvbSAnLi4vVGV4dElucHV0VjInXG5pbXBvcnQgdHlwZSB7IFNlYXJjaElucHV0UHJvcHMgfSBmcm9tICcuL3R5cGVzJ1xuXG5jb25zdCBTdHlsZWRQb3B1cCA9IHN0eWxlZChQb3B1cClgXG4gIHdpZHRoOiAxMDAlO1xuICB0ZXh0LWFsaWduOiBpbml0aWFsO1xuICBtaW4td2lkdGg6IDYxMHB4O1xuICBwYWRkaW5nOiAkeyh7IHRoZW1lIH0pID0+IGAke3RoZW1lLnNwYWNlWycyJ119ICR7dGhlbWUuc3BhY2VbJzEnXX1gfTtcbiAgYmFja2dyb3VuZDogJHsoeyB0aGVtZSB9KSA9PiB0aGVtZS5jb2xvcnMubmV1dHJhbC5iYWNrZ3JvdW5kfTtcbiAgYm94LXNoYWRvdzogJHsoeyB0aGVtZSB9KSA9PiB0aGVtZS5zaGFkb3dzLm1vZGFsfTtcbmBcblxuLyoqXG4gKiBTZWFyY2hJbnB1dCBpcyBhIGNvbXBvbmVudCB0aGF0IGFsbG93cyB1c2VycyB0byBzZWFyY2ggZm9yIGl0ZW1zLiBJdCBpcyBhIGNvbWJpbmF0aW9uIG9mIGEgVGV4dElucHV0VjIgYW5kIGEgUG9wdXAuIFRoZSBQb3B1cCBpcyB1c2VkIHRvIGRpc3BsYXkgc2VhcmNoIHJlc3VsdHMuXG4gKiBDaGlsZHJlbiBvZiB0aGUgU2VhcmNoSW5wdXQgY29tcG9uZW50IGNhbiBiZSBhIGZ1bmN0aW9uIHRoYXQgcmVjZWl2ZXMgYW4gb2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICogLSBgc2VhcmNoVGVybXNgOiB0aGUgY3VycmVudCBzZWFyY2ggdGVybXNcbiAqIC0gYGlzT3BlbmA6IGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIHRoZSBwb3B1cCBpcyBvcGVuXG4gKiAtIGB0b2dnbGVJc09wZW5gOiBhIGZ1bmN0aW9uIHRvIHRvZ2dsZSB0aGUgcG9wdXBcbiAqL1xuZXhwb3J0IGNvbnN0IFNlYXJjaElucHV0ID0gZm9yd2FyZFJlZihcbiAgKFxuICAgIHtcbiAgICAgIHBsYWNlaG9sZGVyLFxuICAgICAgbGFiZWwsXG4gICAgICBsb2FkaW5nLFxuICAgICAgc2l6ZSxcbiAgICAgIHN1ZmZpeCxcbiAgICAgIHBvcHVwUGxhY2VtZW50LFxuICAgICAgdGhyZXNob2xkID0gMCxcbiAgICAgIGNoaWxkcmVuLFxuICAgICAgb25TZWFyY2gsXG4gICAgICBvbkNsb3NlLFxuICAgICAgJ2RhdGEtdGVzdGlkJzogZGF0YVRlc3RJZCxcbiAgICB9OiBTZWFyY2hJbnB1dFByb3BzLFxuICAgIHJlZjogUmVmPEhUTUxJbnB1dEVsZW1lbnQ+LFxuICApID0+IHtcbiAgICBjb25zdCBmb2N1c2VkTGlua0luZGV4ID0gdXNlUmVmKDApXG4gICAgY29uc3QgcG9wdXBSZWYgPSB1c2VSZWY8SFRNTERpdkVsZW1lbnQ+KG51bGwpXG4gICAgY29uc3QgW2NvbnRhaW5lcldpZHRoLCBzZXRDb250YWluZXJXaWR0aF0gPSB1c2VTdGF0ZSgwKVxuICAgIGNvbnN0IFtzZWFyY2hUZXJtcywgc2V0U2VhcmNoVGVybXNdID0gdXNlU3RhdGUoJycpXG4gICAgY29uc3QgW2lzT3BlbiwgdG9nZ2xlSXNPcGVuXSA9IHVzZVJlZHVjZXIoc3RhdGUgPT4gIXN0YXRlLCBmYWxzZSlcblxuICAgIGNvbnN0IGNvbnRlbnQgPVxuICAgICAgdHlwZW9mIGNoaWxkcmVuID09PSAnZnVuY3Rpb24nXG4gICAgICAgID8gY2hpbGRyZW4oeyBzZWFyY2hUZXJtcywgaXNPcGVuLCB0b2dnbGVJc09wZW4gfSlcbiAgICAgICAgOiBjaGlsZHJlblxuXG4gICAgY29uc3QgcmVzaXplU2VhcmNoQmFyID0gKCkgPT4ge1xuICAgICAgaWYgKHBvcHVwUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgc2V0Q29udGFpbmVyV2lkdGgocG9wdXBSZWYuY3VycmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aClcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBoYW5kbGVOYXZpZ2F0aW9uID0gKGV2ZW50OiBLZXlib2FyZEV2ZW50KSA9PiB7XG4gICAgICBjb25zdCBsaW5rcyA9IFsuLi4ocG9wdXBSZWYuY3VycmVudD8ucXVlcnlTZWxlY3RvckFsbCgnYScpID8/IFtdKV1cblxuICAgICAgaWYgKFxuICAgICAgICBsaW5rcy5sZW5ndGggPiAwICYmXG4gICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA+PSAwICYmXG4gICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA8PSBsaW5rcy5sZW5ndGhcbiAgICAgICkge1xuICAgICAgICBpZiAoZXZlbnQua2V5ID09PSAnQXJyb3dVcCcpIHtcbiAgICAgICAgICBpZiAoZm9jdXNlZExpbmtJbmRleC5jdXJyZW50IC0gMSA8IDApIHtcbiAgICAgICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA9IGxpbmtzLmxlbmd0aCAtIDFcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9jdXNlZExpbmtJbmRleC5jdXJyZW50IC09IDFcbiAgICAgICAgICB9XG4gICAgICAgICAgbGlua3NbZm9jdXNlZExpbmtJbmRleC5jdXJyZW50XT8uZm9jdXMoKVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV2ZW50LmtleSA9PT0gJ0Fycm93RG93bicpIHtcbiAgICAgICAgICBpZiAoZm9jdXNlZExpbmtJbmRleC5jdXJyZW50ICsgMSA+PSBsaW5rcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGZvY3VzZWRMaW5rSW5kZXguY3VycmVudCA9IDBcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9jdXNlZExpbmtJbmRleC5jdXJyZW50ICs9IDFcbiAgICAgICAgICB9XG4gICAgICAgICAgbGlua3NbZm9jdXNlZExpbmtJbmRleC5jdXJyZW50XT8uZm9jdXMoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2tleXVwJywgaGFuZGxlTmF2aWdhdGlvbilcblxuICAgICAgcmV0dXJuICgpID0+IGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2tleXVwJywgaGFuZGxlTmF2aWdhdGlvbilcbiAgICB9LCBbXSlcblxuICAgIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgICByZXNpemVTZWFyY2hCYXIoKVxuXG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgcmVzaXplU2VhcmNoQmFyKVxuXG4gICAgICByZXR1cm4gKCkgPT4gd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHJlc2l6ZVNlYXJjaEJhcilcbiAgICB9LCBbXSlcblxuICAgIGNvbnN0IG9uU2VhcmNoQ2FsbGJhY2sgPSAodmFsdWU6IHN0cmluZykgPT4ge1xuICAgICAgc2V0U2VhcmNoVGVybXModmFsdWUpXG5cbiAgICAgIHRyeSB7XG4gICAgICAgIG9uU2VhcmNoKHZhbHVlKVxuICAgICAgICBpZiAodmFsdWUubGVuZ3RoID49IHRocmVzaG9sZCAmJiAhaXNPcGVuKSB7XG4gICAgICAgICAgdG9nZ2xlSXNPcGVuKClcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHRvZ2dsZUlzT3BlbigpXG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3Qgb25DbG9zZUNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgb25DbG9zZT8uKClcbiAgICAgIGlmIChpc09wZW4pIHtcbiAgICAgICAgdG9nZ2xlSXNPcGVuKClcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdj5cbiAgICAgICAgPFN0eWxlZFBvcHVwXG4gICAgICAgICAgZGF0YS10ZXN0aWQ9e2Bwb3B1cC0ke2RhdGFUZXN0SWR9YH1cbiAgICAgICAgICByb2xlPVwiZGlhbG9nXCJcbiAgICAgICAgICB2aXNpYmxlPXtpc09wZW59XG4gICAgICAgICAgb25DbG9zZT17b25DbG9zZUNhbGxiYWNrfVxuICAgICAgICAgIHBsYWNlbWVudD17cG9wdXBQbGFjZW1lbnR9XG4gICAgICAgICAgbWF4V2lkdGg9e2NvbnRhaW5lcldpZHRofVxuICAgICAgICAgIGhpZGVPbkNsaWNrT3V0c2lkZVxuICAgICAgICAgIGhhc0Fycm93PXtmYWxzZX1cbiAgICAgICAgICBpbm5lclJlZj17cG9wdXBSZWZ9XG4gICAgICAgICAgdGV4dD17Y29udGVudH1cbiAgICAgICAgICBtYXhIZWlnaHQ9ezQxMH1cbiAgICAgICAgICBkZWJvdW5jZURlbGF5PXswfVxuICAgICAgICA+XG4gICAgICAgICAgPFRleHRJbnB1dFYyXG4gICAgICAgICAgICByZWY9e3JlZn1cbiAgICAgICAgICAgIHByZWZpeD17PEljb24gbmFtZT1cInNlYXJjaFwiIC8+fVxuICAgICAgICAgICAgc3VmZml4PXtzdWZmaXh9XG4gICAgICAgICAgICBkYXRhLXRlc3RpZD17ZGF0YVRlc3RJZH1cbiAgICAgICAgICAgIHZhbHVlPXtzZWFyY2hUZXJtc31cbiAgICAgICAgICAgIHNpemU9e3NpemV9XG4gICAgICAgICAgICBsYWJlbD17bGFiZWx9XG4gICAgICAgICAgICBwbGFjZWhvbGRlcj17cGxhY2Vob2xkZXJ9XG4gICAgICAgICAgICBsb2FkaW5nPXtsb2FkaW5nfVxuICAgICAgICAgICAgb25DaGFuZ2U9e29uU2VhcmNoQ2FsbGJhY2t9XG4gICAgICAgICAgICBjbGVhcmFibGVcbiAgICAgICAgICAvPlxuICAgICAgICA8L1N0eWxlZFBvcHVwPlxuICAgICAgPC9kaXY+XG4gICAgKVxuICB9LFxuKVxuIl19 */"));
19
+ const SearchInput = forwardRef(({
20
+ placeholder,
21
+ label,
22
+ loading,
23
+ size,
24
+ suffix,
25
+ popupPlacement,
26
+ threshold = 0,
27
+ children,
28
+ onSearch,
29
+ onClose,
30
+ "data-testid": dataTestId
31
+ }, ref) => {
32
+ const focusedLinkIndex = useRef(0);
33
+ const popupRef = useRef(null);
34
+ const [containerWidth, setContainerWidth] = useState(0);
35
+ const [searchTerms, setSearchTerms] = useState("");
36
+ const [isOpen, toggleIsOpen] = useReducer((state) => !state, false);
37
+ const content = typeof children === "function" ? children({
38
+ searchTerms,
39
+ isOpen,
40
+ toggleIsOpen
41
+ }) : children;
42
+ const resizeSearchBar = () => {
43
+ if (popupRef.current) {
44
+ setContainerWidth(popupRef.current.getBoundingClientRect().width);
45
+ }
46
+ };
47
+ const handleNavigation = (event) => {
48
+ const links = [...popupRef.current?.querySelectorAll("a") ?? []];
49
+ if (links.length > 0 && focusedLinkIndex.current >= 0 && focusedLinkIndex.current <= links.length) {
50
+ if (event.key === "ArrowUp") {
51
+ if (focusedLinkIndex.current - 1 < 0) {
52
+ focusedLinkIndex.current = links.length - 1;
53
+ } else {
54
+ focusedLinkIndex.current -= 1;
55
+ }
56
+ links[focusedLinkIndex.current]?.focus();
57
+ }
58
+ if (event.key === "ArrowDown") {
59
+ if (focusedLinkIndex.current + 1 >= links.length) {
60
+ focusedLinkIndex.current = 0;
61
+ } else {
62
+ focusedLinkIndex.current += 1;
63
+ }
64
+ links[focusedLinkIndex.current]?.focus();
65
+ }
66
+ }
67
+ };
68
+ useEffect(() => {
69
+ document.addEventListener("keyup", handleNavigation);
70
+ return () => document.removeEventListener("keyup", handleNavigation);
71
+ }, []);
72
+ useEffect(() => {
73
+ resizeSearchBar();
74
+ window.addEventListener("resize", resizeSearchBar);
75
+ return () => window.removeEventListener("resize", resizeSearchBar);
76
+ }, []);
77
+ const onSearchCallback = (value) => {
78
+ setSearchTerms(value);
79
+ try {
80
+ onSearch(value);
81
+ if (value.length >= threshold && !isOpen) {
82
+ toggleIsOpen();
83
+ }
84
+ } catch {
85
+ toggleIsOpen();
86
+ }
87
+ };
88
+ const onCloseCallback = () => {
89
+ onClose?.();
90
+ if (isOpen) {
91
+ toggleIsOpen();
92
+ }
93
+ };
94
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(StyledPopup, { "data-testid": `popup-${dataTestId}`, role: "dialog", visible: isOpen, onClose: onCloseCallback, placement: popupPlacement, maxWidth: containerWidth, hideOnClickOutside: true, hasArrow: false, innerRef: popupRef, text: content, maxHeight: 410, debounceDelay: 0, children: /* @__PURE__ */ jsx(TextInputV2, { ref, prefix: /* @__PURE__ */ jsx(Icon, { name: "search" }), suffix, "data-testid": dataTestId, value: searchTerms, size, label, placeholder, loading, onChange: onSearchCallback, clearable: true }) }) });
95
+ });
96
+ export {
97
+ SearchInput
98
+ };
@@ -0,0 +1,17 @@
1
+ import type { Popup, TextInputV2 } from '@ultraviolet/ui';
2
+ import type { ComponentProps, DispatchWithoutAction, ReactNode } from 'react';
3
+ type ChildrenProps = {
4
+ searchTerms: string;
5
+ isOpen: boolean;
6
+ toggleIsOpen: DispatchWithoutAction;
7
+ };
8
+ export type SearchBarChildrenFunctionProps = ({ searchTerms, isOpen, toggleIsOpen, }: ChildrenProps) => ReactNode;
9
+ export type SearchInputProps = {
10
+ popupPlacement?: ComponentProps<typeof Popup>['placement'];
11
+ threshold?: number;
12
+ children: SearchBarChildrenFunctionProps | ReactNode;
13
+ onSearch: (value: string) => void;
14
+ onClose?: () => void;
15
+ ['data-testid']?: string;
16
+ } & Pick<ComponentProps<typeof TextInputV2>, 'placeholder' | 'size' | 'label' | 'loading' | 'suffix'>;
17
+ export {};
@@ -29,10 +29,8 @@ const getControlColor = ({
29
29
  error,
30
30
  theme
31
31
  }) => {
32
- if (state.isDisabled)
33
- return theme.colors.neutral.textDisabled;
34
- if (error)
35
- return theme.colors.danger.text;
32
+ if (state.isDisabled) return theme.colors.neutral.textDisabled;
33
+ if (error) return theme.colors.danger.text;
36
34
  return theme.colors.neutral.text;
37
35
  };
38
36
  const getPlaceholderColor = ({
@@ -40,10 +38,8 @@ const getPlaceholderColor = ({
40
38
  error,
41
39
  theme
42
40
  }) => {
43
- if (state.isDisabled)
44
- return theme.colors.neutral.textDisabled;
45
- if (error)
46
- return theme.colors.danger.text;
41
+ if (state.isDisabled) return theme.colors.neutral.textDisabled;
42
+ if (error) return theme.colors.danger.text;
47
43
  return theme.colors.neutral.textWeak;
48
44
  };
49
45
  const getOptionColor = ({
@@ -23,10 +23,8 @@ const getControlColor = ({
23
23
  error,
24
24
  theme
25
25
  }) => {
26
- if (state.isDisabled)
27
- return theme.colors.neutral.textDisabled;
28
- if (error)
29
- return theme.colors.danger.text;
26
+ if (state.isDisabled) return theme.colors.neutral.textDisabled;
27
+ if (error) return theme.colors.danger.text;
30
28
  return theme.colors.neutral.text;
31
29
  };
32
30
  const getPlaceholderColor = ({
@@ -34,10 +32,8 @@ const getPlaceholderColor = ({
34
32
  error,
35
33
  theme
36
34
  }) => {
37
- if (state.isDisabled)
38
- return theme.colors.neutral.textDisabled;
39
- if (error)
40
- return theme.colors.danger.text;
35
+ if (state.isDisabled) return theme.colors.neutral.textDisabled;
36
+ if (error) return theme.colors.danger.text;
41
37
  return theme.colors.neutral.textWeak;
42
38
  };
43
39
  const getOptionColor = ({