@envive-ai/react-widgets 0.1.1 → 0.1.2-arthur-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 (42) hide show
  1. package/dist/SearchResults/index-D8nrHueo.d.ts +6 -0
  2. package/dist/{index.cjs → SearchResults/index.cjs} +2 -24
  3. package/dist/SearchZeroState/index-19CiYvee.d.cts +27 -0
  4. package/dist/SearchZeroState/index-6EaGWYP4.d.ts +27 -0
  5. package/dist/SearchZeroState/index.cjs +3047 -0
  6. package/dist/SearchZeroState/index.js +3043 -0
  7. package/dist/SuggestionBar/index-DZU9kbWS.d.cts +39 -0
  8. package/dist/SuggestionBar/index-DyXd4-b7.d.ts +39 -0
  9. package/dist/SuggestionBar/index.cjs +5 -0
  10. package/dist/SuggestionBar/index.js +4 -0
  11. package/dist/SuggestionBar-BOThXJvJ.cjs +453 -0
  12. package/dist/SuggestionBar-DeMmAK4M.js +131 -0
  13. package/dist/SuggestionButtonContainer/index-B_X537jw.d.cts +20 -0
  14. package/dist/SuggestionButtonContainer/index-vwelzDzM.d.ts +20 -0
  15. package/dist/SuggestionButtonContainer/index.cjs +3 -0
  16. package/dist/SuggestionButtonContainer/index.js +3 -0
  17. package/dist/SuggestionButtonContainer-BeWPpeQk.cjs +173 -0
  18. package/dist/SuggestionButtonContainer-CZhOkZaJ.js +167 -0
  19. package/dist/chunk-DWy1uDak.cjs +39 -0
  20. package/package.json +18 -6
  21. package/src/SearchZeroState/SearchIcon.tsx +57 -0
  22. package/src/SearchZeroState/SearchOverlay.tsx +81 -0
  23. package/src/SearchZeroState/SearchZeroState.tsx +264 -0
  24. package/src/SearchZeroState/SearchZeroStateWidget.tsx +33 -0
  25. package/src/SearchZeroState/components/RecommendedProducts.tsx +118 -0
  26. package/src/SearchZeroState/index.ts +8 -0
  27. package/src/SearchZeroState/overlay/overlayHostLocator.ts +17 -0
  28. package/src/SearchZeroState/types.ts +9 -0
  29. package/src/SearchZeroState/zeroStateSearchVariants.ts +24 -0
  30. package/src/SuggestionBar/SuggestionBar.tsx +139 -0
  31. package/src/SuggestionBar/index.ts +2 -0
  32. package/src/SuggestionBar/types.ts +4 -0
  33. package/src/SuggestionButtonContainer/SuggestionButtonContainer.tsx +141 -0
  34. package/src/SuggestionButtonContainer/index.ts +2 -0
  35. package/src/SuggestionButtonContainer/types.ts +16 -0
  36. package/src/stories/SearchZeroState.stories.tsx +44 -0
  37. package/src/stories/SuggestionBar.stories.tsx +46 -0
  38. package/src/util/useHorizontalScrollAnimation.ts +121 -0
  39. package/src/util/useReducedMotionWithOverride.ts +24 -0
  40. package/dist/index-VWNd4lyI.d.cts +0 -6
  41. /package/dist/{index-BPfKr14f.d.ts → SearchResults/index-D52sX_I2.d.cts} +0 -0
  42. /package/dist/{index.js → SearchResults/index.js} +0 -0
