spotlight-omni-search 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,391 @@
1
+ # spotlight-omni-search 🔍 (v1.0.0)
2
+
3
+ A professional, **Tailwind-Native** Spotlight Search component for React and Next.js. Engineered to blend perfectly into your existing design system without shipping any global CSS resets or side effects.
4
+
5
+ ## 🆕 What's New in v1.0.0
6
+
7
+ - **🎯 Fuzzy Search**: Intelligent VS Code-style character matching with relevance scoring
8
+ - **📜 Recent Items**: Automatic tracking and display of recently selected items
9
+ - **⚡ Built-in Actions**: Pre-built actions for theme toggle, navigation, utilities
10
+ - **🔌 Enhanced Router Integration**: Better Next.js and React Router support
11
+ - **⏳ Loading States**: Built-in skeleton loader for async data
12
+ - **⌨️ Keyboard Shortcuts**: Display shortcut hints on items
13
+ - **🎨 Custom Rendering**: Optional custom render function support
14
+ - **🪝 useSpotlight Hook**: Simplified state management with built-in Cmd+K support
15
+
16
+ ---
17
+
18
+ ## 🏛 Architecture
19
+
20
+ This package is "Tailwind-Native". Instead of shipping a giant, compiled CSS file with internal resets, this library uses standard Tailwind classes that are compiled by **YOUR** application's Tailwind build.
21
+
22
+ ### Key Benefits:
23
+
24
+ - **Zero Style Leaks**: No bundled resets. Your `body`, `button`, and `h1` styles remain yours.
25
+ - **Microscopic Bundle Size**: Only ships the logic. Your Tailwind build handles the styles.
26
+ - **Perfect Design Parity**: Inherits your fonts, colors, and layout rules natively.
27
+
28
+ ---
29
+
30
+ ## 📦 Installation
31
+
32
+ ```bash
33
+ npm install spotlight-omni-search
34
+ ```
35
+
36
+ ## 🛠 Integration (Required)
37
+
38
+ Because v3 uses standard Tailwind classes, you **must** tell Tailwind to scan the library for styles.
39
+
40
+ ### 1. Update `tailwind.config.js`
41
+
42
+ Add the library path to your `content` array:
43
+
44
+ ```javascript
45
+ /** @type {import('tailwindcss').Config} */
46
+ export default {
47
+ content: [
48
+ "./index.html",
49
+ "./src/**/*.{js,ts,jsx,tsx}",
50
+ "./node_modules/spotlight-omni-search/**/*.{js,ts,jsx,tsx}", // <--- ADD THIS
51
+ ],
52
+ // ...
53
+ };
54
+ ```
55
+
56
+ ### 2. (Optional) Import Default Variables
57
+
58
+ If you want to use our default colors, import the minimal variable sheet in your `layout.tsx` or `index.css`:
59
+
60
+ ```tsx
61
+ import "spotlight-omni-search/dist/style.css";
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 🌓 Customization
67
+
68
+ Since we use standard Tailwind, you can customize the theme using CSS variables in your global CSS:
69
+
70
+ ```css
71
+ :root {
72
+ --spotlight-primary: #3b82f6;
73
+ --spotlight-background: #ffffff;
74
+ }
75
+
76
+ .dark {
77
+ --spotlight-background: #0f172a;
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ## ✨ Features
84
+
85
+ - **🎯 Fuzzy Search**: Intelligent character-by-character matching (like VS Code's Cmd+P)
86
+ - **⚡ Smart Relevance**: Results sorted by match quality and position
87
+ - **📜 Recent Items**: Automatically tracks and shows recently selected items
88
+ - **⌨️ Keyboard Shortcuts**: Built-in Cmd+K / Ctrl+K support via `useSpotlight()` hook
89
+ - **🎨 Tailwind-Native**: Zero style conflicts, inherits your design system
90
+ - **📦 Tiny Bundle**: Only logic shipped, styles compiled by your Tailwind
91
+ - **🔌 Router Agnostic**: Works with Next.js, React Router, or any navigation system
92
+
93
+ ---
94
+
95
+ ## 🚀 Quick Start (Recommended)
96
+
97
+ The easiest way to use this package is with the `useSpotlight()` hook:
98
+
99
+ ```tsx
100
+ "use client";
101
+
102
+ import { useSpotlight, Spotlight, SpotlightItem } from "spotlight-omni-search";
103
+ import { useRouter } from "next/navigation";
104
+ import { Home, Settings, User } from "lucide-react";
105
+
106
+ export function MyApp() {
107
+ const router = useRouter();
108
+ const { isOpen, close } = useSpotlight(); // ✨ Handles Cmd+K automatically!
109
+
110
+ const items: SpotlightItem[] = [
111
+ {
112
+ id: "home",
113
+ label: "Home",
114
+ icon: <Home size={20} />,
115
+ type: "page",
116
+ route: "/",
117
+ },
118
+ {
119
+ id: "settings",
120
+ label: "Settings",
121
+ icon: <Settings size={20} />,
122
+ type: "page",
123
+ route: "/settings",
124
+ },
125
+ ];
126
+
127
+ return (
128
+ <Spotlight
129
+ isOpen={isOpen}
130
+ onClose={close}
131
+ items={items}
132
+ onNavigate={(path) => router.push(path)}
133
+ />
134
+ );
135
+ }
136
+ ```
137
+
138
+ **That's it!** Press `Cmd+K` (Mac) or `Ctrl+K` (Windows/Linux) to open the spotlight.
139
+
140
+ ### Hook Options
141
+
142
+ ```tsx
143
+ const { isOpen, open, close, toggle } = useSpotlight({
144
+ defaultOpen: false, // Initial state
145
+ shortcut: "cmd+k", // Keyboard shortcut
146
+ enableShortcut: true, // Enable/disable shortcut
147
+ });
148
+ ```
149
+
150
+ ---
151
+
152
+ ## 💡 Manual Setup (Advanced)
153
+
154
+ If you need more control, you can manage state manually:
155
+
156
+ Here is a complete, copy-pasteable example of how to use this in a Next.js app with `lucide-react`.
157
+
158
+ ### `components/CommandPalette.tsx`
159
+
160
+ ```tsx
161
+ "use client";
162
+
163
+ import { useEffect, useState } from "react";
164
+ import { useRouter } from "next/navigation";
165
+ import { CreditCard, Home, Settings, User, LogOut } from "lucide-react";
166
+
167
+ // Import the component and types
168
+ import { Spotlight, SpotlightItem } from "spotlight-omni-search";
169
+
170
+ export function CommandPalette() {
171
+ const [isOpen, setIsOpen] = useState(false);
172
+ const router = useRouter();
173
+
174
+ // 1. Define your items
175
+ const items: SpotlightItem[] = [
176
+ {
177
+ id: "home",
178
+ label: "Home",
179
+ description: "Go to dashboard",
180
+ icon: <Home size={20} />,
181
+ type: "page",
182
+ group: "Navigation",
183
+ route: "/dashboard",
184
+ },
185
+ {
186
+ id: "profile",
187
+ label: "Profile",
188
+ description: "Manage your account",
189
+ icon: <User size={20} />,
190
+ type: "page",
191
+ group: "Navigation",
192
+ route: "/profile",
193
+ },
194
+ {
195
+ id: "billing",
196
+ label: "Billing",
197
+ description: "View invoices and plans",
198
+ icon: <CreditCard size={20} />,
199
+ type: "page",
200
+ group: "Navigation",
201
+ route: "/billing",
202
+ },
203
+ {
204
+ id: "settings",
205
+ label: "Settings",
206
+ description: "App configuration",
207
+ icon: <Settings size={20} />,
208
+ type: "page",
209
+ group: "Navigation",
210
+ route: "/settings",
211
+ },
212
+ {
213
+ id: "logout",
214
+ label: "Log Out",
215
+ description: "Sign out of your account",
216
+ icon: <LogOut size={20} />,
217
+ type: "action",
218
+ group: "Actions",
219
+ action: () => {
220
+ console.log("Logging out...");
221
+ // perform logout logic
222
+ },
223
+ },
224
+ ];
225
+
226
+ // 2. Handle Keyboard Shortcut (Cmd+K)
227
+ useEffect(() => {
228
+ const handleKeyDown = (e: KeyboardEvent) => {
229
+ if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
230
+ e.preventDefault();
231
+ setIsOpen((prev) => !prev);
232
+ }
233
+ };
234
+ window.addEventListener("keydown", handleKeyDown);
235
+ return () => window.removeEventListener("keydown", handleKeyDown);
236
+ }, []);
237
+
238
+ // 3. Render
239
+ return (
240
+ <Spotlight
241
+ isOpen={isOpen}
242
+ onClose={() => setIsOpen(false)}
243
+ items={items}
244
+ onNavigate={(path) => router.push(path)} // Determine how to navigate
245
+ searchPlaceholder="Type a command or search..."
246
+ />
247
+ );
248
+ }
249
+ ```
250
+
251
+ Then simply drop `<CommandPalette />` into your root `layout.tsx` or `App.tsx`!
252
+
253
+ ---
254
+
255
+ ## 🔌 Router Integration
256
+
257
+ ### Next.js with Manual Routes
258
+
259
+ ```tsx
260
+ import {
261
+ getSpotlightItemsFromRoutes,
262
+ RouteConfig,
263
+ } from "spotlight-omni-search";
264
+ import { Home, Settings, Users } from "lucide-react";
265
+
266
+ const routes: RouteConfig[] = [
267
+ {
268
+ path: "/",
269
+ label: "Home",
270
+ icon: <Home size={20} />,
271
+ },
272
+ {
273
+ path: "/settings",
274
+ label: "Settings",
275
+ description: "Manage your preferences",
276
+ icon: <Settings size={20} />,
277
+ },
278
+ {
279
+ path: "/admin",
280
+ label: "Admin Panel",
281
+ hidden: true, // Won't appear in spotlight
282
+ },
283
+ ];
284
+
285
+ const spotlightItems = getSpotlightItemsFromRoutes(routes);
286
+ ```
287
+
288
+ ### React Router v6
289
+
290
+ ```tsx
291
+ import { createBrowserRouter } from "react-router-dom";
292
+ import {
293
+ getSpotlightItemsFromRoutes,
294
+ RouterHandle,
295
+ } from "spotlight-omni-search";
296
+
297
+ const routes = [
298
+ {
299
+ path: "/dashboard",
300
+ element: <Dashboard />,
301
+ handle: {
302
+ spotlight: {
303
+ label: "Dashboard",
304
+ description: "View your dashboard",
305
+ icon: <HomeIcon />,
306
+ keywords: ["home", "overview"],
307
+ },
308
+ } satisfies RouterHandle,
309
+ },
310
+ ];
311
+
312
+ const router = createBrowserRouter(routes);
313
+ const spotlightItems = getSpotlightItemsFromRoutes(routes);
314
+ ```
315
+
316
+ ---
317
+
318
+ ## ⚡ Built-in Actions
319
+
320
+ Use pre-built actions for common functionality:
321
+
322
+ ```tsx
323
+ import {
324
+ createCommonActions,
325
+ createThemeActions,
326
+ createUtilityActions,
327
+ } from "spotlight-omni-search";
328
+
329
+ // All common actions at once
330
+ const actions = createCommonActions({
331
+ currentTheme: theme,
332
+ onToggle: (newTheme) => setTheme(newTheme),
333
+ });
334
+
335
+ // Or pick specific action groups
336
+ const themeActions = createThemeActions({
337
+ currentTheme: theme,
338
+ onToggle: setTheme,
339
+ });
340
+
341
+ const utilityActions = createUtilityActions(); // Copy URL, Print, Reload
342
+
343
+ // Combine with your pages
344
+ const allItems = [...pages, ...actions];
345
+ ```
346
+
347
+ **Available Actions:**
348
+
349
+ - 🌓 Theme toggle (dark/light)
350
+ - ⬅️ Navigate back/forward
351
+ - ⬆️ Scroll to top/bottom
352
+ - 📋 Copy current URL
353
+ - 🖨️ Print page
354
+ - 🔄 Reload page
355
+
356
+ ---
357
+
358
+ ## ⏳ Loading States
359
+
360
+ Handle async data loading with built-in loading UI:
361
+
362
+ ```tsx
363
+ const [items, setItems] = useState<SpotlightItem[]>([]);
364
+ const [isLoading, setIsLoading] = useState(false);
365
+
366
+ useEffect(() => {
367
+ async function loadItems() {
368
+ setIsLoading(true);
369
+ const data = await fetchItemsFromAPI();
370
+ setItems(data);
371
+ setIsLoading(false);
372
+ }
373
+ loadItems();
374
+ }, []);
375
+
376
+ return (
377
+ <Spotlight
378
+ isOpen={isOpen}
379
+ onClose={close}
380
+ items={items}
381
+ isLoading={isLoading} // Shows skeleton loader
382
+ onNavigate={(path) => router.push(path)}
383
+ />
384
+ );
385
+ ```
386
+
387
+ ---
388
+
389
+ ## 📄 License
390
+
391
+ MIT © Dhruv
@@ -0,0 +1,2 @@
1
+ import { SpotlightProps } from './types';
2
+ export declare function Spotlight({ isOpen, onClose, items, onNavigate, searchPlaceholder, enableRecent, maxRecentItems, isLoading, renderItem, }: SpotlightProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,31 @@
1
+ import { SpotlightItem } from '../types';
2
+ export interface ThemeActionsOptions {
3
+ /**
4
+ * Callback when theme is toggled
5
+ */
6
+ onToggle?: (theme: 'light' | 'dark') => void;
7
+ /**
8
+ * Current theme (to show correct icon)
9
+ */
10
+ currentTheme?: 'light' | 'dark';
11
+ }
12
+ /**
13
+ * Creates theme toggle actions
14
+ */
15
+ export declare function createThemeActions(options?: ThemeActionsOptions): SpotlightItem[];
16
+ /**
17
+ * Creates browser navigation actions
18
+ */
19
+ export declare function createNavigationActions(): SpotlightItem[];
20
+ /**
21
+ * Creates scroll actions
22
+ */
23
+ export declare function createScrollActions(): SpotlightItem[];
24
+ /**
25
+ * Creates utility actions
26
+ */
27
+ export declare function createUtilityActions(): SpotlightItem[];
28
+ /**
29
+ * Creates all common actions
30
+ */
31
+ export declare function createCommonActions(themeOptions?: ThemeActionsOptions): SpotlightItem[];
@@ -0,0 +1,23 @@
1
+ import { ReactNode } from "react";
2
+ import { SpotlightItem } from "../types";
3
+ export interface RouteConfig {
4
+ path: string;
5
+ label?: string;
6
+ name?: string;
7
+ title?: string;
8
+ description?: string;
9
+ icon?: ReactNode;
10
+ children?: RouteConfig[];
11
+ /**
12
+ * Hide this route from spotlight search
13
+ */
14
+ hidden?: boolean;
15
+ [key: string]: unknown;
16
+ }
17
+ /**
18
+ * Recursively extracts spotlight items from a route configuration.
19
+ * @param routes The list of routes to traverse.
20
+ * @param baseUrl The base URL for the current level (used for recursion).
21
+ * @param parentGroup The group name to assign (defaults to "Pages").
22
+ */
23
+ export declare function getSpotlightItemsFromRoutes(routes: RouteConfig[], baseUrl?: string, parentGroup?: string): SpotlightItem[];
@@ -0,0 +1,37 @@
1
+ import { RouteObject } from "react-router-dom";
2
+ import { SpotlightItem, SpotlightItemType } from "../types";
3
+ /**
4
+ * Interface for React Router handle metadata
5
+ * Use this to add spotlight metadata to your routes
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * {
10
+ * path: '/dashboard',
11
+ * element: <Dashboard />,
12
+ * handle: {
13
+ * spotlight: {
14
+ * label: 'Dashboard',
15
+ * description: 'View your dashboard',
16
+ * icon: <HomeIcon />,
17
+ * keywords: ['home', 'overview']
18
+ * }
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export interface RouterHandle {
24
+ spotlight?: {
25
+ label: string;
26
+ icon?: React.ReactNode;
27
+ description?: string;
28
+ keywords?: string[];
29
+ type?: SpotlightItemType;
30
+ };
31
+ }
32
+ /**
33
+ * Recursively extracts spotlight items from route configuration
34
+ * @param routes The React Router route definitions
35
+ * @param parentPath The path accumulator for recursion
36
+ */
37
+ export declare function getSpotlightItemsFromRoutes(routes: RouteObject[], parentPath?: string): SpotlightItem[];
@@ -0,0 +1,36 @@
1
+ import { SpotlightItem } from '../types';
2
+ export interface UseRecentItemsOptions {
3
+ /**
4
+ * LocalStorage key for persistence
5
+ * @default 'spotlight-recent-items'
6
+ */
7
+ storageKey?: string;
8
+ /**
9
+ * Maximum number of recent items to track
10
+ * @default 10
11
+ */
12
+ maxItems?: number;
13
+ /**
14
+ * Enable recent items tracking
15
+ * @default true
16
+ */
17
+ enabled?: boolean;
18
+ }
19
+ export interface UseRecentItemsReturn {
20
+ /**
21
+ * List of recent items
22
+ */
23
+ recentItems: SpotlightItem[];
24
+ /**
25
+ * Add an item to recent history
26
+ */
27
+ addRecentItem: (item: SpotlightItem) => void;
28
+ /**
29
+ * Clear all recent items
30
+ */
31
+ clearRecent: () => void;
32
+ }
33
+ /**
34
+ * Hook to manage recent items with localStorage persistence
35
+ */
36
+ export declare function useRecentItems(options?: UseRecentItemsOptions): UseRecentItemsReturn;
@@ -0,0 +1,47 @@
1
+ export interface UseSpotlightOptions {
2
+ /**
3
+ * Initial open state
4
+ * @default false
5
+ */
6
+ defaultOpen?: boolean;
7
+ /**
8
+ * Keyboard shortcut to toggle spotlight
9
+ * Format: 'cmd+k', 'ctrl+shift+p', etc.
10
+ * @default 'cmd+k' (Mac) / 'ctrl+k' (Windows/Linux)
11
+ */
12
+ shortcut?: string;
13
+ /**
14
+ * Enable keyboard shortcut
15
+ * @default true
16
+ */
17
+ enableShortcut?: boolean;
18
+ }
19
+ export interface UseSpotlightReturn {
20
+ /**
21
+ * Current open state
22
+ */
23
+ isOpen: boolean;
24
+ /**
25
+ * Open the spotlight
26
+ */
27
+ open: () => void;
28
+ /**
29
+ * Close the spotlight
30
+ */
31
+ close: () => void;
32
+ /**
33
+ * Toggle the spotlight open/closed
34
+ */
35
+ toggle: () => void;
36
+ }
37
+ /**
38
+ * Hook to manage Spotlight state and keyboard shortcuts
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * const { isOpen, open, close, toggle } = useSpotlight();
43
+ *
44
+ * return <Spotlight isOpen={isOpen} onClose={close} ... />;
45
+ * ```
46
+ */
47
+ export declare function useSpotlight(options?: UseSpotlightOptions): UseSpotlightReturn;
@@ -0,0 +1,7 @@
1
+ import "./index.css";
2
+ export * from "./types";
3
+ export * from "./Spotlight";
4
+ export * from "./adapters/routes";
5
+ export * from "./hooks/useSpotlight";
6
+ export * from "./hooks/useRecentItems";
7
+ export * from "./actions/commonActions";