@knymbus/voxel-ui 1.0.11 → 1.0.13

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.
@@ -0,0 +1,452 @@
1
+ import { t as e } from "./jsx-runtime-Boo2vksn.js";
2
+ import { t } from "./Button-BgQwvn3C.js";
3
+ import { E as n, S as r } from "./icons-BpfDVwCQ.js";
4
+ import { useEffect as i, useRef as a, useState as o } from "react";
5
+ //#region src/components/search/types.ts
6
+ var s = {
7
+ colors: {
8
+ bgInput: "var(--color-vsc-bg-input, #f6f8fa)",
9
+ border: "var(--color-vsc-border, #e4e4e7)",
10
+ borderAccent: "var(--color-vsc-accent, #007acc)",
11
+ borderAccentHover: "var(--color-vsc-accent-hover, #0062a3)",
12
+ text: "var(--color-vsc-text, #333333)",
13
+ muted: "var(--color-vsc-muted, #6a737d)",
14
+ sidebarBg: "var(--color-vsc-sidebar, #f3f3f3)",
15
+ hoverBg: "var(--color-vsc-hover, #e8e8e8)",
16
+ accentBgLight: "rgba(0, 122, 204, 0.1)"
17
+ },
18
+ transitions: { smooth: "all 200ms cubic-bezier(0.34, 1.56, 0.64, 1)" }
19
+ }, c = e();
20
+ function l({ isOpen: e, value: t, menuResults: n, onResultClick: r, onViewMoreClick: i, onCloseMenu: a }) {
21
+ let [l, u] = o(null), [d, f] = o(!1);
22
+ return !e || !t ? null : /* @__PURE__ */ (0, c.jsxs)("div", {
23
+ style: {
24
+ position: "absolute",
25
+ top: "36px",
26
+ left: 0,
27
+ width: "100%",
28
+ backgroundColor: s.colors.sidebarBg,
29
+ border: `1px solid ${s.colors.border}`,
30
+ borderRadius: "4px",
31
+ boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.2)",
32
+ zIndex: 50,
33
+ padding: "4px",
34
+ display: "flex",
35
+ flexDirection: "column",
36
+ maxHeight: "256px"
37
+ },
38
+ children: [/* @__PURE__ */ (0, c.jsx)("div", {
39
+ style: {
40
+ overflowY: "auto",
41
+ flex: 1
42
+ },
43
+ children: n.length === 0 ? /* @__PURE__ */ (0, c.jsx)("div", {
44
+ style: {
45
+ padding: "16px",
46
+ textAlign: "center",
47
+ fontSize: "11px",
48
+ color: s.colors.muted,
49
+ fontStyle: "italic"
50
+ },
51
+ children: "No indexed record entities match your text query constraints."
52
+ }) : n.map((e) => /* @__PURE__ */ (0, c.jsxs)("div", {
53
+ onMouseEnter: () => u(e.id),
54
+ onMouseLeave: () => u(null),
55
+ onClick: () => {
56
+ r && r(e), a();
57
+ },
58
+ style: {
59
+ width: "100%",
60
+ padding: "8px",
61
+ backgroundColor: l === e.id ? s.colors.hoverBg : "transparent",
62
+ borderRadius: "2px",
63
+ cursor: "pointer",
64
+ display: "flex",
65
+ flexDirection: "column",
66
+ gap: "2px",
67
+ transition: "background-color 100ms",
68
+ boxSizing: "border-box"
69
+ },
70
+ children: [/* @__PURE__ */ (0, c.jsxs)("div", {
71
+ style: {
72
+ fontWeight: 600,
73
+ color: s.colors.text,
74
+ display: "flex",
75
+ justifyContent: "space-between",
76
+ alignItems: "center",
77
+ width: "100%"
78
+ },
79
+ children: [/* @__PURE__ */ (0, c.jsx)("span", {
80
+ style: {
81
+ whiteSpace: "nowrap",
82
+ overflow: "hidden",
83
+ textOverflow: "ellipsis",
84
+ flex: 1
85
+ },
86
+ children: e.title
87
+ }), e.category && /* @__PURE__ */ (0, c.jsx)("span", {
88
+ style: {
89
+ fontSize: "9px",
90
+ fontFamily: "monospace",
91
+ fontWeight: "bold",
92
+ backgroundColor: s.colors.accentBgLight,
93
+ border: "1px solid rgba(0, 122, 204, 0.2)",
94
+ color: s.colors.borderAccent,
95
+ padding: "2px 4px",
96
+ borderRadius: "2px",
97
+ textTransform: "uppercase",
98
+ marginLeft: "8px",
99
+ flexShrink: 0
100
+ },
101
+ children: e.category
102
+ })]
103
+ }), e.subtitle && /* @__PURE__ */ (0, c.jsx)("div", {
104
+ style: {
105
+ fontSize: "10px",
106
+ color: s.colors.muted,
107
+ whiteSpace: "nowrap",
108
+ overflow: "hidden",
109
+ textOverflow: "ellipsis"
110
+ },
111
+ children: e.subtitle
112
+ })]
113
+ }, e.id))
114
+ }), n.length > 0 && i && /* @__PURE__ */ (0, c.jsx)("button", {
115
+ onMouseEnter: () => f(!0),
116
+ onMouseLeave: () => f(!1),
117
+ onClick: () => {
118
+ i(), a();
119
+ },
120
+ style: {
121
+ width: "100%",
122
+ border: "none",
123
+ borderTop: `1px solid ${s.colors.border}`,
124
+ backgroundColor: d ? s.colors.hoverBg : "transparent",
125
+ padding: "8px",
126
+ textAlign: "center",
127
+ fontSize: "10px",
128
+ fontWeight: "bold",
129
+ color: s.colors.borderAccent,
130
+ letterSpacing: "0.5px",
131
+ textTransform: "uppercase",
132
+ transition: "background-color 150ms",
133
+ borderRadius: "0 0 2px 2px",
134
+ cursor: "pointer"
135
+ },
136
+ children: "View All Matching Search Metrics Records →"
137
+ })]
138
+ });
139
+ }
140
+ //#endregion
141
+ //#region src/components/search/SearchInput.tsx
142
+ function u({ variant: e = "simple", value: u, onChange: d, onClear: f, placeholder: p = "Search manifests or tracking codes...", resultsCount: m = 0, menuResults: h = [], onResultClick: g, onViewMoreClick: _, className: v = "", showFloatPeek: y = !1 }) {
143
+ let [b, x] = o(!1), [S, C] = o(!1), [w, T] = o(!1), [E, D] = o(!1), O = a(null), k = a(null);
144
+ i(() => {
145
+ let t = (t) => {
146
+ O.current && !O.current.contains(t.target) && (C(!1), e === "float" && u === "" && x(!1));
147
+ };
148
+ return window.addEventListener("mousedown", t), () => window.removeEventListener("mousedown", t);
149
+ }, [e, u]);
150
+ let A = (e) => {
151
+ e.stopPropagation(), d(""), f && f(), k.current && k.current.focus();
152
+ }, j = () => {
153
+ x(!0), setTimeout(() => k.current?.focus(), 50);
154
+ }, M = {
155
+ position: "relative",
156
+ display: "flex",
157
+ flexDirection: "column",
158
+ fontFamily: "sans-serif",
159
+ fontSize: "12px",
160
+ userSelect: "none",
161
+ boxSizing: "border-box"
162
+ }, N = {
163
+ position: "relative",
164
+ display: "flex",
165
+ alignItems: "center",
166
+ backgroundColor: s.colors.bgInput,
167
+ border: `1px solid ${E || e === "float" && b ? s.colors.borderAccent : w ? s.colors.borderAccentHover : s.colors.border}`,
168
+ borderRadius: "2px",
169
+ height: "32px",
170
+ transition: s.transitions.smooth,
171
+ boxSizing: "border-box"
172
+ }, P = {
173
+ width: "100%",
174
+ height: "100%",
175
+ backgroundColor: "transparent",
176
+ color: s.colors.text,
177
+ border: "none",
178
+ outline: "none",
179
+ padding: "0 32px",
180
+ fontSize: "12px",
181
+ boxSizing: "border-box"
182
+ };
183
+ if (e === "simple") {
184
+ let e = m > 0 && u.length > 0;
185
+ return /* @__PURE__ */ (0, c.jsxs)("div", {
186
+ style: M,
187
+ className: v,
188
+ children: [/* @__PURE__ */ (0, c.jsxs)("div", {
189
+ style: N,
190
+ onMouseEnter: () => T(!0),
191
+ onMouseLeave: () => T(!1),
192
+ children: [
193
+ /* @__PURE__ */ (0, c.jsx)("div", {
194
+ style: {
195
+ position: "absolute",
196
+ left: "10px",
197
+ display: "flex",
198
+ alignItems: "center",
199
+ color: w ? s.colors.text : s.colors.muted
200
+ },
201
+ children: /* @__PURE__ */ (0, c.jsx)(r, { size: 14 })
202
+ }),
203
+ /* @__PURE__ */ (0, c.jsx)("input", {
204
+ ref: k,
205
+ type: "text",
206
+ value: u,
207
+ onChange: (e) => d(e.target.value),
208
+ onFocus: () => D(!0),
209
+ onBlur: () => D(!1),
210
+ placeholder: p,
211
+ style: P
212
+ }),
213
+ u && /* @__PURE__ */ (0, c.jsx)("div", {
214
+ style: {
215
+ position: "absolute",
216
+ right: "4px",
217
+ top: "50%",
218
+ transform: "translateY(-50%)",
219
+ display: "flex",
220
+ alignItems: "center"
221
+ },
222
+ children: /* @__PURE__ */ (0, c.jsx)(t, {
223
+ icon: n,
224
+ color: "ghost",
225
+ iconOnly: !0,
226
+ onClick: A,
227
+ size: "xs"
228
+ })
229
+ })
230
+ ]
231
+ }), /* @__PURE__ */ (0, c.jsx)("div", {
232
+ style: {
233
+ position: "absolute",
234
+ left: 0,
235
+ right: 0,
236
+ top: "32px",
237
+ zIndex: 10,
238
+ overflow: "hidden",
239
+ transition: s.transitions.smooth,
240
+ height: e ? "24px" : "0px",
241
+ opacity: +!!e,
242
+ transform: e ? "translateY(0px)" : "translateY(-4px)",
243
+ pointerEvents: "none"
244
+ },
245
+ children: /* @__PURE__ */ (0, c.jsx)("div", {
246
+ style: {
247
+ backgroundColor: s.colors.sidebarBg,
248
+ border: `1px solid ${s.colors.border}`,
249
+ borderTop: "none",
250
+ padding: "4px 6px",
251
+ borderRadius: "0 0 2px 2px",
252
+ boxShadow: "0 4px 6px -1px rgba(0,0,0,0.1)"
253
+ },
254
+ children: /* @__PURE__ */ (0, c.jsxs)("p", {
255
+ style: {
256
+ margin: 0,
257
+ fontSize: "10px",
258
+ fontFamily: "monospace",
259
+ color: s.colors.muted,
260
+ whiteSpace: "nowrap",
261
+ overflow: "hidden",
262
+ textOverflow: "ellipsis"
263
+ },
264
+ children: [
265
+ "Showing ",
266
+ /* @__PURE__ */ (0, c.jsx)("span", {
267
+ style: {
268
+ color: s.colors.borderAccent,
269
+ fontWeight: "bold"
270
+ },
271
+ children: m
272
+ }),
273
+ " matching database metrics records"
274
+ ]
275
+ })
276
+ })
277
+ })]
278
+ });
279
+ }
280
+ if (e === "float") {
281
+ let e = y && m > 0 && u.length > 0, i = b || u.length > 0;
282
+ return /* @__PURE__ */ (0, c.jsxs)("div", {
283
+ ref: O,
284
+ style: M,
285
+ className: v,
286
+ children: [/* @__PURE__ */ (0, c.jsx)("div", {
287
+ onMouseEnter: () => T(!0),
288
+ onMouseLeave: () => T(!1),
289
+ style: {
290
+ ...N,
291
+ width: i ? "256px" : "32px",
292
+ justifyContent: i ? "flex-start" : "center",
293
+ backgroundColor: i ? s.colors.bgInput : "transparent",
294
+ borderColor: i ? s.colors.borderAccent : "transparent",
295
+ padding: i ? "0 8px" : "0"
296
+ },
297
+ children: i ? /* @__PURE__ */ (0, c.jsxs)("div", {
298
+ style: {
299
+ position: "relative",
300
+ display: "flex",
301
+ alignItems: "center",
302
+ width: "100%",
303
+ height: "100%"
304
+ },
305
+ children: [
306
+ /* @__PURE__ */ (0, c.jsx)(r, {
307
+ size: 14,
308
+ style: {
309
+ color: s.colors.text,
310
+ flexShrink: 0
311
+ }
312
+ }),
313
+ /* @__PURE__ */ (0, c.jsx)("input", {
314
+ ref: k,
315
+ type: "text",
316
+ value: u,
317
+ onChange: (e) => d(e.target.value),
318
+ placeholder: p,
319
+ style: {
320
+ ...P,
321
+ padding: "0 24px 0 8px"
322
+ }
323
+ }),
324
+ u && /* @__PURE__ */ (0, c.jsx)("div", {
325
+ style: {
326
+ position: "absolute",
327
+ right: 0,
328
+ top: "50%",
329
+ transform: "translateY(-50%)",
330
+ display: "flex",
331
+ alignItems: "center"
332
+ },
333
+ children: /* @__PURE__ */ (0, c.jsx)(t, {
334
+ iconOnly: !0,
335
+ color: "ghost",
336
+ icon: n,
337
+ onClick: A,
338
+ size: "xs"
339
+ })
340
+ })
341
+ ]
342
+ }) : /* @__PURE__ */ (0, c.jsx)(t, {
343
+ iconOnly: !0,
344
+ size: "sm",
345
+ icon: r,
346
+ onClick: j,
347
+ color: "ghost",
348
+ style: { color: s.colors.muted },
349
+ title: "Open Expandable Search"
350
+ })
351
+ }), /* @__PURE__ */ (0, c.jsx)("div", {
352
+ style: {
353
+ position: "absolute",
354
+ top: "32px",
355
+ width: "256px",
356
+ zIndex: 10,
357
+ overflow: "hidden",
358
+ transition: s.transitions.smooth,
359
+ height: e ? "24px" : "0px",
360
+ opacity: +!!e,
361
+ transform: e ? "translateY(0px)" : "translateY(-4px)",
362
+ pointerEvents: "none"
363
+ },
364
+ children: /* @__PURE__ */ (0, c.jsx)("div", {
365
+ style: {
366
+ backgroundColor: s.colors.sidebarBg,
367
+ border: `1px solid ${s.colors.border}`,
368
+ borderTop: "none",
369
+ padding: "4px",
370
+ borderRadius: "0 0 2px 2px",
371
+ boxShadow: "0 4px 6px -1px rgba(0,0,0,0.1)"
372
+ },
373
+ children: /* @__PURE__ */ (0, c.jsxs)("p", {
374
+ style: {
375
+ margin: 0,
376
+ fontSize: "9px",
377
+ fontFamily: "monospace",
378
+ color: s.colors.borderAccent,
379
+ whiteSpace: "nowrap",
380
+ overflow: "hidden",
381
+ textOverflow: "ellipsis"
382
+ },
383
+ children: [
384
+ "Quick Peek: Found ",
385
+ m,
386
+ " rows"
387
+ ]
388
+ })
389
+ })
390
+ })]
391
+ });
392
+ }
393
+ return /* @__PURE__ */ (0, c.jsxs)("div", {
394
+ ref: O,
395
+ style: M,
396
+ className: v,
397
+ children: [/* @__PURE__ */ (0, c.jsxs)("div", {
398
+ style: N,
399
+ onMouseEnter: () => T(!0),
400
+ onMouseLeave: () => T(!1),
401
+ children: [
402
+ /* @__PURE__ */ (0, c.jsx)("div", {
403
+ style: {
404
+ position: "absolute",
405
+ left: "10px",
406
+ display: "flex",
407
+ alignItems: "center",
408
+ color: s.colors.muted
409
+ },
410
+ children: /* @__PURE__ */ (0, c.jsx)(r, { size: 14 })
411
+ }),
412
+ /* @__PURE__ */ (0, c.jsx)("input", {
413
+ ref: k,
414
+ type: "text",
415
+ value: u,
416
+ onChange: (e) => {
417
+ d(e.target.value), C(!0);
418
+ },
419
+ onFocus: () => C(!0),
420
+ placeholder: p,
421
+ style: P
422
+ }),
423
+ u && /* @__PURE__ */ (0, c.jsx)("div", {
424
+ style: {
425
+ position: "absolute",
426
+ right: "4px",
427
+ top: "50%",
428
+ transform: "translateY(-50%)",
429
+ display: "flex",
430
+ alignItems: "center"
431
+ },
432
+ children: /* @__PURE__ */ (0, c.jsx)(t, {
433
+ iconOnly: !0,
434
+ icon: n,
435
+ color: "ghost",
436
+ onClick: A,
437
+ size: "xs"
438
+ })
439
+ })
440
+ ]
441
+ }), /* @__PURE__ */ (0, c.jsx)(l, {
442
+ isOpen: S,
443
+ value: u,
444
+ menuResults: h,
445
+ onResultClick: g,
446
+ onViewMoreClick: _,
447
+ onCloseMenu: () => C(!1)
448
+ })]
449
+ });
450
+ }
451
+ //#endregion
452
+ export { s as n, u as t };
@@ -1,10 +1,3 @@
1
- import { default as React, ReactNode } from 'react';
1
+ import { default as React } from 'react';
2
2
  import { SearchInputProps } from './types';
