@seekho/ui 0.1.9 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,391 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
4
- var reactHotkeysHook = require('react-hotkeys-hook');
3
+ var React = require('react');
5
4
  var jsxRuntime = require('react/jsx-runtime');
5
+ var reactHotkeysHook = require('react-hotkeys-hook');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
8
 
7
- // src/components/Modal/Modal.tsx
9
+ var React__default = /*#__PURE__*/_interopDefault(React);
10
+
11
+ // src/components/AutoComplete/AutoComplete.tsx
12
+ function AutoComplete({
13
+ label,
14
+ value,
15
+ options,
16
+ disabled = false,
17
+ error = false,
18
+ className,
19
+ getOptionLabel,
20
+ isOptionEqualToValue,
21
+ isLoading = false,
22
+ renderOption,
23
+ onChange,
24
+ onInputChange
25
+ }) {
26
+ const inputId = React.useId();
27
+ const containerRef = React.useRef(null);
28
+ const listRef = React.useRef(null);
29
+ const [open, setOpen] = React.useState(false);
30
+ const [inputValue, setInputValue] = React.useState(
31
+ value ? getOptionLabel(value) : ""
32
+ );
33
+ const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
34
+ const filteredOptions = options.filter(
35
+ (option) => getOptionLabel(option).toLowerCase().includes(inputValue.toLowerCase())
36
+ );
37
+ const handleInputChange = (e) => {
38
+ const val = e.target.value;
39
+ setInputValue(val);
40
+ setOpen(true);
41
+ setHighlightedIndex(-1);
42
+ onInputChange == null ? void 0 : onInputChange(val);
43
+ };
44
+ const handleSelect = ({ option }) => {
45
+ onChange(option);
46
+ setInputValue(getOptionLabel(option));
47
+ setOpen(false);
48
+ setHighlightedIndex(-1);
49
+ };
50
+ const handleKeyDown = (e) => {
51
+ if (!open && (e.key === "ArrowDown" || e.key === "ArrowUp")) {
52
+ setOpen(true);
53
+ return;
54
+ }
55
+ if (e.key === "ArrowDown") {
56
+ setHighlightedIndex(
57
+ (prev) => Math.min(prev + 1, filteredOptions.length - 1)
58
+ );
59
+ } else if (e.key === "ArrowUp") {
60
+ setHighlightedIndex((prev) => Math.max(prev - 1, 0));
61
+ } else if (e.key === "Enter" && highlightedIndex >= 0) {
62
+ handleSelect({ option: filteredOptions[highlightedIndex] });
63
+ } else if (e.key === "Escape") {
64
+ setOpen(false);
65
+ setInputValue(value ? getOptionLabel(value) : "");
66
+ }
67
+ };
68
+ const isSelected = ({ option }) => {
69
+ if (!value) return false;
70
+ return isOptionEqualToValue ? isOptionEqualToValue(option, value) : getOptionLabel(option) === getOptionLabel(value);
71
+ };
72
+ React.useEffect(() => {
73
+ setInputValue(value ? getOptionLabel(value) : "");
74
+ }, [value]);
75
+ React.useEffect(() => {
76
+ const handleClickOutside = (e) => {
77
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
78
+ setOpen(false);
79
+ setInputValue(value ? getOptionLabel(value) : "");
80
+ }
81
+ };
82
+ document.addEventListener("mousedown", handleClickOutside);
83
+ return () => document.removeEventListener("mousedown", handleClickOutside);
84
+ }, [value]);
85
+ const isFloated = !!(inputValue || open);
86
+ return /* @__PURE__ */ jsxRuntime.jsxs(
87
+ "div",
88
+ {
89
+ ref: containerRef,
90
+ className: ["relative w-full", className || ""].join(" "),
91
+ children: [
92
+ /* @__PURE__ */ jsxRuntime.jsxs(
93
+ "div",
94
+ {
95
+ className: [
96
+ "relative flex items-center rounded-md bg-white px-3 py-2 gap-2 transition-colors",
97
+ disabled ? "bg-gray-50 opacity-60 cursor-not-allowed" : ""
98
+ ].join(" "),
99
+ children: [
100
+ /* @__PURE__ */ jsxRuntime.jsx(
101
+ "fieldset",
102
+ {
103
+ className: [
104
+ "absolute inset-0 rounded-md border pointer-events-none transition-colors",
105
+ error ? "border-red-400" : open ? "border-basePurple border-2" : "border-gray-300"
106
+ ].join(" "),
107
+ style: { paddingLeft: "8px" },
108
+ children: label && /* @__PURE__ */ jsxRuntime.jsx(
109
+ "legend",
110
+ {
111
+ className: "text-[11px] transition-all duration-150 h-0 overflow-visible",
112
+ style: {
113
+ maxWidth: isFloated ? "100%" : "0.01px",
114
+ visibility: "hidden",
115
+ whiteSpace: "nowrap"
116
+ },
117
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1 text-[11px]", children: label })
118
+ }
119
+ )
120
+ }
121
+ ),
122
+ label && /* @__PURE__ */ jsxRuntime.jsx(
123
+ "label",
124
+ {
125
+ htmlFor: inputId,
126
+ className: [
127
+ "absolute left-3 transition-all duration-150 pointer-events-none",
128
+ isFloated ? "-top-[9px] text-[11px] bg-white px-1" : "top-1/2 -translate-y-1/2 text-[13px]",
129
+ error ? "text-red-500" : isFloated || open ? "text-basePurple" : "text-gray-500"
130
+ ].join(" "),
131
+ children: label
132
+ }
133
+ ),
134
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
135
+ "input",
136
+ {
137
+ id: inputId,
138
+ value: inputValue,
139
+ disabled,
140
+ autoComplete: "off",
141
+ className: "w-full text-[13px] focus:outline-none bg-transparent text-gray-800 disabled:cursor-not-allowed",
142
+ onChange: handleInputChange,
143
+ onFocus: () => setOpen(true),
144
+ onKeyDown: handleKeyDown
145
+ }
146
+ ) }),
147
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [
148
+ isLoading && /* @__PURE__ */ jsxRuntime.jsxs(
149
+ "svg",
150
+ {
151
+ className: "animate-spin w-4 h-4 text-gray-400",
152
+ xmlns: "http://www.w3.org/2000/svg",
153
+ fill: "none",
154
+ viewBox: "0 0 24 24",
155
+ children: [
156
+ /* @__PURE__ */ jsxRuntime.jsx(
157
+ "circle",
158
+ {
159
+ className: "opacity-25",
160
+ cx: "12",
161
+ cy: "12",
162
+ r: "10",
163
+ stroke: "currentColor",
164
+ strokeWidth: "4"
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsxRuntime.jsx(
168
+ "path",
169
+ {
170
+ className: "opacity-75",
171
+ fill: "currentColor",
172
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
173
+ }
174
+ )
175
+ ]
176
+ }
177
+ ),
178
+ value && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
179
+ "button",
180
+ {
181
+ type: "button",
182
+ onClick: () => {
183
+ onChange(null);
184
+ setInputValue("");
185
+ onInputChange == null ? void 0 : onInputChange("");
186
+ },
187
+ className: "text-gray-400 hover:text-gray-600 transition-colors",
188
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
189
+ "svg",
190
+ {
191
+ xmlns: "http://www.w3.org/2000/svg",
192
+ className: "w-3.5 h-3.5",
193
+ viewBox: "0 0 24 24",
194
+ fill: "none",
195
+ stroke: "currentColor",
196
+ strokeWidth: "2.5",
197
+ strokeLinecap: "round",
198
+ strokeLinejoin: "round",
199
+ children: [
200
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
201
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
202
+ ]
203
+ }
204
+ )
205
+ }
206
+ ),
207
+ /* @__PURE__ */ jsxRuntime.jsx(
208
+ "button",
209
+ {
210
+ type: "button",
211
+ disabled,
212
+ onClick: () => !disabled && setOpen((prev) => !prev),
213
+ className: "text-gray-400 hover:text-gray-600 transition-colors disabled:cursor-not-allowed",
214
+ children: /* @__PURE__ */ jsxRuntime.jsx(
215
+ "svg",
216
+ {
217
+ xmlns: "http://www.w3.org/2000/svg",
218
+ className: [
219
+ "w-4 h-4 transition-transform",
220
+ open ? "rotate-180" : ""
221
+ ].join(" "),
222
+ viewBox: "0 0 24 24",
223
+ fill: "none",
224
+ stroke: "currentColor",
225
+ strokeWidth: "2",
226
+ strokeLinecap: "round",
227
+ strokeLinejoin: "round",
228
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
229
+ }
230
+ )
231
+ }
232
+ )
233
+ ] })
234
+ ]
235
+ }
236
+ ),
237
+ open && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
238
+ "ul",
239
+ {
240
+ ref: listRef,
241
+ className: "absolute z-50 mt-1 w-full bg-white border border-gray-200 rounded-md shadow-lg max-h-56 overflow-y-auto",
242
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-[13px] text-gray-400", children: "Loading..." }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-3 py-2 text-[13px] text-gray-400", children: "No options" }) : filteredOptions.map((option, idx) => {
243
+ const optionProps = {
244
+ onClick: () => handleSelect({ option }),
245
+ onMouseEnter: () => setHighlightedIndex(idx),
246
+ className: [
247
+ "px-3 py-2 text-[13px] cursor-pointer select-none",
248
+ highlightedIndex === idx ? "bg-basePurple/10 text-basePurple" : "text-gray-700",
249
+ isSelected({ option }) ? "font-semibold" : ""
250
+ ].join(" ")
251
+ };
252
+ return renderOption ? /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: renderOption(optionProps, option) }, idx) : /* @__PURE__ */ jsxRuntime.jsx(
253
+ "li",
254
+ {
255
+ onMouseDown: () => handleSelect({ option }),
256
+ onMouseEnter: () => setHighlightedIndex(idx),
257
+ className: optionProps.className,
258
+ children: getOptionLabel(option)
259
+ },
260
+ idx
261
+ );
262
+ })
263
+ }
264
+ )
265
+ ]
266
+ }
267
+ );
268
+ }
269
+ var ButtonLoader = ({ className }) => {
270
+ return /* @__PURE__ */ jsxRuntime.jsxs(
271
+ "svg",
272
+ {
273
+ xmlns: "http://www.w3.org/2000/svg",
274
+ fill: "none",
275
+ viewBox: "0 0 24 24",
276
+ className: `animate-spin h-5 w-5 text-white ${className || ""}`,
277
+ children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx(
279
+ "circle",
280
+ {
281
+ className: "opacity-25",
282
+ cx: "12",
283
+ cy: "12",
284
+ r: "10",
285
+ stroke: "currentColor",
286
+ strokeWidth: "4"
287
+ }
288
+ ),
289
+ /* @__PURE__ */ jsxRuntime.jsx(
290
+ "path",
291
+ {
292
+ className: "opacity-75",
293
+ fill: "currentColor",
294
+ d: "M4 12a8 8 0 018-8v4l3-3-3-3v4a8 8 0 018 8h-4l3 3 3-3h-4a8 8 0 01-8 8v-4l-3 3 3 3v-4a8 8 0 01-8-8z"
295
+ }
296
+ )
297
+ ]
298
+ }
299
+ );
300
+ };
301
+
302
+ // src/utils/helperFunctions.ts
303
+ var cn = (...classes) => classes.filter(Boolean).join(" ");
304
+ var handleCopyTextToClipboard = async ({
305
+ clipboardText
306
+ }) => {
307
+ if (clipboardText === void 0 || clipboardText === null) return false;
308
+ const text = String(clipboardText);
309
+ if (navigator.clipboard && window.isSecureContext) {
310
+ try {
311
+ await navigator.clipboard.writeText(text);
312
+ return true;
313
+ } catch (err) {
314
+ console.warn(
315
+ "navigator.clipboard.writeText failed, falling back to execCommand",
316
+ err
317
+ );
318
+ }
319
+ }
320
+ try {
321
+ const textArea = document.createElement("textarea");
322
+ textArea.value = text;
323
+ textArea.style.position = "fixed";
324
+ textArea.style.top = "0";
325
+ textArea.style.left = "0";
326
+ textArea.style.opacity = "0";
327
+ textArea.setAttribute("readonly", "");
328
+ document.body.appendChild(textArea);
329
+ textArea.focus();
330
+ textArea.select();
331
+ textArea.setSelectionRange(0, text.length);
332
+ const success = document.execCommand("copy");
333
+ document.body.removeChild(textArea);
334
+ if (success) return true;
335
+ } catch (err) {
336
+ console.warn("execCommand copy failed", err);
337
+ }
338
+ try {
339
+ window.prompt("Copy to clipboard: Cmd+C, Enter", text);
340
+ return false;
341
+ } catch (e) {
342
+ return false;
343
+ }
344
+ };
345
+ var CopyId = ({
346
+ id,
347
+ className,
348
+ displayHash = true,
349
+ onCopy
350
+ }) => {
351
+ const handleClick = async (e) => {
352
+ e.stopPropagation();
353
+ const success = await handleCopyTextToClipboard({ clipboardText: id });
354
+ onCopy == null ? void 0 : onCopy(success);
355
+ };
356
+ return /* @__PURE__ */ jsxRuntime.jsxs(
357
+ "button",
358
+ {
359
+ onClick: handleClick,
360
+ className: [
361
+ "border border-basePurple px-3 py-[1px] text-basePurple",
362
+ "rounded-[24px] text-[11px] mt-1 hover:bg-basePurple/10 transition-colors",
363
+ className || ""
364
+ ].join(" "),
365
+ children: [
366
+ displayHash && "#",
367
+ id
368
+ ]
369
+ }
370
+ );
371
+ };
372
+ var CustomAnchor = ({
373
+ displayText,
374
+ href,
375
+ className,
376
+ openInNewTab = false
377
+ }) => {
378
+ return /* @__PURE__ */ jsxRuntime.jsx(
379
+ "a",
380
+ {
381
+ href,
382
+ className: `hover:text-black hover:no-underline ${className || ""}`,
383
+ target: openInNewTab ? "_blank" : "",
384
+ rel: openInNewTab ? "noopener noreferrer" : void 0,
385
+ children: displayText
386
+ }
387
+ );
388
+ };
8
389
 