@@ -0,0 +1,20 @@
1
+ import { SuggestionButtonVariant } from "@envive-ai/react-hooks/contexts/types";
2
+ import { TestProps } from "@envive-ai/react-hooks/types";
3
+
4
+ //#region src/SuggestionButtonContainer/types.d.ts
5
+ interface SuggestionButtonContainerProps extends TestProps {
6
+ buttonVariation: SuggestionButtonVariant;
7
+ hoverButtonVariation: SuggestionButtonVariant;
8
+ buttonTexts: string[];
9
+ onButtonClick: (text: string) => void;
10
+ scrollContainerRef: React.RefObject<HTMLDivElement>;
11
+ boldFirstButton?: boolean | undefined;
12
+ twoRowsOnMobile?: boolean | undefined;
13
+ animationSpeed?: 'standard' | 'slow' | 'none';
14
+ buttonBorderRadius?: 'sm' | 'md' | 'lg';
15
+ }
16
+ //#endregion
17
+ //#region src/SuggestionButtonContainer/SuggestionButtonContainer.d.ts
18
+ declare const SuggestionButtonContainer: React.FC<SuggestionButtonContainerProps>;
19
+ //#endregion
20
+ export { SuggestionButtonContainer, SuggestionButtonContainerProps };
@@ -0,0 +1,20 @@
1
+ import { TestProps } from "@envive-ai/react-hooks/types";
2
+ import { SuggestionButtonVariant } from "@envive-ai/react-hooks/contexts/types";
3
+
4
+ //#region src/SuggestionButtonContainer/types.d.ts
5
+ interface SuggestionButtonContainerProps extends TestProps {
6
+ buttonVariation: SuggestionButtonVariant;
7
+ hoverButtonVariation: SuggestionButtonVariant;
8
+ buttonTexts: string[];
9
+ onButtonClick: (text: string) => void;
10
+ scrollContainerRef: React.RefObject<HTMLDivElement>;
11
+ boldFirstButton?: boolean | undefined;
12
+ twoRowsOnMobile?: boolean | undefined;
13
+ animationSpeed?: 'standard' | 'slow' | 'none';
14
+ buttonBorderRadius?: 'sm' | 'md' | 'lg';
15
+ }
16
+ //#endregion
17
+ //#region src/SuggestionButtonContainer/SuggestionButtonContainer.d.ts
18
+ declare const SuggestionButtonContainer: React.FC<SuggestionButtonContainerProps>;
19
+ //#endregion
20
+ export { SuggestionButtonContainer, SuggestionButtonContainerProps };
@@ -0,0 +1,3 @@
1
+ const require_SuggestionButtonContainer = require('../SuggestionButtonContainer-BeWPpeQk.cjs');
2
+
3
+ exports.SuggestionButtonContainer = require_SuggestionButtonContainer.SuggestionButtonContainer;
@@ -0,0 +1,3 @@
1
+ import { t as SuggestionButtonContainer } from "../SuggestionButtonContainer-CZhOkZaJ.js";
2
+
3
+ export { SuggestionButtonContainer };
@@ -0,0 +1,173 @@
1
+ const require_chunk = require('./chunk-DWy1uDak.cjs');
2
+ let react = require("react");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ let framer_motion = require("framer-motion");
5
+ let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
6
+ let __envive_ai_react_hooks_config = require("@envive-ai/react-hooks/config");
7
+ let __envive_ai_react_hooks_hooks_IsSmallScreen = require("@envive-ai/react-hooks/hooks/IsSmallScreen");
8
+ let __envive_ai_react_hooks_hooks_TrackComponentVisibleEvent = require("@envive-ai/react-hooks/hooks/TrackComponentVisibleEvent");
9
+ let __envive_ai_react_toolkit_SuggestionButton = require("@envive-ai/react-toolkit/SuggestionButton");
10
+
11
+ //#region src/util/useReducedMotionWithOverride.ts
12
+ const useReducedMotionWithOverride = () => {
13
+ const reducedMotionConfig = (0, framer_motion.useReducedMotionConfig)();
14
+ return (0, react.useMemo)(() => {
15
+ if (window?._spiffy?.reducedMotionOverride) return window?._spiffy?.reducedMotionOverride;
16
+ return reducedMotionConfig;
17
+ }, [reducedMotionConfig]);
18
+ };
19
+
20
+ //#endregion
21
+ //#region src/util/useHorizontalScrollAnimation.ts
22
+ function useHorizontalScrollAnimation({ scrollContainerRef, animationSpeed = "standard" }) {
23
+ const reducedMotion = useReducedMotionWithOverride();
24
+ const resumeTimeoutRef = (0, react.useRef)(null);
25
+ const scrollAnimationRef = (0, react.useRef)(null);
26
+ const pauseOnHover = true;
27
+ let PIXELS_PER_SECOND = 40;
28
+ switch (animationSpeed) {
29
+ case "standard":
30
+ PIXELS_PER_SECOND = 40;
31
+ break;
32
+ case "slow":
33
+ PIXELS_PER_SECOND = 25;
34
+ break;
35
+ case "none":
36
+ PIXELS_PER_SECOND = 0;
37
+ break;
38
+ default: PIXELS_PER_SECOND = 40;
39
+ }
40
+ const RESUME_DELAY_MS = 2e3;
41
+ const isAnimated = animationSpeed !== "none";
42
+ (0, react.useEffect)(() => {
43
+ if (!isAnimated || reducedMotion || !scrollContainerRef) return () => {};
44
+ const container = scrollContainerRef.current;
45
+ if (!container) return () => {};
46
+ if (container.scrollWidth <= container.clientWidth) return () => {};
47
+ let isPaused = false;
48
+ let lastTimestamp = null;
49
+ let accumulatedScroll = 0;
50
+ const step = (timestamp) => {
51
+ if (lastTimestamp === null) lastTimestamp = timestamp;
52
+ if (!isPaused) {
53
+ const delta = timestamp - lastTimestamp;
54
+ lastTimestamp = timestamp;
55
+ accumulatedScroll += PIXELS_PER_SECOND * (delta / 1e3);
56
+ const pixelsToScroll = Math.floor(accumulatedScroll);
57
+ if (pixelsToScroll > 0) {
58
+ container.scrollLeft += pixelsToScroll;
59
+ accumulatedScroll -= pixelsToScroll;
60
+ if (Math.ceil(container.scrollLeft) >= container.scrollWidth - container.clientWidth) {
61
+ container.scrollLeft = 0;
62
+ accumulatedScroll = 0;
63
+ }
64
+ }
65
+ }
66
+ scrollAnimationRef.current = requestAnimationFrame(step);
67
+ };
68
+ scrollAnimationRef.current = requestAnimationFrame(step);
69
+ const pauseAnimation = () => {
70
+ isPaused = true;
71
+ if (resumeTimeoutRef.current) {
72
+ clearTimeout(resumeTimeoutRef.current);
73
+ resumeTimeoutRef.current = null;
74
+ }
75
+ };
76
+ const scheduleResumeAnimation = () => {
77
+ resumeTimeoutRef.current = setTimeout(() => {
78
+ isPaused = false;
79
+ lastTimestamp = null;
80
+ }, RESUME_DELAY_MS);
81
+ };
82
+ container.addEventListener("mouseenter", pauseAnimation);
83
+ container.addEventListener("mouseleave", scheduleResumeAnimation);
84
+ container.addEventListener("touchstart", pauseAnimation);
85
+ container.addEventListener("touchend", scheduleResumeAnimation);
86
+ return function cleanup() {
87
+ if (scrollAnimationRef.current) cancelAnimationFrame(scrollAnimationRef.current);
88
+ container.removeEventListener("mouseenter", pauseAnimation);
89
+ container.removeEventListener("mouseleave", scheduleResumeAnimation);
90
+ container.removeEventListener("touchstart", pauseAnimation);
91
+ container.removeEventListener("touchend", scheduleResumeAnimation);
92
+ if (resumeTimeoutRef.current) clearTimeout(resumeTimeoutRef.current);
93
+ };
94
+ }, [
95
+ isAnimated,
96
+ reducedMotion,
97
+ PIXELS_PER_SECOND,
98
+ pauseOnHover,
99
+ scrollContainerRef
100
+ ]);
101
+ }
102
+
103
+ //#endregion
104
+ //#region src/SuggestionButtonContainer/SuggestionButtonContainer.tsx
105
+ function ButtonContainer({ children }) {
106
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
107
+ className: "spiffy-tw-flex \n spiffy-tw-flex-row\n spiffy-tw-items-center\n spiffy-tw-space-x-2\n spiffy-tw-h-full\n spiffy-tw-pl-0",
108
+ children
109
+ });
110
+ }
111
+ const SuggestionButtonContainer = ({ buttonVariation, hoverButtonVariation, buttonTexts, boldFirstButton = false, twoRowsOnMobile = false, animationSpeed = "none", buttonBorderRadius = "lg", scrollContainerRef, onButtonClick }) => {
112
+ const componentVisibleTriggerRef = (0, react.useRef)(null);
113
+ useHorizontalScrollAnimation({
114
+ scrollContainerRef,
115
+ animationSpeed
116
+ });
117
+ const isSmallScreen = (0, __envive_ai_react_hooks_hooks_IsSmallScreen.useIsSmallScreen)();
118
+ const isAnimated = animationSpeed !== "none";
119
+ (0, __envive_ai_react_hooks_hooks_TrackComponentVisibleEvent.useTrackComponentVisibleEvent)(__envive_ai_react_hooks_application_models.SpiffyWidgets.SuggestionBar, componentVisibleTriggerRef, { animated: isAnimated });
120
+ const visibleButtonsFirstRow = buttonTexts.slice(0, twoRowsOnMobile && isSmallScreen ? Math.ceil((buttonTexts.length + 1) / 2) : void 0);
121
+ const visibleButtonsSecondRow = buttonTexts.slice(Math.ceil((buttonTexts.length + 1) / 2), buttonTexts.length);
122
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
123
+ className: "spiffy-tw-overflow-x-scroll spiffy-tw-no-scrollbar spiffy-tw-w-full spiffy-tw-whitespace-nowrap",
124
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ButtonContainer, { children: [visibleButtonsFirstRow.map((suggestion, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__envive_ai_react_toolkit_SuggestionButton.SuggestionButton, {
125
+ variant: buttonVariation,
126
+ hoverVariant: hoverButtonVariation,
127
+ isDisabled: false,
128
+ content: suggestion,
129
+ boldText: boldFirstButton && i === 0,
130
+ borderRadius: buttonBorderRadius,
131
+ onClick: () => onButtonClick(suggestion),
132
+ dataTestId: __envive_ai_react_hooks_config.SUGGESTION_BAR_BUTTON_TESTID
133
+ }, i)), isAnimated && buttonTexts.map((suggestion, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__envive_ai_react_toolkit_SuggestionButton.SuggestionButton, {
134
+ variant: buttonVariation,
135
+ hoverVariant: hoverButtonVariation,
136
+ isDisabled: false,
137
+ content: suggestion,
138
+ boldText: boldFirstButton && i === 0,
139
+ borderRadius: buttonBorderRadius,
140
+ onClick: () => onButtonClick(suggestion),
141
+ dataTestId: __envive_ai_react_hooks_config.SUGGESTION_BAR_BUTTON_TESTID
142
+ }, `animation-dupe-${i}`))] }), twoRowsOnMobile && isSmallScreen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
143
+ className: "spiffy-tw-mt-1.5",
144
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ButtonContainer, { children: [visibleButtonsSecondRow.map((suggestion, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__envive_ai_react_toolkit_SuggestionButton.SuggestionButton, {
145
+ variant: buttonVariation,
146
+ hoverVariant: hoverButtonVariation,
147
+ isDisabled: false,
148
+ content: suggestion,
149
+ boldText: boldFirstButton && i === 0,
150
+ borderRadius: buttonBorderRadius,
151
+ onClick: () => onButtonClick(suggestion),
152
+ dataTestId: __envive_ai_react_hooks_config.SUGGESTION_BAR_BUTTON_TESTID
153
+ }, i)), isAnimated && visibleButtonsSecondRow.map((suggestion, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__envive_ai_react_toolkit_SuggestionButton.SuggestionButton, {
154
+ variant: buttonVariation,
155
+ hoverVariant: hoverButtonVariation,
156
+ isDisabled: false,
157
+ content: suggestion,
158
+ boldText: boldFirstButton && i === 0,
159
+ borderRadius: buttonBorderRadius,
160
+ onClick: () => onButtonClick(suggestion),
161
+ dataTestId: __envive_ai_react_hooks_config.SUGGESTION_BAR_BUTTON_TESTID
162
+ }, `animation-dupe-${i}`))] })
163
+ })]
164
+ });
165
+ };
166
+
167
+ //#endregion
168
+ Object.defineProperty(exports, 'SuggestionButtonContainer', {
169
+ enumerable: true,
170
+ get: function () {
171
+ return SuggestionButtonContainer;
172
+ }
173
+ });
@@ -0,0 +1,167 @@
1
+ import { useEffect, useMemo, useRef } from "react";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useReducedMotionConfig } from "framer-motion";
4
+ import { SpiffyWidgets } from "@envive-ai/react-hooks/application/models";
5
+ import { SUGGESTION_BAR_BUTTON_TESTID } from "@envive-ai/react-hooks/config";
6
+ import { useIsSmallScreen } from "@envive-ai/react-hooks/hooks/IsSmallScreen";
7
+ import { useTrackComponentVisibleEvent } from "@envive-ai/react-hooks/hooks/TrackComponentVisibleEvent";
8
+ import { SuggestionButton } from "@envive-ai/react-toolkit/SuggestionButton";
9
+
10
+ //#region src/util/useReducedMotionWithOverride.ts
11
+ const useReducedMotionWithOverride = () => {
12
+ const reducedMotionConfig = useReducedMotionConfig();
13
+ return useMemo(() => {
14
+ if (window?._spiffy?.reducedMotionOverride) return window?._spiffy?.reducedMotionOverride;
15
+ return reducedMotionConfig;
16
+ }, [reducedMotionConfig]);
17
+ };
18
+
19
+ //#endregion
20
+ //#region src/util/useHorizontalScrollAnimation.ts
21
+ function useHorizontalScrollAnimation({ scrollContainerRef, animationSpeed = "standard" }) {
22
+ const reducedMotion = useReducedMotionWithOverride();
23
+ const resumeTimeoutRef = useRef(null);
24
+ const scrollAnimationRef = useRef(null);
25
+ const pauseOnHover = true;
26
+ let PIXELS_PER_SECOND = 40;
27
+ switch (animationSpeed) {
28
+ case "standard":
29
+ PIXELS_PER_SECOND = 40;
30
+ break;
31
+ case "slow":
32
+ PIXELS_PER_SECOND = 25;
33
+ break;
34
+ case "none":
35
+ PIXELS_PER_SECOND = 0;
36
+ break;
37
+ default: PIXELS_PER_SECOND = 40;
38
+ }
39
+ const RESUME_DELAY_MS = 2e3;
40
+ const isAnimated = animationSpeed !== "none";
41
+ useEffect(() => {
42
+ if (!isAnimated || reducedMotion || !scrollContainerRef) return () => {};
43
+ const container = scrollContainerRef.current;
44
+ if (!container) return () => {};
45
+ if (container.scrollWidth <= container.clientWidth) return () => {};
46
+ let isPaused = false;
47
+ let lastTimestamp = null;
48
+ let accumulatedScroll = 0;
49
+ const step = (timestamp) => {
50
+ if (lastTimestamp === null) lastTimestamp = timestamp;
51
+ if (!isPaused) {
52
+ const delta = timestamp - lastTimestamp;
53
+ lastTimestamp = timestamp;
54
+ accumulatedScroll += PIXELS_PER_SECOND * (delta / 1e3);
55
+ const pixelsToScroll = Math.floor(accumulatedScroll);
56
+ if (pixelsToScroll > 0) {
57
+ container.scrollLeft += pixelsToScroll;
58
+ accumulatedScroll -= pixelsToScroll;
59
+ if (Math.ceil(container.scrollLeft) >= container.scrollWidth - container.clientWidth) {
60
+ container.scrollLeft = 0;
61
+ accumulatedScroll = 0;
62
+ }
63
+ }
64
+ }
65
+ scrollAnimationRef.current = requestAnimationFrame(step);
66
+ };
67
+ scrollAnimationRef.current = requestAnimationFrame(step);
68
+ const pauseAnimation = () => {
69
+ isPaused = true;
70
+ if (resumeTimeoutRef.current) {
71
+ clearTimeout(resumeTimeoutRef.current);
72
+ resumeTimeoutRef.current = null;
73
+ }
74
+ };
75
+ const scheduleResumeAnimation = () => {
76
+ resumeTimeoutRef.current = setTimeout(() => {
77
+ isPaused = false;
78
+ lastTimestamp = null;
79
+ }, RESUME_DELAY_MS);
80
+ };
81
+ container.addEventListener("mouseenter", pauseAnimation);
82
+ container.addEventListener("mouseleave", scheduleResumeAnimation);
83
+ container.addEventListener("touchstart", pauseAnimation);
84
+ container.addEventListener("touchend", scheduleResumeAnimation);
85
+ return function cleanup() {
86
+ if (scrollAnimationRef.current) cancelAnimationFrame(scrollAnimationRef.current);
87
+ container.removeEventListener("mouseenter", pauseAnimation);
88
+ container.removeEventListener("mouseleave", scheduleResumeAnimation);
89
+ container.removeEventListener("touchstart", pauseAnimation);
90
+ container.removeEventListener("touchend", scheduleResumeAnimation);
91
+ if (resumeTimeoutRef.current) clearTimeout(resumeTimeoutRef.current);
92
+ };
93
+ }, [
94
+ isAnimated,
95
+ reducedMotion,
96
+ PIXELS_PER_SECOND,
97
+ pauseOnHover,
98
+ scrollContainerRef
99
+ ]);
100
+ }
101
+
102
+ //#endregion
103
+ //#region src/SuggestionButtonContainer/SuggestionButtonContainer.tsx
104
+ function ButtonContainer({ children }) {
105
+ return /* @__PURE__ */ jsx("div", {
106
+ className: "spiffy-tw-flex \n spiffy-tw-flex-row\n spiffy-tw-items-center\n spiffy-tw-space-x-2\n spiffy-tw-h-full\n spiffy-tw-pl-0",
107
+ children
108
+ });
109
+ }
110
+ const SuggestionButtonContainer = ({ buttonVariation, hoverButtonVariation, buttonTexts, boldFirstButton = false, twoRowsOnMobile = false, animationSpeed = "none", buttonBorderRadius = "lg", scrollContainerRef, onButtonClick }) => {
111
+ const componentVisibleTriggerRef = useRef(null);
112
+ useHorizontalScrollAnimation({
113
+ scrollContainerRef,
114
+ animationSpeed
115
+ });
116
+ const isSmallScreen = useIsSmallScreen();
117
+ const isAnimated = animationSpeed !== "none";
118
+ useTrackComponentVisibleEvent(SpiffyWidgets.SuggestionBar, componentVisibleTriggerRef, { animated: isAnimated });
119
+ const visibleButtonsFirstRow = buttonTexts.slice(0, twoRowsOnMobile && isSmallScreen ? Math.ceil((buttonTexts.length + 1) / 2) : void 0);
120
+ const visibleButtonsSecondRow = buttonTexts.slice(Math.ceil((buttonTexts.length + 1) / 2), buttonTexts.length);
121
+ return /* @__PURE__ */ jsxs("div", {
122
+ className: "spiffy-tw-overflow-x-scroll spiffy-tw-no-scrollbar spiffy-tw-w-full spiffy-tw-whitespace-nowrap",
123
+ children: [/* @__PURE__ */ jsxs(ButtonContainer, { children: [visibleButtonsFirstRow.map((suggestion, i) => /* @__PURE__ */ jsx(SuggestionButton, {
124
+ variant: buttonVariation,
125
+ hoverVariant: hoverButtonVariation,
126
+ isDisabled: false,
127
+ content: suggestion,
128
+ boldText: boldFirstButton && i === 0,
129
+ borderRadius: buttonBorderRadius,
130
+ onClick: () => onButtonClick(suggestion),
131
+ dataTestId: SUGGESTION_BAR_BUTTON_TESTID
132
+ }, i)), isAnimated && buttonTexts.map((suggestion, i) => /* @__PURE__ */ jsx(SuggestionButton, {
133
+ variant: buttonVariation,
134
+ hoverVariant: hoverButtonVariation,
135
+ isDisabled: false,
136
+ content: suggestion,
137
+ boldText: boldFirstButton && i === 0,
138
+ borderRadius: buttonBorderRadius,
139
+ onClick: () => onButtonClick(suggestion),
140
+ dataTestId: SUGGESTION_BAR_BUTTON_TESTID
141
+ }, `animation-dupe-${i}`))] }), twoRowsOnMobile && isSmallScreen && /* @__PURE__ */ jsx("div", {
142
+ className: "spiffy-tw-mt-1.5",
143
+ children: /* @__PURE__ */ jsxs(ButtonContainer, { children: [visibleButtonsSecondRow.map((suggestion, i) => /* @__PURE__ */ jsx(SuggestionButton, {
144
+ variant: buttonVariation,
145
+ hoverVariant: hoverButtonVariation,
146
+ isDisabled: false,
147
+ content: suggestion,
148
+ boldText: boldFirstButton && i === 0,
149
+ borderRadius: buttonBorderRadius,
150
+ onClick: () => onButtonClick(suggestion),
151
+ dataTestId: SUGGESTION_BAR_BUTTON_TESTID
152
+ }, i)), isAnimated && visibleButtonsSecondRow.map((suggestion, i) => /* @__PURE__ */ jsx(SuggestionButton, {
153
+ variant: buttonVariation,
154
+ hoverVariant: hoverButtonVariation,
155
+ isDisabled: false,
156
+ content: suggestion,
157
+ boldText: boldFirstButton && i === 0,
158
+ borderRadius: buttonBorderRadius,
159
+ onClick: () => onButtonClick(suggestion),
160
+ dataTestId: SUGGESTION_BAR_BUTTON_TESTID
161
+ }, `animation-dupe-${i}`))] })
162
+ })]
163
+ });
164
+ };
165
+
166
+ //#endregion
167
+ export { SuggestionButtonContainer as t };
@@ -0,0 +1,39 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
13
+ key = keys[i];
14
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
22
+ value: mod,
23
+ enumerable: true
24
+ }) : target, mod));
25
+
26
+ //#endregion
27
+
28
+ Object.defineProperty(exports, '__commonJS', {
29
+ enumerable: true,
30
+ get: function () {
31
+ return __commonJS;
32
+ }
33
+ });
34
+ Object.defineProperty(exports, '__toESM', {
35
+ enumerable: true,
36
+ get: function () {
37
+ return __toESM;
38
+ }
39
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envive-ai/react-widgets",
3
- "version": "0.1.1",
3
+ "version": "0.1.2-arthur-1",
4
4
  "description": "React widget library for Envive services.",
5
5
  "keywords": [
6
6
  "react",
@@ -32,8 +32,8 @@
32
32
  "get-merchants": "tsx ./.storybook/getMerchants.ts"
33
33
  },
34
34
  "dependencies": {
35
- "@envive-ai/react-hooks": "0.2.7",
36
- "@envive-ai/react-toolkit": "*",
35
+ "@envive-ai/react-hooks": "0.2.8",
36
+ "@envive-ai/react-toolkit": "0.2.13-arthur-1",
37
37
  "@tailwindcss/typography": "^0.5.15",
38
38
  "classnames": "^2.5.1",
39
39
  "framer-motion": "^12.23.24",
@@ -65,9 +65,21 @@
65
65
  "vitest": "^3.2.4"
66
66
  },
67
67
  "exports": {
68
- ".": {
69
- "import": "./dist/index.js",
70
- "require": "./dist/index.cjs"
68
+ "./SearchResults": {
69
+ "import": "./dist/SearchResults/index.js",
70
+ "require": "./dist/SearchResults/index.cjs"
71
+ },
72
+ "./SearchZeroState": {
73
+ "import": "./dist/SearchZeroState/index.js",
74
+ "require": "./dist/SearchZeroState/index.cjs"
75
+ },
76
+ "./SuggestionBar": {
77
+ "import": "./dist/SuggestionBar/index.js",
78
+ "require": "./dist/SuggestionBar/index.cjs"
79
+ },
80
+ "./SuggestionButtonContainer": {
81
+ "import": "./dist/SuggestionButtonContainer/index.js",
82
+ "require": "./dist/SuggestionButtonContainer/index.cjs"
71
83
  },
72
84
  "./package.json": "./package.json"
73
85
  },
@@ -0,0 +1,57 @@
1
+ import { SearchIconVariant } from "@envive-ai/react-hooks/contexts/types";
2
+ import AiSearchBold from "@envive-ai/react-icons/AiSearchBold";
3
+ import AiSearchThin from "@envive-ai/react-icons/AiSearchThin";
4
+ import { Typography } from "@envive-ai/react-toolkit/Typography";
5
+ import classNames from "classnames";
6
+ import React from "react";
7
+
8
+ const SEARCH_ENTRYPOINT_BUTTON_TESTID = "spiffy-search-entrypoint-button";
9
+
10
+ interface SearchIconProps {
11
+ size?: number; // in px
12
+ variant?: SearchIconVariant;
13
+ color?: string;
14
+ onClick: () => void;
15
+ label?: string;
16
+ entryPointRef?: React.Ref<HTMLButtonElement>;
17
+ }
18
+
19
+ export const SearchIcon: React.FC<SearchIconProps> = ({
20
+ size = 22,
21
+ variant = 'thin',
22
+ color = 'currentColor',
23
+ onClick,
24
+ label,
25
+ entryPointRef,
26
+ }) => {
27
+ const containerClasses = classNames([
28
+ 'spiffy-global-search-input-container',
29
+ 'spiffy-tw-relative',
30
+ 'spiffy-tw-flex',
31
+ 'spiffy-tw-items-center',
32
+ ]);
33
+
34
+ const iconStrokeWidth = variant === 'thin' ? 'inherit' : '2px';
35
+
36
+ const IconComponent = {
37
+ thin: AiSearchThin,
38
+ bold: AiSearchBold,
39
+ }[variant];
40
+
41
+ return (
42
+ <button
43
+ className={containerClasses}
44
+ type="button"
45
+ onClick={onClick}
46
+ data-testid={SEARCH_ENTRYPOINT_BUTTON_TESTID}
47
+ ref={entryPointRef}
48
+ >
49
+ <IconComponent style={{ width: size, height: size }} fill={color} strokeWidth={iconStrokeWidth} />
50
+ {label && (
51
+ <Typography variant="body3" className="spiffy-global-search-text">
52
+ {label}
53
+ </Typography>
54
+ )}
55
+ </button>
56
+ );
57
+ };
@@ -0,0 +1,81 @@
1
+ import React from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import classNames from 'classnames';
4
+ import { createPortal } from 'react-dom';
5
+ import { getOverlayPortalTarget } from './overlay/overlayHostLocator';
6
+
7
+ export interface SearchOverlayProps {
8
+ children?: React.ReactNode;
9
+ className?: string;
10
+ dataTestId?: string;
11
+ role?: string;
12
+ ariaModal?: boolean;
13
+ ariaLabelledby?: string;
14
+ id?: string;
15
+ usingPortal?: boolean;
16
+ }
17
+
18
+ export const SearchOverlay = React.forwardRef<HTMLDivElement, SearchOverlayProps>(
19
+ ({ children, className, dataTestId, role, ariaModal, ariaLabelledby, id, usingPortal }, ref) => {
20
+ const overlayClasses = classNames(
21
+ 'spiffy-search-overlay',
22
+ 'spiffy-tw-fixed',
23
+ 'spiffy-tw-top-[0]',
24
+ 'spiffy-tw-left-[0]',
25
+ 'spiffy-tw-h-[100vh]',
26
+ 'spiffy-tw-w-full',
27
+ 'spiffy-h-[calc(100%-1rem)]',
28
+ 'spiffy-tw-px-[24px] spiffy-tw-pt-[16px] sm:spiffy-tw-px-[41px] sm:spiffy-tw-pt-[40px]',
29
+ 'spiffy-tw-z-[2147483647]',
30
+ 'spiffy-tw-overflow-y-auto',
31
+ 'spiffy-tw-overflow-x-hidden',
32
+ className,
33
+ );
34
+ const overlayContentClasses = classNames(
35
+ 'spiffy-search-overlay-content',
36
+ 'spiffy-tw-flex spiffy-tw-flex-col',
37
+ 'spiffy-tw-min-h-full',
38
+ className,
39
+ );
40
+
41
+ const node = (
42
+ <motion.div
43
+ ref={ref}
44
+ className={overlayClasses}
45
+ initial={{ opacity: 0 }}
46
+ animate={{ opacity: 1 }}
47
+ exit={{ opacity: 0 }}
48
+ transition={{ duration: 0.2 }}
49
+ >
50
+ <div
51
+ className={overlayContentClasses}
52
+ data-testid={dataTestId}
53
+ role={role}
54
+ aria-modal={ariaModal}
55
+ aria-labelledby={ariaLabelledby}
56
+ id={id}
57
+ >
58
+ {children}
59
+ </div>
60
+ </motion.div>
61
+ );
62
+
63
+ if (!usingPortal) {
64
+ return node;
65
+ }
66
+
67
+ // If we are usingPortal, we need to create a portal widget in the orgConfig
68
+ // so that we can properly identify the portal target. This is often used to
69
+ // get around z-index context hell because it will move the overlay wherever
70
+ // you need to insert it. In most cases, appending it as a child of body is
71
+ // sufficient. Typically this is not needed, but look into how it's done in
72
+ // Bandolier for more info.
73
+ try {
74
+ const target = getOverlayPortalTarget();
75
+ return createPortal(node, target);
76
+ } catch (err) {
77
+ // If host is missing (misconfig), fall back inline overlay
78
+ return node;
79
+ }
80
+ },
81
+ );