3
- interface AdvancedSearchInputProps extends Omit<SearchInputProps, 'variant'> {
4
- variant?: 'simple' | 'float' | 'menu';
5
- showFloatPeek?: boolean;
6
- resultIndicatorPanel?: string | ReactNode;
7
- }
8
- export default function SearchInput({ variant, value, onChange, onClear, placeholder, resultsCount, menuResults, onResultClick, onViewMoreClick, className, showFloatPeek, // Optional feature flag default boundary
9
- resultIndicatorPanel }: AdvancedSearchInputProps): React.JSX.Element;
10
- export {};
3
+ export default function SearchInput({ variant, value, onChange, onClear, placeholder, resultsCount, menuResults, onResultClick, onViewMoreClick, className, showFloatPeek }: SearchInputProps): React.JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { SearchResultItem } from './types';
2
+ interface SearchMenuProps {
3
+ isOpen: boolean;
4
+ value: string;
5
+ menuResults: SearchResultItem[];
6
+ onResultClick?: (item: SearchResultItem) => void;
7
+ onViewMoreClick?: () => void;
8
+ onCloseMenu: () => void;
9
+ }
10
+ export default function SearchMenu({ isOpen, value, menuResults, onResultClick, onViewMoreClick, onCloseMenu }: SearchMenuProps): import("react").JSX.Element | null;
11
+ export {};
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../chunks/search-BnD-97mv.js";
2
- export { e as SearchInput };
1
+ import { n as e, t } from "../../chunks/search-BCvuXqOX.js";
2
+ export { t as SearchInput, e as searchTokens };
@@ -16,4 +16,21 @@ export interface SearchInputProps {
16
16
  onResultClick?: (item: SearchResultItem) => void;
17
17
  onViewMoreClick?: () => void;
18
18
  className?: string;
19
+ showFloatPeek?: boolean;
19
20
  }
