aural-ui 2.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/LICENSE +21 -0
- package/README.md +456 -0
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +1327 -0
- package/dist/components/aspect-ratio/index.tsx +10 -0
- package/dist/components/aspect-ratio/meta.ts +8 -0
- package/dist/components/avatar/Avatar.stories.tsx +645 -0
- package/dist/components/avatar/index.tsx +50 -0
- package/dist/components/avatar/meta.ts +8 -0
- package/dist/components/badge/Badge.stories.tsx +169 -0
- package/dist/components/badge/index.tsx +28 -0
- package/dist/components/badge/meta.ts +6 -0
- package/dist/components/banner/Banner.stories.tsx +475 -0
- package/dist/components/banner/index.tsx +256 -0
- package/dist/components/banner/meta.ts +36 -0
- package/dist/components/button/Button.stories.tsx +74 -0
- package/dist/components/button/index.tsx +158 -0
- package/dist/components/button/meta.ts +33 -0
- package/dist/components/card/Card.stories.tsx +377 -0
- package/dist/components/card/index.tsx +85 -0
- package/dist/components/card/meta.ts +14 -0
- package/dist/components/char-count/CharCount.stories.tsx +334 -0
- package/dist/components/char-count/index.tsx +51 -0
- package/dist/components/char-count/meta.ts +13 -0
- package/dist/components/checkbox/Checkbox.stories.tsx +209 -0
- package/dist/components/checkbox/index.tsx +34 -0
- package/dist/components/checkbox/meta.ts +19 -0
- package/dist/components/chip/Chip.stories.tsx +207 -0
- package/dist/components/chip/index.tsx +92 -0
- package/dist/components/chip/meta.ts +17 -0
- package/dist/components/circular-loader/CircularLoader.stories.tsx +741 -0
- package/dist/components/circular-loader/index.tsx +138 -0
- package/dist/components/circular-loader/meta.ts +11 -0
- package/dist/components/collapsible/Collapsible.stories.tsx +319 -0
- package/dist/components/collapsible/index.tsx +158 -0
- package/dist/components/collapsible/meta.ts +22 -0
- package/dist/components/command/Command.stories.tsx +996 -0
- package/dist/components/command/index.tsx +324 -0
- package/dist/components/command/meta.ts +18 -0
- package/dist/components/dialog/Dialog.stories.tsx +963 -0
- package/dist/components/dialog/index.tsx +250 -0
- package/dist/components/dialog/meta.ts +28 -0
- package/dist/components/divider/Divider.stories.tsx +633 -0
- package/dist/components/divider/index.tsx +181 -0
- package/dist/components/divider/meta.ts +12 -0
- package/dist/components/dot-loader/DotLoader.stories.tsx +352 -0
- package/dist/components/dot-loader/index.tsx +78 -0
- package/dist/components/dot-loader/meta.ts +14 -0
- package/dist/components/dropdown/Dropdown.stories.tsx +1210 -0
- package/dist/components/dropdown/index.tsx +479 -0
- package/dist/components/dropdown/meta.ts +21 -0
- package/dist/components/form/Form.stories.tsx +320 -0
- package/dist/components/form/index.tsx +183 -0
- package/dist/components/form/meta.ts +11 -0
- package/dist/components/helper-text/HelperText.stories.tsx +254 -0
- package/dist/components/helper-text/index.tsx +102 -0
- package/dist/components/helper-text/meta.ts +18 -0
- package/dist/components/hover-card/HoverCard.stories.tsx +1328 -0
- package/dist/components/hover-card/index.tsx +42 -0
- package/dist/components/hover-card/meta.ts +12 -0
- package/dist/components/icon-button/IconButton.stories.tsx +252 -0
- package/dist/components/icon-button/index.tsx +130 -0
- package/dist/components/icon-button/meta.ts +20 -0
- package/dist/components/if-else/if-else.stories.tsx +100 -0
- package/dist/components/if-else/index.tsx +56 -0
- package/dist/components/if-else/meta.ts +6 -0
- package/dist/components/index.ts +70 -0
- package/dist/components/input/Input.stories.tsx +431 -0
- package/dist/components/input/index.tsx +487 -0
- package/dist/components/input/meta.ts +28 -0
- package/dist/components/label/Label.stories.tsx +200 -0
- package/dist/components/label/index.tsx +43 -0
- package/dist/components/label/meta.ts +14 -0
- package/dist/components/list/List.stories.tsx +963 -0
- package/dist/components/list/index.tsx +567 -0
- package/dist/components/list/meta.ts +24 -0
- package/dist/components/marquee/Marquee.stories.tsx +819 -0
- package/dist/components/marquee/index.tsx +107 -0
- package/dist/components/marquee/meta.ts +6 -0
- package/dist/components/overlay/Overlay.stories.tsx +954 -0
- package/dist/components/overlay/index.tsx +58 -0
- package/dist/components/overlay/meta.ts +10 -0
- package/dist/components/pagination/Pagination.stories.tsx +354 -0
- package/dist/components/pagination/index.tsx +455 -0
- package/dist/components/pagination/meta.ts +29 -0
- package/dist/components/popover/Popover.stories.tsx +1037 -0
- package/dist/components/popover/index.tsx +67 -0
- package/dist/components/popover/meta.ts +12 -0
- package/dist/components/radio/Radio.stories.tsx +146 -0
- package/dist/components/radio/index.tsx +41 -0
- package/dist/components/radio/meta.ts +19 -0
- package/dist/components/resizable/Resizable.stories.tsx +866 -0
- package/dist/components/resizable/index.tsx +55 -0
- package/dist/components/resizable/meta.ts +12 -0
- package/dist/components/scroll-area/ScrollArea.stories.tsx +1104 -0
- package/dist/components/scroll-area/index.tsx +55 -0
- package/dist/components/scroll-area/meta.ts +8 -0
- package/dist/components/search/Search.stories.tsx +678 -0
- package/dist/components/search/index.tsx +141 -0
- package/dist/components/search/meta.ts +6 -0
- package/dist/components/select/Select.stories.tsx +962 -0
- package/dist/components/select/index.tsx +512 -0
- package/dist/components/select/meta.ts +40 -0
- package/dist/components/sheet/Sheet.stories.tsx +1060 -0
- package/dist/components/sheet/index.tsx +440 -0
- package/dist/components/sheet/meta.ts +38 -0
- package/dist/components/skelton/Skelton.stories.tsx +859 -0
- package/dist/components/skelton/index.tsx +17 -0
- package/dist/components/skelton/meta.ts +6 -0
- package/dist/components/slider/Slider.stories.tsx +876 -0
- package/dist/components/slider/index.tsx +156 -0
- package/dist/components/slider/meta.ts +29 -0
- package/dist/components/stepper/Stepper.stories.tsx +639 -0
- package/dist/components/stepper/index.tsx +650 -0
- package/dist/components/stepper/meta.ts +19 -0
- package/dist/components/switch/Switch.stories.tsx +85 -0
- package/dist/components/switch/index.tsx +37 -0
- package/dist/components/switch/meta.ts +24 -0
- package/dist/components/switch-case/SwitchCase.stories.tsx +209 -0
- package/dist/components/switch-case/index.tsx +89 -0
- package/dist/components/switch-case/meta.ts +6 -0
- package/dist/components/table/Table.stories.tsx +1095 -0
- package/dist/components/table/index.tsx +113 -0
- package/dist/components/table/meta.ts +20 -0
- package/dist/components/tabs/Tabs.stories.tsx +1379 -0
- package/dist/components/tabs/index.tsx +186 -0
- package/dist/components/tabs/meta.ts +25 -0
- package/dist/components/tag/Tag.stories.tsx +625 -0
- package/dist/components/tag/index.tsx +320 -0
- package/dist/components/tag/meta.ts +52 -0
- package/dist/components/textarea/TextArea.stories.tsx +723 -0
- package/dist/components/textarea/index.tsx +480 -0
- package/dist/components/textarea/meta.ts +23 -0
- package/dist/components/toast/Toast.stories.tsx +1427 -0
- package/dist/components/toast/index.tsx +26 -0
- package/dist/components/toast/meta.ts +19 -0
- package/dist/components/toggle/Toggle.stories.tsx +1093 -0
- package/dist/components/toggle/index.tsx +44 -0
- package/dist/components/toggle/meta.ts +19 -0
- package/dist/components/tooltip/Tooltip.stories.tsx +1548 -0
- package/dist/components/tooltip/index.tsx +304 -0
- package/dist/components/tooltip/meta.ts +21 -0
- package/dist/components/typography/Typography.stories.tsx +197 -0
- package/dist/components/typography/index.tsx +184 -0
- package/dist/components/typography/meta.ts +38 -0
- package/dist/fonts/LabGrotesque-Regular.ttf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Bold.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Light.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Medium.otf +0 -0
- package/dist/fonts/LabGrotesqueTRIAL-Regular.otf +0 -0
- package/dist/fonts/PPSupplySans-Regular (1).otf +0 -0
- package/dist/fonts/PPSupplySans-Regular.otf +0 -0
- package/dist/fonts/PPSupplySans-Ultralight.otf +0 -0
- package/dist/hooks/index.ts +3 -0
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +997 -0
- package/dist/hooks/use-previous/index.ts +15 -0
- package/dist/hooks/use-previous/meta.ts +6 -0
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +983 -0
- package/dist/hooks/use-standalone-pagination/index.ts +146 -0
- package/dist/hooks/use-standalone-pagination/meta.ts +6 -0
- package/dist/icons/Icons.stories.tsx +29 -0
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +991 -0
- package/dist/icons/alert-icon/index.tsx +48 -0
- package/dist/icons/alert-icon/meta.ts +8 -0
- package/dist/icons/all-icons.tsx +738 -0
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +1031 -0
- package/dist/icons/angle-down-icon/index.tsx +25 -0
- package/dist/icons/angle-down-icon/meta.ts +8 -0
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +1080 -0
- package/dist/icons/arrow-box-left-icon/index.tsx +24 -0
- package/dist/icons/arrow-box-left-icon/meta.ts +8 -0
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +1151 -0
- package/dist/icons/arrow-right-icon/index.tsx +26 -0
- package/dist/icons/arrow-right-icon/meta.ts +8 -0
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +1273 -0
- package/dist/icons/arrow-right-up-icon/index.tsx +24 -0
- package/dist/icons/arrow-right-up-icon/meta.ts +8 -0
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +670 -0
- package/dist/icons/art-board-icon/index.tsx +24 -0
- package/dist/icons/art-board-icon/meta.ts +7 -0
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +1244 -0
- package/dist/icons/audio-bar-icon/index.tsx +19 -0
- package/dist/icons/audio-bar-icon/meta.ts +8 -0
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +1239 -0
- package/dist/icons/bubble-check-icon/index.tsx +24 -0
- package/dist/icons/bubble-check-icon/meta.ts +8 -0
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +1228 -0
- package/dist/icons/bubble-crossed-icon/index.tsx +24 -0
- package/dist/icons/bubble-crossed-icon/meta.ts +8 -0
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +912 -0
- package/dist/icons/bubble-sparkle-icon/index.tsx +26 -0
- package/dist/icons/bubble-sparkle-icon/meta.ts +8 -0
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-double-left-icon/index.tsx +34 -0
- package/dist/icons/chevron-double-left-icon/meta.ts +8 -0
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-double-right-icon/index.tsx +34 -0
- package/dist/icons/chevron-double-right-icon/meta.ts +8 -0
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +1001 -0
- package/dist/icons/chevron-down-icon/index.tsx +27 -0
- package/dist/icons/chevron-down-icon/meta.ts +8 -0
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +1029 -0
- package/dist/icons/chevron-left-icon/index.tsx +27 -0
- package/dist/icons/chevron-left-icon/meta.ts +8 -0
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +1021 -0
- package/dist/icons/chevron-right-icon/index.tsx +27 -0
- package/dist/icons/chevron-right-icon/meta.ts +8 -0
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +1036 -0
- package/dist/icons/chevron-up-icon/index.tsx +27 -0
- package/dist/icons/chevron-up-icon/meta.ts +8 -0
- package/dist/icons/command-icon/CommandIcon.stories.tsx +1098 -0
- package/dist/icons/command-icon/index.tsx +24 -0
- package/dist/icons/command-icon/meta.ts +8 -0
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +1061 -0
- package/dist/icons/cross-circle-icon/index.tsx +23 -0
- package/dist/icons/cross-circle-icon/meta.ts +8 -0
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +1027 -0
- package/dist/icons/cross-icon/index.tsx +24 -0
- package/dist/icons/cross-icon/meta.ts +8 -0
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +1092 -0
- package/dist/icons/edit-big-icon/index.tsx +22 -0
- package/dist/icons/edit-big-icon/meta.ts +8 -0
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +1090 -0
- package/dist/icons/eye-close-icon/index.tsx +26 -0
- package/dist/icons/eye-close-icon/meta.ts +8 -0
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +1098 -0
- package/dist/icons/eye-open-icon/index.tsx +24 -0
- package/dist/icons/eye-open-icon/meta.ts +8 -0
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +1071 -0
- package/dist/icons/feature-shine-icon/index.tsx +29 -0
- package/dist/icons/feature-shine-icon/meta.ts +8 -0
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +1115 -0
- package/dist/icons/file-chart-icon/index.tsx +24 -0
- package/dist/icons/file-chart-icon/meta.ts +8 -0
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +668 -0
- package/dist/icons/file-text-icon/index.tsx +24 -0
- package/dist/icons/file-text-icon/meta.ts +8 -0
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +1239 -0
- package/dist/icons/grip-vertical-icon/index.tsx +28 -0
- package/dist/icons/grip-vertical-icon/meta.ts +8 -0
- package/dist/icons/image-icon/ImageIcon.stories.tsx +1181 -0
- package/dist/icons/image-icon/index.tsx +24 -0
- package/dist/icons/image-icon/meta.ts +8 -0
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +1248 -0
- package/dist/icons/import-folder-icon/index.tsx +22 -0
- package/dist/icons/import-folder-icon/meta.ts +8 -0
- package/dist/icons/index.ts +46 -0
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +1272 -0
- package/dist/icons/light-bulb-simple-icon/index.tsx +24 -0
- package/dist/icons/light-bulb-simple-icon/meta.ts +8 -0
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +1245 -0
- package/dist/icons/magic-book-icon/index.tsx +32 -0
- package/dist/icons/magic-book-icon/meta.ts +8 -0
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +1251 -0
- package/dist/icons/maintenance-icon/index.tsx +23 -0
- package/dist/icons/maintenance-icon/meta.ts +8 -0
- package/dist/icons/message-icon/MessageIcon.stories.tsx +595 -0
- package/dist/icons/message-icon/index.tsx +30 -0
- package/dist/icons/message-icon/meta.ts +8 -0
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +1245 -0
- package/dist/icons/move-horizontal-icon/index.tsx +23 -0
- package/dist/icons/move-horizontal-icon/meta.ts +8 -0
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +1196 -0
- package/dist/icons/move-vertical-icon/index.tsx +23 -0
- package/dist/icons/move-vertical-icon/meta.ts +8 -0
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +1167 -0
- package/dist/icons/page-search-icon/index.tsx +21 -0
- package/dist/icons/page-search-icon/meta.ts +8 -0
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +1131 -0
- package/dist/icons/pencil-icon/index.tsx +21 -0
- package/dist/icons/pencil-icon/meta.ts +8 -0
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +1151 -0
- package/dist/icons/plus-icon/index.tsx +24 -0
- package/dist/icons/plus-icon/meta.ts +8 -0
- package/dist/icons/search-icon/SearchIcon.stories.tsx +1181 -0
- package/dist/icons/search-icon/index.tsx +24 -0
- package/dist/icons/search-icon/meta.ts +8 -0
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +1167 -0
- package/dist/icons/site-logo-icon/index.tsx +79 -0
- package/dist/icons/site-logo-icon/meta.ts +8 -0
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +637 -0
- package/dist/icons/spinner-gradient-icon/index.tsx +53 -0
- package/dist/icons/spinner-gradient-icon/meta.ts +8 -0
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +644 -0
- package/dist/icons/spinner-solid-icon/index.tsx +59 -0
- package/dist/icons/spinner-solid-icon/meta.ts +8 -0
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +736 -0
- package/dist/icons/spinner-solid-neutral-icon/index.tsx +53 -0
- package/dist/icons/spinner-solid-neutral-icon/meta.ts +8 -0
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +1204 -0
- package/dist/icons/tick-circle-icon/index.tsx +23 -0
- package/dist/icons/tick-circle-icon/meta.ts +8 -0
- package/dist/icons/tick-icon/TickIcon.stories.tsx +1340 -0
- package/dist/icons/tick-icon/index.tsx +24 -0
- package/dist/icons/tick-icon/meta.ts +8 -0
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +996 -0
- package/dist/icons/trash-icon/index.tsx +24 -0
- package/dist/icons/trash-icon/meta.ts +8 -0
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +947 -0
- package/dist/icons/upload-icon/index.tsx +24 -0
- package/dist/icons/upload-icon/meta.ts +8 -0
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +1045 -0
- package/dist/icons/vertical-menu-icon/index.tsx +27 -0
- package/dist/icons/vertical-menu-icon/meta.ts +8 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +206 -0
- package/dist/lib/utils.ts +6 -0
- package/dist/styles/aural-theme.css +1008 -0
- package/package.json +142 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
import React, { useState } from "react"
|
|
2
|
+
import { Button } from "@components/button"
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
4
|
+
|
|
5
|
+
import Search, { SearchResult } from "."
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Search> = {
|
|
8
|
+
title: "Components/UI/Search",
|
|
9
|
+
component: Search,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "centered",
|
|
12
|
+
backgrounds: {
|
|
13
|
+
default: "dark",
|
|
14
|
+
values: [
|
|
15
|
+
{ name: "dark", value: "#0a0a0a" },
|
|
16
|
+
{ name: "light", value: "#ffffff" },
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
docs: {
|
|
20
|
+
description: {
|
|
21
|
+
component: `
|
|
22
|
+
# Search Component
|
|
23
|
+
|
|
24
|
+
A comprehensive search input component with both controlled and uncontrolled modes, built with dark theme optimization and flexible content rendering.
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
- **Dual Mode Support**: Works as both controlled and uncontrolled component
|
|
29
|
+
- **Search Icon**: Built-in search icon with proper theming
|
|
30
|
+
- **Clear Functionality**: X button to clear search input
|
|
31
|
+
- **Flexible Results**: Custom children rendering for search results
|
|
32
|
+
- **Dark Theme Optimized**: Default styling for dark interfaces
|
|
33
|
+
- **Accessibility**: Full keyboard navigation and screen reader support
|
|
34
|
+
- **Event Handling**: Separate onChange and onSearch callbacks
|
|
35
|
+
|
|
36
|
+
## Component Modes
|
|
37
|
+
|
|
38
|
+
### Controlled Component
|
|
39
|
+
Use \`value\`, \`onChange\`, and \`onSearch\` for external state management:
|
|
40
|
+
|
|
41
|
+
\`\`\`tsx
|
|
42
|
+
const [searchValue, setSearchValue] = useState("")
|
|
43
|
+
|
|
44
|
+
<Search
|
|
45
|
+
value={searchValue}
|
|
46
|
+
onChange={setSearchValue}
|
|
47
|
+
onSearch={(query) => handleSearch(query)}
|
|
48
|
+
/>
|
|
49
|
+
\`\`\`
|
|
50
|
+
|
|
51
|
+
### Uncontrolled Component
|
|
52
|
+
Use \`initialValue\` and \`onSearch\` for internal state management:
|
|
53
|
+
|
|
54
|
+
\`\`\`tsx
|
|
55
|
+
<Search
|
|
56
|
+
initialValue="initial search"
|
|
57
|
+
onSearch={(query) => handleSearch(query)}
|
|
58
|
+
/>
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
## Props Overview
|
|
62
|
+
|
|
63
|
+
- **value**: Current value (controlled mode)
|
|
64
|
+
- **onChange**: Value change handler (controlled mode)
|
|
65
|
+
- **initialValue**: Initial value (uncontrolled mode)
|
|
66
|
+
- **onSearch**: Search handler (both modes)
|
|
67
|
+
- **results**: Array of search results
|
|
68
|
+
- **children**: Custom content for rendering results
|
|
69
|
+
- **placeholder**: Input placeholder text
|
|
70
|
+
- **className**: Additional CSS classes
|
|
71
|
+
`,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
tags: ["autodocs"],
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default meta
|
|
79
|
+
type Story = StoryObj<typeof Search>
|
|
80
|
+
|
|
81
|
+
// 1. Basic Search Component Examples
|
|
82
|
+
export const BasicSearch: Story = {
|
|
83
|
+
render: () => (
|
|
84
|
+
<div className="space-y-6">
|
|
85
|
+
<div className="text-center">
|
|
86
|
+
<h3 className="mb-2 font-medium text-white">Basic Search Component</h3>
|
|
87
|
+
<p className="text-sm text-white/60">
|
|
88
|
+
Simple search input with different placeholder examples
|
|
89
|
+
</p>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div className="space-y-4">
|
|
93
|
+
{/* Default Placeholder */}
|
|
94
|
+
<div className="space-y-2">
|
|
95
|
+
<label className="text-sm font-medium text-white/80">Default</label>
|
|
96
|
+
<Search placeholder="Search episodes" />
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
{/* Custom Placeholders */}
|
|
100
|
+
<div className="space-y-2">
|
|
101
|
+
<label className="text-sm font-medium text-white/80">
|
|
102
|
+
Custom Placeholders
|
|
103
|
+
</label>
|
|
104
|
+
<div className="space-y-3">
|
|
105
|
+
<Search placeholder="Search podcasts..." />
|
|
106
|
+
<Search placeholder="Find your favorite shows" />
|
|
107
|
+
<Search placeholder="Type to search music" />
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
{/* With Initial Value */}
|
|
112
|
+
<div className="space-y-2">
|
|
113
|
+
<label className="text-sm font-medium text-white/80">
|
|
114
|
+
With Initial Value
|
|
115
|
+
</label>
|
|
116
|
+
<Search placeholder="Search episodes" initialValue="The Daily" />
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
),
|
|
121
|
+
parameters: {
|
|
122
|
+
docs: {
|
|
123
|
+
description: {
|
|
124
|
+
story:
|
|
125
|
+
"Basic search component examples with different placeholder text and initial values.",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 2. Controlled Component Examples
|
|
132
|
+
export const ControlledSearch: Story = {
|
|
133
|
+
render: () => {
|
|
134
|
+
const [searchValue1, setSearchValue1] = useState("")
|
|
135
|
+
const [searchValue2, setSearchValue2] = useState("Controlled")
|
|
136
|
+
const [searchValue3, setSearchValue3] = useState("")
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div className="space-y-6">
|
|
140
|
+
<div className="text-center">
|
|
141
|
+
<h3 className="mb-2 font-medium text-white">Controlled Search</h3>
|
|
142
|
+
<p className="text-sm text-white/60">
|
|
143
|
+
Search components with external state control
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div className="space-y-6">
|
|
148
|
+
{/* Basic Controlled */}
|
|
149
|
+
<div className="space-y-3">
|
|
150
|
+
<div className="flex items-center justify-between">
|
|
151
|
+
<label className="text-sm font-medium text-white/80">
|
|
152
|
+
Basic Controlled
|
|
153
|
+
</label>
|
|
154
|
+
<div className="text-xs text-white/60">
|
|
155
|
+
Value: "{searchValue1}"
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
<Search
|
|
159
|
+
placeholder="Type something..."
|
|
160
|
+
value={searchValue1}
|
|
161
|
+
onChange={setSearchValue1}
|
|
162
|
+
/>
|
|
163
|
+
<div className="flex gap-2">
|
|
164
|
+
<Button
|
|
165
|
+
size="sm"
|
|
166
|
+
variant="outline"
|
|
167
|
+
onClick={() => setSearchValue1("Preset Value")}
|
|
168
|
+
>
|
|
169
|
+
Set Value
|
|
170
|
+
</Button>
|
|
171
|
+
<Button
|
|
172
|
+
size="sm"
|
|
173
|
+
variant="outline"
|
|
174
|
+
onClick={() => setSearchValue1("")}
|
|
175
|
+
>
|
|
176
|
+
Clear
|
|
177
|
+
</Button>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
{/* Pre-filled Controlled */}
|
|
182
|
+
<div className="space-y-3">
|
|
183
|
+
<div className="flex items-center justify-between">
|
|
184
|
+
<label className="text-sm font-medium text-white/80">
|
|
185
|
+
Pre-filled Controlled
|
|
186
|
+
</label>
|
|
187
|
+
<div className="text-xs text-white/60">
|
|
188
|
+
Value: "{searchValue2}"
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
<Search
|
|
192
|
+
placeholder="Search with preset value"
|
|
193
|
+
value={searchValue2}
|
|
194
|
+
onChange={setSearchValue2}
|
|
195
|
+
/>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
{/* Controlled with Validation */}
|
|
199
|
+
<div className="space-y-3">
|
|
200
|
+
<div className="flex items-center justify-between">
|
|
201
|
+
<label className="text-sm font-medium text-white/80">
|
|
202
|
+
With Validation
|
|
203
|
+
</label>
|
|
204
|
+
<div className="text-xs text-white/60">
|
|
205
|
+
Length: {searchValue3.length}/20
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
<Search
|
|
209
|
+
placeholder="Max 20 characters"
|
|
210
|
+
value={searchValue3}
|
|
211
|
+
onChange={(value) => {
|
|
212
|
+
if (value.length <= 20) {
|
|
213
|
+
setSearchValue3(value)
|
|
214
|
+
}
|
|
215
|
+
}}
|
|
216
|
+
/>
|
|
217
|
+
{searchValue3.length >= 20 && (
|
|
218
|
+
<p className="text-xs text-red-400">Maximum length reached</p>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
)
|
|
224
|
+
},
|
|
225
|
+
parameters: {
|
|
226
|
+
docs: {
|
|
227
|
+
description: {
|
|
228
|
+
story:
|
|
229
|
+
"Controlled search component examples showing external state management, pre-filled values, and validation.",
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 3. Uncontrolled Component Examples
|
|
236
|
+
export const UncontrolledSearch: Story = {
|
|
237
|
+
render: () => {
|
|
238
|
+
const [lastSearch1, setLastSearch1] = useState("")
|
|
239
|
+
const [lastSearch2, setLastSearch2] = useState("")
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<div className="space-y-6">
|
|
243
|
+
<div className="text-center">
|
|
244
|
+
<h3 className="mb-2 font-medium text-white">Uncontrolled Search</h3>
|
|
245
|
+
<p className="text-sm text-white/60">
|
|
246
|
+
Search components with internal state management
|
|
247
|
+
</p>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
<div className="space-y-6">
|
|
251
|
+
{/* Basic Uncontrolled */}
|
|
252
|
+
<div className="space-y-3">
|
|
253
|
+
<div className="flex items-center justify-between">
|
|
254
|
+
<label className="text-sm font-medium text-white/80">
|
|
255
|
+
Basic Uncontrolled
|
|
256
|
+
</label>
|
|
257
|
+
<div className="text-xs text-white/60">
|
|
258
|
+
Last search: "{lastSearch1}"
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
<Search
|
|
262
|
+
placeholder="Search internally managed"
|
|
263
|
+
onSearch={setLastSearch1}
|
|
264
|
+
/>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
{/* With Initial Value */}
|
|
268
|
+
<div className="space-y-3">
|
|
269
|
+
<div className="flex items-center justify-between">
|
|
270
|
+
<label className="text-sm font-medium text-white/80">
|
|
271
|
+
With Initial Value
|
|
272
|
+
</label>
|
|
273
|
+
<div className="text-xs text-white/60">
|
|
274
|
+
Last search: "{lastSearch2}"
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
<Search
|
|
278
|
+
placeholder="Search with initial value"
|
|
279
|
+
initialValue="Initial Search"
|
|
280
|
+
onSearch={setLastSearch2}
|
|
281
|
+
/>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
{/* Multiple Independent */}
|
|
285
|
+
<div className="space-y-3">
|
|
286
|
+
<label className="text-sm font-medium text-white/80">
|
|
287
|
+
Multiple Independent
|
|
288
|
+
</label>
|
|
289
|
+
<div className="grid grid-cols-2 gap-3">
|
|
290
|
+
<Search placeholder="Search A" />
|
|
291
|
+
<Search placeholder="Search B" />
|
|
292
|
+
</div>
|
|
293
|
+
<p className="text-xs text-white/60">
|
|
294
|
+
Each search maintains its own independent state
|
|
295
|
+
</p>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
)
|
|
300
|
+
},
|
|
301
|
+
parameters: {
|
|
302
|
+
docs: {
|
|
303
|
+
description: {
|
|
304
|
+
story:
|
|
305
|
+
"Uncontrolled search component examples with internal state management and initial values.",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 4. Interactive Search with Results
|
|
312
|
+
export const InteractiveSearch: Story = {
|
|
313
|
+
render: () => {
|
|
314
|
+
const [query, setQuery] = useState("")
|
|
315
|
+
const [results, setResults] = useState<SearchResult[]>([])
|
|
316
|
+
const [selectedResult, setSelectedResult] = useState<string | null>(null)
|
|
317
|
+
|
|
318
|
+
// Mock search data
|
|
319
|
+
const allPodcasts = [
|
|
320
|
+
{ id: "1", text: "The Joe Rogan Experience" },
|
|
321
|
+
{ id: "2", text: "Serial" },
|
|
322
|
+
{ id: "3", text: "This American Life" },
|
|
323
|
+
{ id: "4", text: "Stuff You Should Know" },
|
|
324
|
+
{ id: "5", text: "The Daily" },
|
|
325
|
+
{ id: "6", text: "Crime Junkie" },
|
|
326
|
+
{ id: "7", text: "The Michelle Obama Podcast" },
|
|
327
|
+
{ id: "8", text: "Call Her Daddy" },
|
|
328
|
+
{ id: "9", text: "My Favorite Murder" },
|
|
329
|
+
{ id: "10", text: "The Tim Ferriss Show" },
|
|
330
|
+
{ id: "11", text: "Conan O'Brien Needs a Friend" },
|
|
331
|
+
{ id: "12", text: "The Ben Shapiro Show" },
|
|
332
|
+
]
|
|
333
|
+
|
|
334
|
+
const handleSearch = (searchQuery: string) => {
|
|
335
|
+
setQuery(searchQuery)
|
|
336
|
+
|
|
337
|
+
if (!searchQuery.trim()) {
|
|
338
|
+
setResults([])
|
|
339
|
+
return
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Filter podcasts based on query
|
|
343
|
+
const filteredResults = allPodcasts.filter((podcast) =>
|
|
344
|
+
podcast.text.toLowerCase().includes(searchQuery.toLowerCase())
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
setResults(filteredResults)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<div className="w-96 space-y-4">
|
|
352
|
+
<div className="text-center">
|
|
353
|
+
<h3 className="mb-2 font-medium text-white">Interactive Search</h3>
|
|
354
|
+
<p className="text-sm text-white/60">
|
|
355
|
+
Real-time search with custom results rendering
|
|
356
|
+
</p>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
<Search
|
|
360
|
+
placeholder="Search podcasts..."
|
|
361
|
+
value={query}
|
|
362
|
+
onChange={setQuery}
|
|
363
|
+
onSearch={handleSearch}
|
|
364
|
+
results={results}
|
|
365
|
+
>
|
|
366
|
+
{/* Custom Results Rendering */}
|
|
367
|
+
{results.length > 0 && (
|
|
368
|
+
<div className="mt-2 rounded-lg border border-white/10 bg-gray-800/90 shadow-xl">
|
|
369
|
+
<div className="p-3">
|
|
370
|
+
<div className="mb-2 flex items-center justify-between">
|
|
371
|
+
<span className="text-xs font-medium text-white/80">
|
|
372
|
+
Search Results
|
|
373
|
+
</span>
|
|
374
|
+
<span className="text-xs text-white/60">
|
|
375
|
+
{results.length} found
|
|
376
|
+
</span>
|
|
377
|
+
</div>
|
|
378
|
+
<div className="max-h-64 space-y-1 overflow-y-auto">
|
|
379
|
+
{results.map((result) => (
|
|
380
|
+
<button
|
|
381
|
+
key={result.id}
|
|
382
|
+
onClick={() => {
|
|
383
|
+
setSelectedResult(result.text)
|
|
384
|
+
setQuery(result.text)
|
|
385
|
+
setResults([])
|
|
386
|
+
}}
|
|
387
|
+
className="w-full rounded px-3 py-2 text-left text-sm text-white hover:bg-white/10"
|
|
388
|
+
>
|
|
389
|
+
{result.text}
|
|
390
|
+
</button>
|
|
391
|
+
))}
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
)}
|
|
396
|
+
</Search>
|
|
397
|
+
|
|
398
|
+
{/* Search Info */}
|
|
399
|
+
<div className="rounded-lg border border-white/10 bg-white/5 p-4">
|
|
400
|
+
<h4 className="mb-2 text-sm font-medium text-white">Search Info</h4>
|
|
401
|
+
<div className="space-y-1 text-xs text-white/60">
|
|
402
|
+
<div>Query: "{query || "(empty)"}"</div>
|
|
403
|
+
<div>Results: {results.length}</div>
|
|
404
|
+
<div>Selected: {selectedResult || "(none)"}</div>
|
|
405
|
+
</div>
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
)
|
|
409
|
+
},
|
|
410
|
+
parameters: {
|
|
411
|
+
docs: {
|
|
412
|
+
description: {
|
|
413
|
+
story:
|
|
414
|
+
"Interactive search example with real-time filtering, custom results rendering, and selection handling.",
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 5. Search with Different States
|
|
421
|
+
export const SearchStates: Story = {
|
|
422
|
+
render: () => {
|
|
423
|
+
const [loadingQuery, setLoadingQuery] = useState("")
|
|
424
|
+
const [errorQuery, setErrorQuery] = useState("")
|
|
425
|
+
const [emptyQuery, setEmptyQuery] = useState("nonexistent")
|
|
426
|
+
|
|
427
|
+
return (
|
|
428
|
+
<div className="space-y-6">
|
|
429
|
+
<div className="text-center">
|
|
430
|
+
<h3 className="mb-2 font-medium text-white">Search States</h3>
|
|
431
|
+
<p className="text-sm text-white/60">
|
|
432
|
+
Different search states and feedback
|
|
433
|
+
</p>
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<div className="grid gap-6">
|
|
437
|
+
{/* Loading State */}
|
|
438
|
+
<div className="space-y-3">
|
|
439
|
+
<label className="text-sm font-medium text-white/80">
|
|
440
|
+
Loading State
|
|
441
|
+
</label>
|
|
442
|
+
<Search
|
|
443
|
+
placeholder="Search with loading..."
|
|
444
|
+
value={loadingQuery}
|
|
445
|
+
onChange={setLoadingQuery}
|
|
446
|
+
onSearch={setLoadingQuery}
|
|
447
|
+
>
|
|
448
|
+
{loadingQuery && (
|
|
449
|
+
<div className="mt-2 rounded-lg border border-white/10 bg-gray-800/90 p-4 text-center">
|
|
450
|
+
<div className="flex items-center justify-center gap-2">
|
|
451
|
+
<div className="h-4 w-4 animate-spin rounded-full border-2 border-white/20 border-t-white"></div>
|
|
452
|
+
<span className="text-sm text-white/80">Searching...</span>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
)}
|
|
456
|
+
</Search>
|
|
457
|
+
</div>
|
|
458
|
+
|
|
459
|
+
{/* Error State */}
|
|
460
|
+
<div className="space-y-3">
|
|
461
|
+
<label className="text-sm font-medium text-white/80">
|
|
462
|
+
Error State
|
|
463
|
+
</label>
|
|
464
|
+
<Search
|
|
465
|
+
placeholder="Search with error..."
|
|
466
|
+
value={errorQuery}
|
|
467
|
+
onChange={setErrorQuery}
|
|
468
|
+
onSearch={setErrorQuery}
|
|
469
|
+
>
|
|
470
|
+
{errorQuery && (
|
|
471
|
+
<div className="mt-2 rounded-lg border border-red-500/30 bg-red-900/30 p-4">
|
|
472
|
+
<div className="flex items-center gap-2">
|
|
473
|
+
<svg
|
|
474
|
+
className="h-4 w-4 text-red-400"
|
|
475
|
+
fill="none"
|
|
476
|
+
stroke="currentColor"
|
|
477
|
+
viewBox="0 0 24 24"
|
|
478
|
+
>
|
|
479
|
+
<path
|
|
480
|
+
strokeLinecap="round"
|
|
481
|
+
strokeLinejoin="round"
|
|
482
|
+
strokeWidth={2}
|
|
483
|
+
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
484
|
+
/>
|
|
485
|
+
</svg>
|
|
486
|
+
<span className="text-sm text-red-400">
|
|
487
|
+
Search failed. Please try again.
|
|
488
|
+
</span>
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
)}
|
|
492
|
+
</Search>
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
{/* Empty State */}
|
|
496
|
+
<div className="space-y-3">
|
|
497
|
+
<label className="text-sm font-medium text-white/80">
|
|
498
|
+
Empty Results
|
|
499
|
+
</label>
|
|
500
|
+
<Search
|
|
501
|
+
placeholder="Search with no results..."
|
|
502
|
+
value={emptyQuery}
|
|
503
|
+
onChange={setEmptyQuery}
|
|
504
|
+
onSearch={setEmptyQuery}
|
|
505
|
+
>
|
|
506
|
+
{emptyQuery && (
|
|
507
|
+
<div className="mt-2 rounded-lg border border-white/10 bg-gray-800/90 p-4 text-center">
|
|
508
|
+
<div className="space-y-2">
|
|
509
|
+
<svg
|
|
510
|
+
className="mx-auto h-8 w-8 text-white/40"
|
|
511
|
+
fill="none"
|
|
512
|
+
stroke="currentColor"
|
|
513
|
+
viewBox="0 0 24 24"
|
|
514
|
+
>
|
|
515
|
+
<path
|
|
516
|
+
strokeLinecap="round"
|
|
517
|
+
strokeLinejoin="round"
|
|
518
|
+
strokeWidth={2}
|
|
519
|
+
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
520
|
+
/>
|
|
521
|
+
</svg>
|
|
522
|
+
<div>
|
|
523
|
+
<p className="text-sm font-medium text-white">
|
|
524
|
+
No results found
|
|
525
|
+
</p>
|
|
526
|
+
<p className="text-xs text-white/60">
|
|
527
|
+
Try different keywords or check your spelling
|
|
528
|
+
</p>
|
|
529
|
+
</div>
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
)}
|
|
533
|
+
</Search>
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
)
|
|
538
|
+
},
|
|
539
|
+
parameters: {
|
|
540
|
+
docs: {
|
|
541
|
+
description: {
|
|
542
|
+
story:
|
|
543
|
+
"Search component examples showing different states: loading, error, and empty results with appropriate feedback.",
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// 6. Advanced Search Features
|
|
550
|
+
export const AdvancedFeatures: Story = {
|
|
551
|
+
render: () => {
|
|
552
|
+
const [searchHistory, setSearchHistory] = useState<string[]>([
|
|
553
|
+
"The Daily",
|
|
554
|
+
"Serial",
|
|
555
|
+
"This American Life",
|
|
556
|
+
])
|
|
557
|
+
const [currentSearch, setCurrentSearch] = useState("")
|
|
558
|
+
const [showHistory, setShowHistory] = useState(false)
|
|
559
|
+
|
|
560
|
+
const addToHistory = (query: string) => {
|
|
561
|
+
if (query.trim() && !searchHistory.includes(query)) {
|
|
562
|
+
setSearchHistory((prev) => [query, ...prev.slice(0, 4)])
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return (
|
|
567
|
+
<div className="w-96 space-y-6">
|
|
568
|
+
<div className="text-center">
|
|
569
|
+
<h3 className="mb-2 font-medium text-white">Advanced Features</h3>
|
|
570
|
+
<p className="text-sm text-white/60">
|
|
571
|
+
Search with history, suggestions, and shortcuts
|
|
572
|
+
</p>
|
|
573
|
+
</div>
|
|
574
|
+
|
|
575
|
+
<div className="space-y-6">
|
|
576
|
+
{/* Search with History */}
|
|
577
|
+
<div className="space-y-3">
|
|
578
|
+
<label className="text-sm font-medium text-white/80">
|
|
579
|
+
Search with History
|
|
580
|
+
</label>
|
|
581
|
+
<Search
|
|
582
|
+
placeholder="Search with history..."
|
|
583
|
+
value={currentSearch}
|
|
584
|
+
onChange={setCurrentSearch}
|
|
585
|
+
onSearch={(query) => {
|
|
586
|
+
addToHistory(query)
|
|
587
|
+
setShowHistory(false)
|
|
588
|
+
}}
|
|
589
|
+
>
|
|
590
|
+
{(showHistory ||
|
|
591
|
+
(!currentSearch && searchHistory.length > 0)) && (
|
|
592
|
+
<div className="mt-2 rounded-lg border border-white/10 bg-gray-800/90 shadow-xl">
|
|
593
|
+
<div className="p-3">
|
|
594
|
+
<div className="mb-2 text-xs font-medium text-white/80">
|
|
595
|
+
Recent Searches
|
|
596
|
+
</div>
|
|
597
|
+
<div className="space-y-1">
|
|
598
|
+
{searchHistory.map((item, index) => (
|
|
599
|
+
<button
|
|
600
|
+
key={index}
|
|
601
|
+
onClick={() => {
|
|
602
|
+
setCurrentSearch(item)
|
|
603
|
+
setShowHistory(false)
|
|
604
|
+
}}
|
|
605
|
+
className="flex w-full items-center gap-2 rounded px-3 py-2 text-left text-sm text-white hover:bg-white/10"
|
|
606
|
+
>
|
|
607
|
+
<svg
|
|
608
|
+
className="h-3 w-3 text-white/40"
|
|
609
|
+
fill="none"
|
|
610
|
+
stroke="currentColor"
|
|
611
|
+
viewBox="0 0 24 24"
|
|
612
|
+
>
|
|
613
|
+
<path
|
|
614
|
+
strokeLinecap="round"
|
|
615
|
+
strokeLinejoin="round"
|
|
616
|
+
strokeWidth={2}
|
|
617
|
+
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
618
|
+
/>
|
|
619
|
+
</svg>
|
|
620
|
+
{item}
|
|
621
|
+
</button>
|
|
622
|
+
))}
|
|
623
|
+
</div>
|
|
624
|
+
</div>
|
|
625
|
+
</div>
|
|
626
|
+
)}
|
|
627
|
+
</Search>
|
|
628
|
+
<div className="flex gap-2">
|
|
629
|
+
<Button
|
|
630
|
+
size="sm"
|
|
631
|
+
variant="outline"
|
|
632
|
+
onClick={() => setShowHistory(!showHistory)}
|
|
633
|
+
>
|
|
634
|
+
{showHistory ? "Hide" : "Show"} History
|
|
635
|
+
</Button>
|
|
636
|
+
<Button
|
|
637
|
+
size="sm"
|
|
638
|
+
variant="outline"
|
|
639
|
+
onClick={() => setSearchHistory([])}
|
|
640
|
+
>
|
|
641
|
+
Clear History
|
|
642
|
+
</Button>
|
|
643
|
+
</div>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
{/* Keyboard Shortcuts Info */}
|
|
647
|
+
<div className="rounded-lg border border-white/10 bg-white/5 p-4">
|
|
648
|
+
<h4 className="mb-2 text-sm font-medium text-white">
|
|
649
|
+
Keyboard Shortcuts
|
|
650
|
+
</h4>
|
|
651
|
+
<div className="space-y-1 text-xs text-white/60">
|
|
652
|
+
<div className="flex justify-between">
|
|
653
|
+
<span>Focus search:</span>
|
|
654
|
+
<kbd className="rounded bg-white/10 px-1 font-mono">Cmd+K</kbd>
|
|
655
|
+
</div>
|
|
656
|
+
<div className="flex justify-between">
|
|
657
|
+
<span>Clear search:</span>
|
|
658
|
+
<kbd className="rounded bg-white/10 px-1 font-mono">Esc</kbd>
|
|
659
|
+
</div>
|
|
660
|
+
<div className="flex justify-between">
|
|
661
|
+
<span>Navigate results:</span>
|
|
662
|
+
<kbd className="rounded bg-white/10 px-1 font-mono">↑↓</kbd>
|
|
663
|
+
</div>
|
|
664
|
+
</div>
|
|
665
|
+
</div>
|
|
666
|
+
</div>
|
|
667
|
+
</div>
|
|
668
|
+
)
|
|
669
|
+
},
|
|
670
|
+
parameters: {
|
|
671
|
+
docs: {
|
|
672
|
+
description: {
|
|
673
|
+
story:
|
|
674
|
+
"Advanced search features including search history, keyboard shortcuts, and enhanced user experience patterns.",
|
|
675
|
+
},
|
|
676
|
+
},
|
|
677
|
+
},
|
|
678
|
+
}
|