9
390
  // src/utils/modalStack.ts
10
391
  var stack = [];
@@ -32,8 +413,8 @@ function Modal({
32
413
  handleConfirmation,
33
414
  handleConfirmationBtnText = "Confirm"
34
415
  }) {
35
- const modalId = react.useId();
36
- react.useEffect(() => {
416
+ const modalId = React.useId();
417
+ React.useEffect(() => {
37
418
  if (show) handlePushModal({ id: modalId });
38
419
  return () => handlePopModal({ id: modalId });
39
420
  }, [show, modalId]);
@@ -160,11 +541,17 @@ function ReadMore({
160
541
  displayText,
161
542
  className,
162
543
  numberOfCharactersToShow = 300,
163
- handleCopyDisplayText,
544
+ showCopy = false,
545
+ onCopy,
164
546
  handleToggleReadMore
165
547
  }) {
166
548
  const isExpanded = readMore == null ? void 0 : readMore[index];
167
549
  const isLong = (displayText == null ? void 0 : displayText.length) > numberOfCharactersToShow;
550
+ const handleCopy = async (e) => {
551
+ e.stopPropagation();
552
+ const success = await handleCopyTextToClipboard({ clipboardText: displayText });
553
+ onCopy == null ? void 0 : onCopy(success);
554
+ };
168
555
  return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
169
556
  "p",
170
557
  {
@@ -181,32 +568,23 @@ function ReadMore({
181
568
  onClick: handleToggleReadMore,
182
569
  className: "text-basePurple cursor-pointer font-semibold text-[11px]",
183
570
  children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
184
- handleCopyDisplayText && /* @__PURE__ */ jsxRuntime.jsx(
185
- "span",
571
+ showCopy && /* @__PURE__ */ jsxRuntime.jsx("span", { onClick: handleCopy, children: /* @__PURE__ */ jsxRuntime.jsxs(
572
+ "svg",
186
573
  {
187
- onClick: (e) => {
188
- e.stopPropagation();
189
- handleCopyDisplayText({ displayText });
190
- },
191
- children: /* @__PURE__ */ jsxRuntime.jsxs(
192
- "svg",
193
- {
194
- xmlns: "http://www.w3.org/2000/svg",
195
- className: "text-gray-500 w-[14px] h-[14px]",
196
- viewBox: "0 0 24 24",
197
- fill: "none",
198
- stroke: "currentColor",
199
- strokeWidth: "2",
200
- strokeLinecap: "round",
201
- strokeLinejoin: "round",
202
- children: [
203
- /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
204
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
205
- ]
206
- }
207
- )
574
+ xmlns: "http://www.w3.org/2000/svg",
575
+ className: "text-gray-500 w-[14px] h-[14px]",
576
+ viewBox: "0 0 24 24",
577
+ fill: "none",
578
+ stroke: "currentColor",
579
+ strokeWidth: "2",
580
+ strokeLinecap: "round",
581
+ strokeLinejoin: "round",
582
+ children: [
583
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
584
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
585
+ ]
208
586
  }
209
- ),
587
+ ) }),
210
588
  " ",
211
589
  "...Read Less"
212
590
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "...Read More" })
@@ -216,8 +594,79 @@ function ReadMore({
216
594
  }
217
595
  ) });
218
596
  }
597
+ function SearchBar({
598
+ value,
599
+ placeHolder,
600
+ wrapperClass,
601
+ className,
602
+ searchParamQuery = "",
603
+ onChange,
604
+ handleInputKey,
605
+ handleClearInput
606
+ }) {
607
+ const showClear = searchParamQuery || value;
608
+ return /* @__PURE__ */ jsxRuntime.jsxs(
609
+ "div",
610
+ {
611
+ className: [
612
+ "flex items-center rounded-full justify-between border px-2 bg-white",
613
+ wrapperClass || ""
614
+ ].join(" "),
615
+ children: [
616
+ /* @__PURE__ */ jsxRuntime.jsxs(
617
+ "svg",
618
+ {
619
+ xmlns: "http://www.w3.org/2000/svg",
620
+ className: "text-gray-400 w-[14px] h-[14px] ml-2 shrink-0",
621
+ viewBox: "0 0 24 24",
622
+ fill: "none",
623
+ stroke: "currentColor",
624
+ strokeWidth: "2",
625
+ strokeLinecap: "round",
626
+ strokeLinejoin: "round",
627
+ children: [
628
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "8" }),
629
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
630
+ ]
631
+ }
632
+ ),
633
+ /* @__PURE__ */ jsxRuntime.jsx(
634
+ "input",
635
+ {
636
+ value,
637
+ placeholder: placeHolder,
638
+ className: [
639
+ "w-[95%] focus:outline-none rounded-r-full",
640
+ "placeholder:text-[13px] text-[13px] py-[8px] px-2",
641
+ className || ""
642
+ ].join(" "),
643
+ onKeyPress: handleInputKey,
644
+ onChange
645
+ }
646
+ ),
647
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[20px] shrink-0", children: showClear && handleClearInput && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleClearInput, children: /* @__PURE__ */ jsxRuntime.jsxs(
648
+ "svg",
649
+ {
650
+ xmlns: "http://www.w3.org/2000/svg",
651
+ className: "w-[16px] h-[16px]",
652
+ viewBox: "0 0 24 24",
653
+ fill: "none",
654
+ stroke: "currentColor",
655
+ strokeWidth: "2.5",
656
+ strokeLinecap: "round",
657
+ strokeLinejoin: "round",
658
+ children: [
659
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
660
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
661
+ ]
662
+ }
663
+ ) }) })
664
+ ]
665
+ }
666
+ );
667
+ }
219
668
  function useLocalStorage(key, initialValue) {
220
- const [storedValue, setStoredValue] = react.useState(() => {
669
+ const [storedValue, setStoredValue] = React.useState(() => {
221
670
  if (typeof window === "undefined") return initialValue;
222
671
  try {
223
672
  const item = window.localStorage.getItem(key);
@@ -250,14 +699,15 @@ function useLocalStorage(key, initialValue) {
250
699
  return [storedValue, setValue, remove];
251
700
  }
252
701
 
253
- // src/utils/cn.ts
254
- function cn(...classes) {
255
- return classes.filter(Boolean).join(" ");
256
- }
257
-
702
+ exports.AutoComplete = AutoComplete;
703
+ exports.ButtonLoader = ButtonLoader;
704
+ exports.CopyId = CopyId;
705
+ exports.CustomAnchor = CustomAnchor;
258
706
  exports.Modal = Modal;
259
707
  exports.ReadMore = ReadMore;
708
+ exports.SearchBar = SearchBar;
260
709
  exports.cn = cn;
710
+ exports.handleCopyTextToClipboard = handleCopyTextToClipboard;
261
711
  exports.useLocalStorage = useLocalStorage;
262
712
  //# sourceMappingURL=index.js.map
263
713
  //# sourceMappingURL=index.js.map