21
+ export declare const searchTokens: {
22
+ colors: {
23
+ bgInput: string;
24
+ border: string;
25
+ borderAccent: string;
26
+ borderAccentHover: string;
27
+ text: string;
28
+ muted: string;
29
+ sidebarBg: string;
30
+ hoverBg: string;
31
+ accentBgLight: string;
32
+ };
33
+ transitions: {
34
+ smooth: string;
35
+ };
36
+ };
package/dist/index.js CHANGED
@@ -1,8 +1,7 @@
1
- (function(){try{if(typeof document<`u`){var e=document.createElement(`style`);e.appendChild(document.createTextNode(`/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer theme{:root,:host{--voxel-font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--voxel-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--voxel-default-font-family:var(--voxel-font-sans);--voxel-default-mono-font-family:var(--voxel-font-mono)}}@layer base{@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--voxel-default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--voxel-default-font-feature-settings,normal);font-variation-settings:var(--voxel-default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--voxel-default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--voxel-default-mono-font-feature-settings,normal);font-variation-settings:var(--voxel-default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}.dark{--color-vsc-bg:#1e1e1e;--color-vsc-sidebar:#252526;--color-vsc-border:#3c3c3c;--color-vsc-accent:#007acc;--color-vsc-accent-hover:#0062a3;--color-vsc-hover:#2a2d2e;--color-vsc-text:#ccc;--color-vsc-muted:#8b949e;--color-vsc-bg-input:#1f1f1f}}@layer components,utilities;/*$vite$:1*/`)),document.head.appendChild(e)}}catch(e){console.error(`vite-plugin-css-injected-by-js`,e)}})();
2
1
  import { t as e } from "./chunks/resizable-ImB8dfG_.js";
3
2
  import { i as t, n, r, t as i } from "./chunks/tabs-MaVN00hJ.js";
4
3
  import { t as a } from "./chunks/Button-BgQwvn3C.js";
5
4
  import { n as o, t as s } from "./chunks/button-dHcpTNIG.js";
6
5
  import { C as c, E as l, S as u, T as d, _ as f, a as p, b as m, c as h, d as g, f as _, g as v, h as y, i as b, l as x, m as S, n as C, o as w, p as T, r as E, s as D, t as O, u as k, v as A, w as j, x as M, y as N } from "./chunks/icons-BpfDVwCQ.js";
7
- import { t as P } from "./chunks/search-BnD-97mv.js";
8
- export { A as Add, S as BlankDoc, a as Button, o as ButtonGroup, _ as Chat, N as ChevronDown, l as Close, x as Comment, k as DeleteChat, j as Document, v as Expand, c as Folder, C as Group, y as Minimize, f as Minus, w as More, D as OpenFolder, b as Person, g as PlusChat, h as PlusComment, T as PlusDoc, O as PlusDocBadge, E as PlusPerson, M as Refresh, e as ResizablePanel, u as Search, P as SearchInput, s as SplitActionButton, i as TabButton, n as TabPanel, r as TabPanelList, d as Terminal, m as Trash, p as Truck, t as useTab };
6
+ import { n as P, t as F } from "./chunks/search-BCvuXqOX.js";
7
+ export { A as Add, S as BlankDoc, a as Button, o as ButtonGroup, _ as Chat, N as ChevronDown, l as Close, x as Comment, k as DeleteChat, j as Document, v as Expand, c as Folder, C as Group, y as Minimize, f as Minus, w as More, D as OpenFolder, b as Person, g as PlusChat, h as PlusComment, T as PlusDoc, O as PlusDocBadge, E as PlusPerson, M as Refresh, e as ResizablePanel, u as Search, F as SearchInput, s as SplitActionButton, i as TabButton, n as TabPanel, r as TabPanelList, d as Terminal, m as Trash, p as Truck, P as searchTokens, t as useTab };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knymbus/voxel-ui",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,14 +1,8 @@
1
- import React, { useState, useRef, useEffect, ReactNode } from 'react';
2
- import { SearchInputProps } from './types';
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { SearchInputProps, searchTokens } from './types';
3
3
  import { Search, Close } from '../icons';
4
4
  import { Button } from '../button/Button';
5
-
6
- // Extend your props declaration interface locally to support the new feature flags
7
- interface AdvancedSearchInputProps extends Omit<SearchInputProps, 'variant'> {
8
- variant?: 'simple' | 'float' | 'menu';
9
- showFloatPeek?: boolean; // When true, float variant slides down a results indicator bar
10
- resultIndicatorPanel?: string | ReactNode
11
- }
5
+ import SearchMenu from './SearchMenu';
12
6
 
13
7
  export default function SearchInput({
14
8
  variant = 'simple',
@@ -21,15 +15,16 @@ export default function SearchInput({
21
15
  onResultClick,
22
16
  onViewMoreClick,
23
17
  className = '',
24
- showFloatPeek = false, // Optional feature flag default boundary
25
- resultIndicatorPanel
26
- }: AdvancedSearchInputProps) {
18
+ showFloatPeek = false
19
+ }: SearchInputProps) {
27
20
  const [isExpanded, setIsExpanded] = useState<boolean>(false);
28
21
  const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
22
+ const [isInputHovered, setIsInputHovered] = useState<boolean>(false);
23
+ const [isInputFocused, setIsInputFocused] = useState<boolean>(false);
24
+
29
25
  const containerRef = useRef<HTMLDivElement | null>(null);
30
26
  const inputRef = useRef<HTMLInputElement | null>(null);
31
27
 
32
- // Auto-close overlay dropdowns if the user clicks completely out of the component framework bounding box
33
28
  useEffect(() => {
34
29
  const handleOutsideClick = (e: MouseEvent) => {
35
30
  if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
@@ -55,67 +50,95 @@ export default function SearchInput({
55
50
  setTimeout(() => inputRef.current?.focus(), 50);
56
51
  };
57
52
 
58
- const baseWrapper = "relative flex flex-col font-sans text-xs select-none";
53
+ const baseWrapperStyles: React.CSSProperties = {
54
+ position: 'relative',
55
+ display: 'flex',
56
+ flexDirection: 'column',
57
+ fontFamily: 'sans-serif',
58
+ fontSize: '12px',
59
+ userSelect: 'none',
60
+ boxSizing: 'border-box'
61
+ };
62
+
63
+ const inputContainerBaseStyles: React.CSSProperties = {
64
+ position: 'relative',
65
+ display: 'flex',
66
+ alignItems: 'center',
67
+ backgroundColor: searchTokens.colors.bgInput,
68
+ border: `1px solid ${isInputFocused || (variant === 'float' && isExpanded)
69
+ ? searchTokens.colors.borderAccent
70
+ : isInputHovered
71
+ ? searchTokens.colors.borderAccentHover
72
+ : searchTokens.colors.border
73
+ }`,
74
+ borderRadius: '2px',
75
+ height: '32px',
76
+ transition: searchTokens.transitions.smooth,
77
+ boxSizing: 'border-box'
78
+ };
79
+
80
+ const rawInputStyles: React.CSSProperties = {
81
+ width: '100%',
82
+ height: '100%',
83
+ backgroundColor: 'transparent',
84
+ color: searchTokens.colors.text,
85
+ border: 'none',
86
+ outline: 'none',
87
+ padding: '0 32px',
88
+ fontSize: '12px',
89
+ boxSizing: 'border-box'
90
+ };
59
91
 
60
- // --- 1. SIMPLE VARIANT PANEL ---
92
+ // --- 1. SIMPLE VARIANT ---
61
93
  if (variant === 'simple') {
62
- const hasResults = value.length > 0;
94
+ const hasResults = resultsCount > 0 && value.length > 0;
63
95
 
64
96
  return (
65
- <div className={`${baseWrapper} ${className}`.trim()}>
66
- {/* Core Input Box Frame */}
67
- <div className="relative flex items-center bg-vsc-bg-input border border-vsc-border rounded-sm h-8 group hover:border-vsc-accent transition-colors z-20">
68
- <Search size={14} className="absolute left-2.5 text-vsc-muted group-hover:text-vsc-text" />
97
+ <div style={baseWrapperStyles} className={className}>
98
+ <div
99
+ style={inputContainerBaseStyles}
100
+ onMouseEnter={() => setIsInputHovered(true)}
101
+ onMouseLeave={() => setIsInputHovered(false)}
102
+ >
103
+ <div style={{ position: 'absolute', left: '10px', display: 'flex', alignItems: 'center', color: isInputHovered ? searchTokens.colors.text : searchTokens.colors.muted }}>
104
+ <Search size={14} />
105
+ </div>
69
106
  <input
70
107
  ref={inputRef}
71
108
  type="text"
72
109
  value={value}
73
110
  onChange={(e) => onChange(e.target.value)}
111
+ onFocus={() => setIsInputFocused(true)}
112
+ onBlur={() => setIsInputFocused(false)}
74
113
  placeholder={placeholder}
75
- className="w-full h-full pl-8 pr-10 bg-transparent text-vsc-text border-none outline-none focus:outline-none placeholder-vsc-muted"
114
+ style={rawInputStyles}
76
115
  />
77
116
  {value && (
78
- <div className="absolute right-1 top-1/2 -translate-y-1/2 flex items-center">
79
- <Button
80
- icon={Close}
81
- color="ghost"
82
- iconOnly={true}
83
- onClick={handleClearTrigger}
84
- size="xs"
85
- />
117
+ <div style={{ position: 'absolute', right: '4px', top: '50%', transform: 'translateY(-50%)', display: 'flex', alignItems: 'center' }}>
118
+ <Button icon={Close} color="ghost" iconOnly={true} onClick={handleClearTrigger} size="xs" />
86
119
  </div>
87
120
  )}
88
121
  </div>
89
122
 
90
- {/*
91
- 🎛️ HIGH-FIDELITY FLOATING SLIDE-DOWN INDICATOR PANEL
92
- - Uses 'absolute' so it zero-impacts the parent height layout block.
93
- - Utilizes hardware-accelerated transforms (translateY) for a smooth glide effect.
94
- */}
95
123
  <div
96
- className={`absolute left-0 right-0 top-8 z-50 overflow-hidden transition-all duration-200 cubic-bezier(0.34, 1.56, 0.64, 1) ${!hasResults ? 'pointer-events-none' : ''}`}
97
124
  style={{
98
- height: hasResults ? 'auto' : '0px',
125
+ position: 'absolute',
126
+ left: 0,
127
+ right: 0,
128
+ top: '32px',
129
+ zIndex: 10,
130
+ overflow: 'hidden',
131
+ transition: searchTokens.transitions.smooth,
132
+ height: hasResults ? '24px' : '0px',
99
133
  opacity: hasResults ? 1 : 0,
100
- transform: hasResults ? 'translateY(0px)' : 'translateY(-4px)'
134
+ transform: hasResults ? 'translateY(0px)' : 'translateY(-4px)',
135
+ pointerEvents: 'none'
101
136
  }}
102
137
  >
103
- <div className="bg-vsc-sidebar shadow-sm p-1.5 pt-1 ">
104
- {
105
- resultsCount === 0 ? (
106
- <div className="pl-1 text-start text-[11px] text-vsc-muted italic">
107
- No record match your search query constraints.
108
- </div>
109
- ) : (
110
-
111
- resultIndicatorPanel ? resultIndicatorPanel : (
112
- <p className="text-[10px] font-mono text-vsc-muted pl-1 truncate">
113
- Showing <span className="text-vsc-accent font-bold">{resultsCount}</span> matching database metrics records
114
- </p>
115
- )
116
-
117
- )
118
- }
138
+ <div style={{ backgroundColor: searchTokens.colors.sidebarBg, border: `1px solid ${searchTokens.colors.border}`, borderTop: 'none', padding: '4px 6px', borderRadius: '0 0 2px 2px', boxShadow: '0 4px 6px -1px rgba(0,0,0,0.1)' }}>
139
+ <p style={{ margin: 0, fontSize: '10px', fontFamily: 'monospace', color: searchTokens.colors.muted, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
140
+ Showing <span style={{ color: searchTokens.colors.borderAccent, fontWeight: 'bold' }}>{resultsCount}</span> matching database metrics records
141
+ </p>
119
142
  </div>
120
143
  </div>
121
144
  </div>
@@ -125,32 +148,36 @@ export default function SearchInput({
125
148
  // --- 2. FLOAT EXPANDABLE VARIANT ---
126
149
  if (variant === 'float') {
127
150
  const showPeekIndicator = showFloatPeek && resultsCount > 0 && value.length > 0;
151
+ const isOpened = isExpanded || value.length > 0;
152
+
128
153
  return (
129
- <div ref={containerRef} className={`${baseWrapper} ${className}`.trim()}>
154
+ <div ref={containerRef} style={baseWrapperStyles} className={className}>
130
155
  <div
131
- className={`flex items-center bg-vsc-bg-input border rounded-sm h-8 transition-all duration-300 ease-in-out overflow-hidden ${isExpanded || value ? 'w-64 border-vsc-accent px-2' : 'w-8 border-transparent bg-transparent justify-center'
132
- }`}
156
+ onMouseEnter={() => setIsInputHovered(true)}
157
+ onMouseLeave={() => setIsInputHovered(false)}
158
+ style={{
159
+ ...inputContainerBaseStyles,
160
+ width: isOpened ? '256px' : '32px',
161
+ justifyContent: isOpened ? 'flex-start' : 'center',
162
+ backgroundColor: isOpened ? searchTokens.colors.bgInput : 'transparent',
163
+ borderColor: isOpened ? searchTokens.colors.borderAccent : 'transparent',
164
+ padding: isOpened ? '0 8px' : '0'
165
+ }}
133
166
  >
134
- {isExpanded || value ? (
135
- <div className="relative flex items-center w-full h-full">
136
- <Search size={14} className="text-vsc-text shrink-0" />
167
+ {isOpened ? (
168
+ <div style={{ position: 'relative', display: 'flex', alignItems: 'center', width: '100%', height: '100%' }}>
169
+ <Search size={14} style={{ color: searchTokens.colors.text, flexShrink: 0 }} />
137
170
  <input
138
171
  ref={inputRef}
139
172
  type="text"
140
173
  value={value}
141
174
  onChange={(e) => onChange(e.target.value)}
142
175
  placeholder={placeholder}
143
- className="w-full h-full pl-2 pr-6 bg-transparent text-vsc-text border-none outline-none focus:outline-none placeholder-vsc-muted"
176
+ style={{ ...rawInputStyles, padding: '0 24px 0 8px' }}
144
177
  />
145
178
  {value && (
146
- <div className="absolute right-0 top-1/2 -translate-y-1/2 flex items-center">
147
- <Button
148
- iconOnly={true}
149
- color="ghost"
150
- icon={Close}
151
- onClick={handleClearTrigger}
152
- size="xs"
153
- />
179
+ <div style={{ position: 'absolute', right: 0, top: '50%', transform: 'translateY(-50%)', display: 'flex', alignItems: 'center' }}>
180
+ <Button iconOnly={true} color="ghost" icon={Close} onClick={handleClearTrigger} size="xs" />
154
181
  </div>
155
182
  )}
156
183
  </div>
@@ -161,33 +188,47 @@ export default function SearchInput({
161
188
  icon={Search}
162
189
  onClick={handleFloatActivation}
163
190
  color="ghost"
164
- className="text-vsc-muted hover:text-vsc-text transition-colors"
191
+ style={{ color: searchTokens.colors.muted }}
165
192
  title="Open Expandable Search"
166
193
  />
167
194
  )}
168
195
  </div>
169
196
 
170
- {/* Optional dynamic slider line badge dropdown block */}
171
197
  <div
172
- className="overflow-hidden transition-all duration-200 ease-out w-64 absolute top-8"
173
198
  style={{
174
- height: showPeekIndicator ? '20px' : '0px',
175
- opacity: showPeekIndicator ? 1 : 0
199
+ position: 'absolute',
200
+ top: '32px',
201
+ width: '256px',
202
+ zIndex: 10,
203
+ overflow: 'hidden',
204
+ transition: searchTokens.transitions.smooth,
205
+ height: showPeekIndicator ? '24px' : '0px',
206
+ opacity: showPeekIndicator ? 1 : 0,
207
+ transform: showPeekIndicator ? 'translateY(0px)' : 'translateY(-4px)',
208
+ pointerEvents: 'none'
176
209
  }}
177
210
  >
178
- <p className="text-[9px] font-mono text-vsc-accent pt-1 pl-1 truncate bg-vsc-sidebar border border-t-0 border-vsc-border p-1 rounded-b shadow-sm">
179
- Quick Peek: Found {resultsCount} rows
180
- </p>
211
+ <div style={{ backgroundColor: searchTokens.colors.sidebarBg, border: `1px solid ${searchTokens.colors.border}`, borderTop: 'none', padding: '4px', borderRadius: '0 0 2px 2px', boxShadow: '0 4px 6px -1px rgba(0,0,0,0.1)' }}>
212
+ <p style={{ margin: 0, fontSize: '9px', fontFamily: 'monospace', color: searchTokens.colors.borderAccent, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
213
+ Quick Peek: Found {resultsCount} rows
214
+ </p>
215
+ </div>
181
216
  </div>
182
217
  </div>
183
218
  );
184
219
  }
185
220
 
186
- // --- 3. MENU STYLE SEARCH DROPDOWN ---
221
+ // --- 3. MENU DROPDOWN VARIANT ---
187
222
  return (
188
- <div ref={containerRef} className={`${baseWrapper} ${className}`.trim()}>
189
- <div className="relative flex items-center bg-vsc-bg-input border border-vsc-border rounded-sm h-8 focus-within:border-vsc-accent">
190
- <Search size={14} className="absolute left-2.5 text-vsc-muted" />
223
+ <div ref={containerRef} style={baseWrapperStyles} className={className}>
224
+ <div
225
+ style={inputContainerBaseStyles}
226
+ onMouseEnter={() => setIsInputHovered(true)}
227
+ onMouseLeave={() => setIsInputHovered(false)}
228
+ >
229
+ <div style={{ position: 'absolute', left: '10px', display: 'flex', alignItems: 'center', color: searchTokens.colors.muted }}>
230
+ <Search size={14} />
231
+ </div>
191
232
  <input
192
233
  ref={inputRef}
193
234
  type="text"
@@ -198,65 +239,23 @@ export default function SearchInput({
198
239
  }}
199
240
  onFocus={() => setIsMenuOpen(true)}
200
241
  placeholder={placeholder}
201
- className="w-full h-full pl-8 pr-10 bg-transparent text-vsc-text border-none outline-none focus:outline-none placeholder-vsc-muted"
242
+ style={rawInputStyles}
202
243
  />
203
244
  {value && (
204
- <div className="absolute right-1 top-1/2 -translate-y-1/2 flex items-center">
205
- <Button
206
- iconOnly={true}
207
- icon={Close}
208
- color="ghost"
209
- onClick={handleClearTrigger}
210
- size="xs"
211
- />
245
+ <div style={{ position: 'absolute', right: '4px', top: '50%', transform: 'translateY(-50%)', display: 'flex', alignItems: 'center' }}>
246
+ <Button iconOnly={true} icon={Close} color="ghost" onClick={handleClearTrigger} size="xs" />
212
247
  </div>
213
248
  )}
214
249
  </div>
215
250
 
216
- {isMenuOpen && value && (
217
- <div className="absolute top-9 left-0 w-full bg-vsc-sidebar border border-vsc-border rounded shadow-xl z-50 p-1 flex flex-col max-h-64 animate-in fade-in slide-in-from-top-1 duration-150">
218
- <div className="overflow-y-auto flex-1">
219
- {menuResults.length === 0 ? (
220
- <div className="p-4 text-center text-[11px] text-vsc-muted italic">
221
- No indexed record entities match your text query constraints.
222
- </div>
223
- ) : (
224
- menuResults.map((item) => (
225
- <div
226
- key={item.id}
227
- onClick={() => {
228
- if (onResultClick) onResultClick(item);
229
- setIsMenuOpen(false);
230
- }}
231
- className="w-full p-2 hover:bg-vsc-hover text-left rounded-sm cursor-pointer flex flex-col space-y-0.5 transition-colors"
232
- >
233
- <div className="font-semibold text-vsc-text flex justify-between items-center">
234
- <span className="truncate">{item.title}</span>
235
- {item.category && (
236
- <span className="text-[9px] font-mono font-bold bg-vsc-accent/10 border border-vsc-accent/20 text-vsc-accent px-1 rounded-sm uppercase tracking-wide">
237
- {item.category}
238
- </span>
239
- )}
240
- </div>
241
- {item.subtitle && <div className="text-[10px] text-vsc-muted truncate">{item.subtitle}</div>}
242
- </div>
243
- ))
244
- )}
245
- </div>
246
-
247
- {menuResults.length > 0 && onViewMoreClick && (
248
- <button
249
- onClick={() => {
250
- onViewMoreClick();
251
- setIsMenuOpen(false);
252
- }}
253
- className="w-full border-t border-vsc-border bg-vsc-bg hover:bg-vsc-hover/60 p-2 text-center text-[10px] font-bold text-vsc-accent tracking-wide uppercase transition-colors rounded-b-sm border-none cursor-pointer"
254
- >
255
- View All Matching Search Metrics Records →
256
- </button>
257
- )}
258
- </div>
259
- )}
251
+ <SearchMenu
252
+ isOpen={isMenuOpen}
253
+ value={value}
254
+ menuResults={menuResults}
255
+ onResultClick={onResultClick}
256
+ onViewMoreClick={onViewMoreClick}
257
+ onCloseMenu={() => setIsMenuOpen(false)}
258
+ />
260
259
  </div>
261
260
  );
262
261
  }
@@ -0,0 +1,119 @@
1
+ import { useState } from 'react';
2
+ import { SearchResultItem, searchTokens } from './types';
3
+
4
+ interface SearchMenuProps {
5
+ isOpen: boolean;
6
+ value: string;
7
+ menuResults: SearchResultItem[];
8
+ onResultClick?: (item: SearchResultItem) => void;
9
+ onViewMoreClick?: () => void;
10
+ onCloseMenu: () => void;
11
+ }
12
+
13
+ export default function SearchMenu({
14
+ isOpen,
15
+ value,
16
+ menuResults,
17
+ onResultClick,
18
+ onViewMoreClick,
19
+ onCloseMenu
20
+ }: SearchMenuProps) {
21
+ const [hoveredResultId, setHoveredResultId] = useState<string | null>(null);
22
+ const [isViewMoreHovered, setIsViewMoreHovered] = useState<boolean>(false);
23
+
24
+ if (!isOpen || !value) return null;
25
+
26
+ return (
27
+ <div
28
+ style={{
29
+ position: 'absolute',
30
+ top: '36px',
31
+ left: 0,
32
+ width: '100%',
33
+ backgroundColor: searchTokens.colors.sidebarBg,
34
+ border: `1px solid ${searchTokens.colors.border}`,
35
+ borderRadius: '4px',
36
+ boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.2)',
37
+ zIndex: 50,
38
+ padding: '4px',
39
+ display: 'flex',
40
+ flexDirection: 'column',
41
+ maxHeight: '256px'
42
+ }}
43
+ >
44
+ <div style={{ overflowY: 'auto', flex: 1 }}>
45
+ {menuResults.length === 0 ? (
46
+ <div style={{ padding: '16px', textAlign: 'center', fontSize: '11px', color: searchTokens.colors.muted, fontStyle: 'italic' }}>
47
+ No indexed record entities match your text query constraints.
48
+ </div>
49
+ ) : (
50
+ menuResults.map((item) => {
51
+ const isItemHovered = hoveredResultId === item.id;
52
+ return (
53
+ <div
54
+ key={item.id}
55
+ onMouseEnter={() => setHoveredResultId(item.id)}
56
+ onMouseLeave={() => setHoveredResultId(null)}
57
+ onClick={() => {
58
+ if (onResultClick) onResultClick(item);
59
+ onCloseMenu();
60
+ }}
61
+ style={{
62
+ width: '100%',
63
+ padding: '8px',
64
+ backgroundColor: isItemHovered ? searchTokens.colors.hoverBg : 'transparent',
65
+ borderRadius: '2px',
66
+ cursor: 'pointer',
67
+ display: 'flex',
68
+ flexDirection: 'column',
69
+ gap: '2px',
70
+ transition: 'background-color 100ms',
71
+ boxSizing: 'border-box'
72
+ }}
73
+ >
74
+ <div style={{ fontWeight: 600, color: searchTokens.colors.text, display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }}>
75
+ <span style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', flex: 1 }}>{item.title}</span>
76
+ {item.category && (
77
+ <span style={{ fontSize: '9px', fontFamily: 'monospace', fontWeight: 'bold', backgroundColor: searchTokens.colors.accentBgLight, border: `1px solid rgba(0, 122, 204, 0.2)`, color: searchTokens.colors.borderAccent, padding: '2px 4px', borderRadius: '2px', textTransform: 'uppercase', marginLeft: '8px', flexShrink: 0 }}>
78
+ {item.category}
79
+ </span>
80
+ )}
81
+ </div>
82
+ {item.subtitle && <div style={{ fontSize: '10px', color: searchTokens.colors.muted, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.subtitle}</div>}
83
+ </div>
84
+ );
85
+ })
86
+ )}
87
+ </div>
88
+
89
+ {menuResults.length > 0 && onViewMoreClick && (
90
+ <button
91
+ onMouseEnter={() => setIsViewMoreHovered(true)}
92
+ onMouseLeave={() => setIsViewMoreHovered(false)}
93
+ onClick={() => {
94
+ onViewMoreClick();
95
+ onCloseMenu();
96
+ }}
97
+ style={{
98
+ width: '100%',
99
+ border: 'none',
100
+ borderTop: `1px solid ${searchTokens.colors.border}`,
101
+ backgroundColor: isViewMoreHovered ? searchTokens.colors.hoverBg : 'transparent',
102
+ padding: '8px',
103
+ textAlign: 'center',
104
+ fontSize: '10px',
105
+ fontWeight: 'bold',
106
+ color: searchTokens.colors.borderAccent,
107
+ letterSpacing: '0.5px',
108
+ textTransform: 'uppercase',
109
+ transition: 'background-color 150ms',
110
+ borderRadius: '0 0 2px 2px',
111
+ cursor: 'pointer'
112
+ }}
113
+ >
114
+ View All Matching Search Metrics Records →
115
+ </button>
116
+ )}
117
+ </div>
118
+ );
119
+ }
@@ -13,9 +13,27 @@ export interface SearchInputProps {
13
13
  onChange: (value: string) => void;
14
14
  onClear?: () => void;
15
15
  placeholder?: string;
16
- resultsCount?: number; // Mandatory for 'simple' variant display logs
17
- menuResults?: SearchResultItem[]; // Array datasets parsed directly to the 'menu' view dropdown
16
+ resultsCount?: number;
17
+ menuResults?: SearchResultItem[];
18
18
  onResultClick?: (item: SearchResultItem) => void;
19
19
  onViewMoreClick?: () => void;
20
20
  className?: string;
21
+ showFloatPeek?: boolean;
21
22
  }
23
+
24
+ export const searchTokens = {
25
+ colors: {
26
+ bgInput: 'var(--color-vsc-bg-input, #f6f8fa)',
27
+ border: 'var(--color-vsc-border, #e4e4e7)',
28
+ borderAccent: 'var(--color-vsc-accent, #007acc)',
29
+ borderAccentHover: 'var(--color-vsc-accent-hover, #0062a3)',
30
+ text: 'var(--color-vsc-text, #333333)',
31
+ muted: 'var(--color-vsc-muted, #6a737d)',
32
+ sidebarBg: 'var(--color-vsc-sidebar, #f3f3f3)',
33
+ hoverBg: 'var(--color-vsc-hover, #e8e8e8)',
34
+ accentBgLight: 'rgba(0, 122, 204, 0.1)'
35
+ },
36
+ transitions: {
37
+ smooth: 'all 200ms cubic-bezier(0.34, 1.56, 0.64, 1)'
38
+ }
39
+ };
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- import './index.css';
2
1
  export * from './components/resizable';
3
2
  export * from './components/tabs';
4
3
  export * from './components/button';
package/vite.config.mts CHANGED
@@ -9,13 +9,11 @@ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
9
9
  import { playwright } from '@vitest/browser-playwright';
10
10
  const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
11
11
  import tailwindcss from '@tailwindcss/vite';
12
- import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
13
12
 
14
13
  // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
15
14
  export default defineConfig({
16
15
  plugins: [
17
16
  tailwindcss(),
18
- cssInjectedByJsPlugin(),
19
17
  react(),
20
18
  // Auto-generates independent TypeScript type declaration files (.d.ts) matching paths
21
19
  dts({
@@ -33,8 +31,6 @@ export default defineConfig({
33
31
  'components/icons/index': resolve(__dirname, 'src/components/icons/index.ts'),
34
32
 
35
33
  },
36
- name: "voxelUi",
37
- fileName: (format) => `index.${format}.js`,
38
34
  formats: ['es'] // Output strictly as modern ES Modules for dead-code elimination (tree-shaking)
39
35
  },
40
36
  rollupOptions: {
@@ -1,205 +0,0 @@
1
- import { t as e } from "./jsx-runtime-Boo2vksn.js";
2
- import { t } from "./Button-BgQwvn3C.js";
3
- import { E as n, S as r } from "./icons-BpfDVwCQ.js";
4
- import { useEffect as i, useRef as a, useState as o } from "react";
5
- //#region src/components/search/SearchInput.tsx
6
- var s = e();
7
- function c({ variant: e = "simple", value: c, onChange: l, onClear: u, placeholder: d = "Search manifests or tracking codes...", resultsCount: f = 0, menuResults: p = [], onResultClick: m, onViewMoreClick: h, className: g = "", showFloatPeek: _ = !1, resultIndicatorPanel: v }) {
8
- let [y, b] = o(!1), [x, S] = o(!1), C = a(null), w = a(null);
9
- i(() => {
10
- let t = (t) => {
11
- C.current && !C.current.contains(t.target) && (S(!1), e === "float" && c === "" && b(!1));
12
- };
13
- return window.addEventListener("mousedown", t), () => window.removeEventListener("mousedown", t);
14
- }, [e, c]);
15
- let T = (e) => {
16
- e.stopPropagation(), l(""), u && u(), w.current && w.current.focus();
17
- }, E = () => {
18
- b(!0), setTimeout(() => w.current?.focus(), 50);
19
- }, D = "relative flex flex-col font-sans text-xs select-none";
20
- if (e === "simple") {
21
- let e = c.length > 0;
22
- return /* @__PURE__ */ (0, s.jsxs)("div", {
23
- className: `${D} ${g}`.trim(),
24
- children: [/* @__PURE__ */ (0, s.jsxs)("div", {
25
- className: "relative flex items-center bg-vsc-bg-input border border-vsc-border rounded-sm h-8 group hover:border-vsc-accent transition-colors z-20",
26
- children: [
27
- /* @__PURE__ */ (0, s.jsx)(r, {
28
- size: 14,
29
- className: "absolute left-2.5 text-vsc-muted group-hover:text-vsc-text"
30
- }),
31
- /* @__PURE__ */ (0, s.jsx)("input", {
32
- ref: w,
33
- type: "text",
34
- value: c,
35
- onChange: (e) => l(e.target.value),
36
- placeholder: d,
37
- className: "w-full h-full pl-8 pr-10 bg-transparent text-vsc-text border-none outline-none focus:outline-none placeholder-vsc-muted"
38
- }),
39
- c && /* @__PURE__ */ (0, s.jsx)("div", {
40
- className: "absolute right-1 top-1/2 -translate-y-1/2 flex items-center",
41
- children: /* @__PURE__ */ (0, s.jsx)(t, {
42
- icon: n,
43
- color: "ghost",
44
- iconOnly: !0,
45
- onClick: T,
46
- size: "xs"
47
- })
48
- })
49
- ]
50
- }), /* @__PURE__ */ (0, s.jsx)("div", {
51
- className: `absolute left-0 right-0 top-8 z-50 overflow-hidden transition-all duration-200 cubic-bezier(0.34, 1.56, 0.64, 1) ${e ? "" : "pointer-events-none"}`,
52
- style: {
53
- height: e ? "auto" : "0px",
54
- opacity: +!!e,
55
- transform: e ? "translateY(0px)" : "translateY(-4px)"
56
- },
57
- children: /* @__PURE__ */ (0, s.jsx)("div", {
58
- className: "bg-vsc-sidebar shadow-sm p-1.5 pt-1 ",
59
- children: f === 0 ? /* @__PURE__ */ (0, s.jsx)("div", {
60
- className: "pl-1 text-start text-[11px] text-vsc-muted italic",
61
- children: "No record match your search query constraints."
62
- }) : v || /* @__PURE__ */ (0, s.jsxs)("p", {
63
- className: "text-[10px] font-mono text-vsc-muted pl-1 truncate",
64
- children: [
65
- "Showing ",
66
- /* @__PURE__ */ (0, s.jsx)("span", {
67
- className: "text-vsc-accent font-bold",
68
- children: f
69
- }),
70
- " matching database metrics records"
71
- ]
72
- })
73
- })
74
- })]
75
- });
76
- }
77
- if (e === "float") {
78
- let e = _ && f > 0 && c.length > 0;
79
- return /* @__PURE__ */ (0, s.jsxs)("div", {
80
- ref: C,
81
- className: `${D} ${g}`.trim(),
82
- children: [/* @__PURE__ */ (0, s.jsx)("div", {
83
- className: `flex items-center bg-vsc-bg-input border rounded-sm h-8 transition-all duration-300 ease-in-out overflow-hidden ${y || c ? "w-64 border-vsc-accent px-2" : "w-8 border-transparent bg-transparent justify-center"}`,
84
- children: y || c ? /* @__PURE__ */ (0, s.jsxs)("div", {
85
- className: "relative flex items-center w-full h-full",
86
- children: [
87
- /* @__PURE__ */ (0, s.jsx)(r, {
88
- size: 14,
89
- className: "text-vsc-text shrink-0"
90
- }),
91
- /* @__PURE__ */ (0, s.jsx)("input", {
92
- ref: w,
93
- type: "text",
94
- value: c,
95
- onChange: (e) => l(e.target.value),
96
- placeholder: d,
97
- className: "w-full h-full pl-2 pr-6 bg-transparent text-vsc-text border-none outline-none focus:outline-none placeholder-vsc-muted"
98
- }),
99
- c && /* @__PURE__ */ (0, s.jsx)("div", {
100
- className: "absolute right-0 top-1/2 -translate-y-1/2 flex items-center",
101
- children: /* @__PURE__ */ (0, s.jsx)(t, {
102
- iconOnly: !0,
103
- color: "ghost",
104
- icon: n,
105
- onClick: T,
106
- size: "xs"
107
- })
108
- })
109
- ]
110
- }) : /* @__PURE__ */ (0, s.jsx)(t, {
111
- iconOnly: !0,
112
- size: "sm",
113
- icon: r,
114
- onClick: E,
115
- color: "ghost",
116
- className: "text-vsc-muted hover:text-vsc-text transition-colors",
117
- title: "Open Expandable Search"
118
- })
119
- }), /* @__PURE__ */ (0, s.jsx)("div", {
120
- className: "overflow-hidden transition-all duration-200 ease-out w-64 absolute top-8",
121
- style: {
122
- height: e ? "20px" : "0px",
123
- opacity: +!!e
124
- },
125
- children: /* @__PURE__ */ (0, s.jsxs)("p", {
126
- className: "text-[9px] font-mono text-vsc-accent pt-1 pl-1 truncate bg-vsc-sidebar border border-t-0 border-vsc-border p-1 rounded-b shadow-sm",
127
- children: [
128
- "Quick Peek: Found ",
129
- f,
130
- " rows"
131
- ]
132
- })
133
- })]
134
- });
135
- }
136
- return /* @__PURE__ */ (0, s.jsxs)("div", {
137
- ref: C,
138
- className: `${D} ${g}`.trim(),
139
- children: [/* @__PURE__ */ (0, s.jsxs)("div", {
140
- className: "relative flex items-center bg-vsc-bg-input border border-vsc-border rounded-sm h-8 focus-within:border-vsc-accent",
141
- children: [
142
- /* @__PURE__ */ (0, s.jsx)(r, {
143
- size: 14,
144
- className: "absolute left-2.5 text-vsc-muted"
145
- }),
146
- /* @__PURE__ */ (0, s.jsx)("input", {
147
- ref: w,
148
- type: "text",
149
- value: c,
150
- onChange: (e) => {
151
- l(e.target.value), S(!0);
152
- },
153
- onFocus: () => S(!0),
154
- placeholder: d,
155
- className: "w-full h-full pl-8 pr-10 bg-transparent text-vsc-text border-none outline-none focus:outline-none placeholder-vsc-muted"
156
- }),
157
- c && /* @__PURE__ */ (0, s.jsx)("div", {
158
- className: "absolute right-1 top-1/2 -translate-y-1/2 flex items-center",
159
- children: /* @__PURE__ */ (0, s.jsx)(t, {
160
- iconOnly: !0,
161
- icon: n,
162
- color: "ghost",
163
- onClick: T,
164
- size: "xs"
165
- })
166
- })
167
- ]
168
- }), x && c && /* @__PURE__ */ (0, s.jsxs)("div", {
169
- className: "absolute top-9 left-0 w-full bg-vsc-sidebar border border-vsc-border rounded shadow-xl z-50 p-1 flex flex-col max-h-64 animate-in fade-in slide-in-from-top-1 duration-150",
170
- children: [/* @__PURE__ */ (0, s.jsx)("div", {
171
- className: "overflow-y-auto flex-1",
172
- children: p.length === 0 ? /* @__PURE__ */ (0, s.jsx)("div", {
173
- className: "p-4 text-center text-[11px] text-vsc-muted italic",
174
- children: "No indexed record entities match your text query constraints."
175
- }) : p.map((e) => /* @__PURE__ */ (0, s.jsxs)("div", {
176
- onClick: () => {
177
- m && m(e), S(!1);
178
- },
179
- className: "w-full p-2 hover:bg-vsc-hover text-left rounded-sm cursor-pointer flex flex-col space-y-0.5 transition-colors",
180
- children: [/* @__PURE__ */ (0, s.jsxs)("div", {
181
- className: "font-semibold text-vsc-text flex justify-between items-center",
182
- children: [/* @__PURE__ */ (0, s.jsx)("span", {
183
- className: "truncate",
184
- children: e.title
185
- }), e.category && /* @__PURE__ */ (0, s.jsx)("span", {
186
- className: "text-[9px] font-mono font-bold bg-vsc-accent/10 border border-vsc-accent/20 text-vsc-accent px-1 rounded-sm uppercase tracking-wide",
187
- children: e.category
188
- })]
189
- }), e.subtitle && /* @__PURE__ */ (0, s.jsx)("div", {
190
- className: "text-[10px] text-vsc-muted truncate",
191
- children: e.subtitle
192
- })]
193
- }, e.id))
194
- }), p.length > 0 && h && /* @__PURE__ */ (0, s.jsx)("button", {
195
- onClick: () => {
196
- h(), S(!1);
197
- },
198
- className: "w-full border-t border-vsc-border bg-vsc-bg hover:bg-vsc-hover/60 p-2 text-center text-[10px] font-bold text-vsc-accent tracking-wide uppercase transition-colors rounded-b-sm border-none cursor-pointer",
199
- children: "View All Matching Search Metrics Records →"
200
- })]
201
- })]
202
- });
203
- }
204
- //#endregion
205
- export { c as t };